258 Commits
v3.2.1 ... gdb

Author SHA1 Message Date
6fee514a1b Import of gdb 7.3.1
Change-Id: I504ac949581b96a04cb1d4b7677a93ee3d0e2ec9
2013-07-19 15:46:07 +02:00
714dd83efe releasetools/arm_sdimage.sh
- adapt usr partition size
 - reformulate partition sizes for easier adaptations
 - ensure 4k-block alignement of the partitions

Change-Id: I88787614163a7be177acb5dbf454b26387376a47
2013-07-12 14:22:04 +02:00
0cdf705cc6 Enable optional GCC install and GCC improvements
-By adding MKGCC=yes and MKGCCCMDS=yes on the make commandline
   it is now possible to compile and install GCC on the system.

   Before doing this, if you are not using the build.sh script,
   you will need to call the fetch scripts in order to retrieve
   the sources of GCC and its dependencies.

 -Reduce difference with NetBSD share/mk

   Move Minix-specific parameters from bsd.gcc.mk to bsd.own.mk,
   which is anyway patched, so that bsd.gcc.mk is now aligned
   on the NetBSD version.

 -Clean libraries dependencies, compiles stdc++ only if gcc is
   also compiled (it is part of the gcc sources)

 -Correct minix.h header sequence, cleanup spec headers.

 -Fix cross-compilation from a 32bit host targeting MINIX/arm

Change-Id: I1b234af18eed4ab5675188244e931b2a2b7bd943
2013-07-12 14:22:03 +02:00
c566d4623b Allow install of binutils and import texinfo
- Enable installing binutils from the base system.

 - Import texinfo which is required for the binutils tools
   to be compiled.

 - Also adapted the fetch rules to correctly generate the
   gitignore files for gcc, and allow the case of multiple
   modules in the same directory, as found in gnu/dist.

Warning: This patch has an entry in docs/UPDATING

Change-Id: Ib781734e8fd7f9c6265fa65d62ba2cf3fccbc5ba
2013-07-12 14:18:08 +02:00
4af66e563d Upgrading to binutils-2.22
* Added --with-ld=default
 * Added --with-lto
 * Fixed ld script for ARM
 * Options are prepared for future activation of gold.

Change-Id: Id9618904055e18d1b37f5e9585f775c367ff356e
2013-07-08 18:53:55 +02:00
Xiaoguang Sun
64f10ee644 Implement getrusage
Implement getrusage.
These fields of struct rusage are not supported and always set to zero at this time
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_nvcsw;           /* voluntary context switches */
long ru_nivcsw;          /* involuntary context switches */

test75.c is the unit test for this new function

Change-Id: I3f1eb69de1fce90d087d76773b09021fc6106539
2013-07-01 23:00:47 +02:00
Thomas Cort
4241cc5d98 include: Import dev/i2c/i2c_io.h
Change-Id: Icb754891349b7f571863f3a87b0318c28c35ac79
2013-06-27 14:20:12 -04:00
Ben Gras
c4d355f7bb test42: skip single step test
Change-Id: If57fc467b0ad28e0e9db27c6dadbe49e59dbc463
2013-06-25 13:51:24 +02:00
Ben Gras
27f7fd3554 kernel: high-hz workaround for do_settime
. with hz=1000, clock_t only lasts a few years.
	  whenever we can't express the desired realtime
	  in ticks because the distance with boottime is
	  too high, simply adjust bootime like we do for
	  otherwise negative values.
	. fixes test 2 on ARM
2013-06-25 09:55:43 +00:00
Ben Gras
bb268230c4 kernel: maintain stack alignment
. 'fixes' 64-bit varargs (i.e. printf("%llu", ..)) argument
	  retrieval bug
2013-06-25 09:53:15 +00:00
Ben Gras
910825ee9b re-import makewhatis
. to benefit from the contribution found by rjkovacic@gmail.com
	  in the minix makewhatis and submitted upstream, see NetBSD
	  PR/47958

Change-Id: I147e1afe0088ab16e7b171f74330d1c6f44a13cf
2013-06-25 09:51:45 +00:00
Ben Gras
cdf2f55a90 kernel, arm ucontext: ARM DBG=-g run fixes
kernel:
	. modules can be as big as the space (8MB) between them
	  instead of 4MB; memory is slightly bigger with DBG=-g

arm ucontext:
	. r4 is clobbered by the restore function, as it's
	  used as a scratch register, causing problems for the
	  DBG=-g build
	. r1-r3 are safe for scratch registers, as they are
	  caller-save, so use r3 instead; and don't bother
	  restoring r1-r3, but preserve r4

vfs:
	. improve TLL pointer sanity check a bit

Change-Id: I0e3cfc367fdc14477e40d04b5e044f288ca4cc7d
2013-06-24 16:57:30 +02:00
Ben Gras
456359aa72 retire 64-bit conversion functions
Change-Id: Ib6b81403f877c363a286c654e0524fa1cb781b80
2013-06-24 16:50:57 +02:00
Kees Jongenburger
964e313c94 arm:use the 4 bit mmc data bus if supported by the card.
Change-Id: I55de05db23ad1766e5faec93252e8410cbf59001
2013-06-24 09:12:11 +02:00
Kees Jongenburger
b07222a5cd build:arm remove "start usb" from u-boot command line.
Removed "start usb" from u-boot command line as it is not needed and
speeds up tftp booting.

Change-Id: I416f7eb0467888d1b69ef3dad09df0639fb63f10
2013-06-24 09:12:11 +02:00
Kees Jongenburger
e399fe53ae arm:increase the mmc driver process priority.
Increase driver process priority to prevent starvation. Without
special attribute drivers will have the same priority as other
userland processes this. Posix test 1 was taking so much resources
that it triggered alarms in the MMC driver.

Change-Id: Icd3295d8f2a4a284418327a3715641fe9a3b3043
2013-06-24 09:12:10 +02:00
Kees Jongenburger
061fed753e arm:mmc driver refactor and timeout fix for BeagleBoneBlack.
When we send MMC commads that contain data the controller provides no
description of the order of events and we need to be able to send data
from and to the controller "when needed". Changed the code to react
on buffer read and buffer write ready based on interrupts.

Change-Id: I60c9140bf0e45b74be6475054564d4e1bd89f21e
2013-06-24 09:12:10 +02:00
Thomas Cort
8bac458ae9 padconf: remove duplicate code.
The same code block was repeated twice (copy & paste error).

Change-Id: I2035c9fff46b3f0a52084c2d6c871bbda6f8f07f
2013-06-21 16:10:58 +02:00
Ben Gras
8e7c0604bd arm timer fix
. set 'done' once initialized so 32-bit read frc works,
	  thanks to keesj
	. make sure the software-implemented upper 32 bit of the 64-bit
	  "tsc" value works OK by adding an assert in one of its calls

Change-Id: I5ce24fea919f4610c6a86ac7ec9f04b1815620c2
2013-06-19 13:11:32 +02:00
Kees Jongenburger
718114d9b0 arm:mmc driver refactor.
Generalize the usage of mmc_send_cmd function to allow
it to transfer data and remove direct invocations to
mmchs_send_cmd.

Change-Id: Iabb9a7d3f4ec57536407b369531ded2b8b649cce
2013-06-18 14:35:44 +02:00
Anton Kuijsten
2e3046757a LLVM bitcode for almost the whole source tree
Change-Id: Ibc6f89de112e0649c3a3bfe49c2baa2ed0746212
2013-06-18 10:49:53 +02:00
Thomas Cort
ba92d5219d clkconf: move clkconf from libgpio to it's own lib
Clock configuration will be needed by other/future subsystems such as i2c.
Extract the functionality from libgpio and put it into it's own library.

Change-Id: I6f6de0b3fb4d305ddfeac74123b78c983d1318dd
2013-06-18 09:09:23 +02:00
Ben Gras
fa86f72420 fix for tap tests
Change-Id: Ic79cfdaf420cbf15a1aba6e30c821f35b726d0da
2013-06-17 11:43:57 +00:00
Ben Gras
9fddecf31f libsys: correct cast priority
Change-Id: I223482884c0e27726e8100209b203a33ded66f59
2013-06-17 10:40:28 +02:00
Ben Gras
5bc48ef12e kernel, libsys: make it arm-target-independent
. by making the address and frequency of the
	  free running clock kinfo members, set at runtime
	  in the kernel, instead of compile time constants
	  in libsys

Change-Id: I4a8387302d4d3ffd47d2448525725683a74c9a4f
2013-06-17 09:55:36 +02:00
Ben Gras
5120b43334 make test run script produce TAP if desired
. primarily intended for jenkins
	. see http://testanything.org/ for more info

Change-Id: If0e942f75898eed640f9edd89ef8ffd0bab9726e
2013-06-16 18:57:19 +00:00
Ben Gras
d1b3ab953e a few DBG=-g build fixes, both arches
- setlogin() not available
	- softfloat needed in -lminc for arm
	- libminc: we have to set LIBCDIR for the included files,
	  so use that instead of LIBCSRCDIR

Change-Id: I7f92621ebbca9ce08dc377b3fa61dee089071757
2013-06-16 15:27:41 +02:00
Ben Gras
71ac8a3a8a some arm uart fixes
. always keep reading data from uart so the interrupt is
	  not continually asserted if data is sent but no process
	  reads it
	. increase tx & rx fifo trigger levels -> reduces the number
	  of interrupts necessary
	. bigger rx/tx buffers

Change-Id: I3cf7c73b22ae2fc091b845d516ba4aa53e892cda
2013-06-14 23:58:44 +02:00
Ben Gras
8f2749cca8 vfs: patch for unpause()/revive() race condition
. unpause() and revive() can race - revive() can run during
	  a device i/o unblock, causing two sendnb()s to occur, and the
	  2nd one to fail
	. this can easily happen when a process is blocking on tty and
	  is then killed by a signal - tty cancels the i/o and then
	  kills the process by a signal

Change-Id: Ia319acaedfa336b78c030a2c4af7246959bdcf87
2013-06-14 23:58:43 +02:00
Kees Jongenburger
a2fcba659c arm:remove pre 1:1 mapping workarounds.
Change-Id: I5a690cf5a561cdca9b9c1f031402f80fd203c92d
2013-06-12 16:42:20 +02:00
Kees Jongenburger
a5a693a046 arm:no longer rely on a 1:1 phys mapping for device memory.
Change-Id: Ie3f61069f882c37dbb81dee813fdfd883e7468cf
2013-06-12 16:42:12 +02:00
Anton Kuijsten
a74251eb16 allow ldd mmap fallback
Change-Id: Ia7b8aa88c3f063c804869065719ac0cbf049b7dd
2013-06-12 07:05:11 +00:00
Ben Gras
8d676bd0a8 is: leave newline for stacktrace for SF9 dump
. otherwise the standard console screen can't hold them

Change-Id: Iea2c047b715bc456747aace8957d8c5eeb94d0fa
2013-06-12 07:04:53 +00:00
Ben Gras
9e43052b21 inline sendnb should not call send vector
. also vfs has to reply to a vm call - so use asynsend for that

Change-Id: I30ac1e591191dea5c99e25b03151a4415d1151b0
2013-06-12 07:04:53 +00:00
Ben Gras
63306d0ad5 init: handle getty string of "" (default)
. the default entry for disabled ttys for getty
	  in /etc/ttys is "", but init crashed on handling that
	  string.

Change-Id: Ib7cd6c6869e338f47df0aa5abed36f15eda4f6ff
2013-06-12 07:04:53 +00:00
Ben Gras
93d9caa2d6 tty: i386: rs232 fix
. ignore interrupt (stop interrupt check loop) if
	  interrupt bit not set; limit loop too
	. mask off other bits when testing bits in the status register
	. this fixes rs232 output that would otherwise never get re-triggered
	  as too many bits were set in the status byte to match the
	  possibilities.

Change-Id: I311c93377fa8fb477ee9a756455fdeda780e6ba1
2013-06-12 07:04:52 +00:00
Ben Gras
9178749e13 libc syslog, syslogd, logger, uds fixes
changes necessary for libc syslog() using a unix domain socket.

	. libc syslog: don't use send() connect() for unix
	  datagram sockets, minix wants write() and ioctl()
	. syslogd: listen on _PATH_LOG unix domain socket
	. logger: warnings fixes
	. pfs: make uds dgram socket type nonblocking so
	  syslog() doesn't block
	. vfs: add sanity check for empty fd in unpause()

Change-Id: Ied136c6fe0cc288f5a53478f1eebccc1ab1f39fb
2013-06-12 07:04:52 +00:00
Anton Kuijsten
1d71e39b73 Gold linker support for entire source tree 2013-06-11 22:51:02 +02:00
Thomas Cort
3d257f8073 Importing usr.bin/shuffle 2013-06-10 10:51:49 +02:00
Kees Jongenburger
b1e0ada171 arm:tty enable FIFO
Change-Id: Iaaa7c0bcb40c2cce2423c1defc14809ed6c70e9c
2013-06-05 19:19:38 +02:00
d554e8c073 libexec/fptd/ftpcmd.c: Removed as it is generated.
Change-Id: Id700ed9c2462e998f9c74482f80ee95b644a1399
2013-06-05 17:26:42 +02:00
Ben Gras
d579bb21f4 vm: bugfix: cover vfs_request-in-callback case
Change-Id: I16fccd9938fe8edab83c6c2e327d27d65ff20224
2013-06-05 15:02:56 +00:00
Thomas Cort
1d842c6a57 Importing libexec/fingerd 2013-06-02 08:14:05 -04:00
Thomas Cort
406cdd95a6 Importing usr.bin/finger 2013-06-02 09:52:40 +02:00
Thomas Cort
92f7a4ab20 Importing usr.bin/bdes 2013-06-02 09:52:35 +02:00
Qi Yong
c50a22578e remove vm_yield_block_get_block leftovers. 2013-06-01 20:51:31 +08:00
Ben Gras
4f3b015903 fix some warnings
Change-Id: I1f3fa582d8e3ddb3c981784dddb13e740102f4f3
2013-05-31 20:57:39 +00:00
Ben Gras
1cc6f4295d vm: handle disappearing process case
Change-Id: Id96759883e4cdb175c79dcef7ef5ff254612101f
2013-05-31 17:31:55 +00:00
Ben Gras
e92490cf47 ld.elf_so, grep, make: use mmap()
. let the dynamic linker use a real file mmap(), reverting
	  most of the minix-specific changes
	. except for a fallback mode for systems or filesystems that
	  do not support mmap() on files
	. make, grep: let them use mmap() too, with fallback

Change-Id: I11c0c9ad439d713917a6f5c2d196558f6c03eabd
2013-05-31 15:42:01 +00:00
Ben Gras
49b9165251 vm: mmap support
. test74 for mmap functionality
	. vm: add a mem_file memory type that specifies an mmap()ped
	  memory range, backed by a file
	. add fdref, an object that keeps track of FD references within
	  VM per process and so knows how to de-duplicate the use of FD's
	  by various mmap()ped ranges; there can be many more than there can
	  be FD's
	. turned off for now, enable with 'filemap=1' as boot option

Change-Id: I640b1126cdaa522a0560301cf6732b7661555672
2013-05-31 15:42:01 +00:00
Ben Gras
f369157d95 pfs, vfs: increase various limits
. pipes in pfs
	. vnodes in vfs
	. thread stack sizes in vfs

Change-Id: Ib27dedd42f57a90821a5b950cd7ea25cb2b42f3f
2013-05-31 15:42:00 +00:00
Ben Gras
33a7ac7557 vfs: mmap support
. libc: add vfs_mmap, a way for vfs to initiate mmap()s.
	  This is a good special case to have as vfs is a slightly
	  different client from regular user processes. It doesn't do it
	  for itself, and has the dev & inode info already so the callback
	  to VFS for the lookup isn't necessary. So it has different info
	  to have to give to VM.
	. libc: also add minix_mmap64() that accepts a 64-bit offset, even
	  though our off_t is still 32 bit now.
	. On exec() time, try to mmap() in the executable if available.
	  (It is not yet available in this commit.)
	. To support mmap(), add do_vm_call that allows VM to lookup
	  (to ino+dev), do i/o from and close FD's on behalf of other
	  processes.

Change-Id: I831551e45a6781c74313c450eb9c967a68505932
2013-05-31 15:42:00 +00:00
Ben Gras
924eb29565 fix inet warnings
Change-Id: Ia6e761d2c649f03a49b2646387f859d6c2a646cb
2013-05-31 14:30:52 +00:00
Thomas Cort
d8b7bfdfe8 Importing usr.bin/logname 2013-05-31 16:13:41 +02:00
Ben Gras
2d2a1a077d panic: declare as printf-style-checked
. and related fixes

Change-Id: I5131ac57dc53d8aec8d421a34c5ceea383404d7a
2013-05-31 13:35:25 +00:00
Ben Gras
5507a12d7c vfs: who_p fix
Change-Id: I0e04b6460907f5e67f6c90b2038d296d66b9a414
2013-05-31 09:28:38 +00:00
Ben Gras
edd50504e9 tcpd: waitpid() for any child process
. prevents zombies from accumulating for as long as tcpd exists
	  for child processes that create their own process group, e.g. ftpd.

Change-Id: Ic56597810f7d17e1cc28b755e2d1998ecf49a27c
2013-05-30 19:41:45 +00:00
Ben Gras
62da011387 import netbsd ftpd
Change-Id: Id7a3dbd40a6f37c55bcbb0d1456301f60626298f
2013-05-30 16:29:20 +00:00
Kees Jongenburger
eb1e5bf042 build:arm allow to store build settings in a .settings file.
If present a file called .settings will be sourced when
calling the arm_sdimage.sh script. This allows to configure
the build setting for arm build without the need to specify
the flags each time arm_sdimage.sh is called.

For example to configure arm_sdimage.sh to target the
beaglebone put the following content in your .settings file.

BASE_URL=http://www.minix3.org/arm/beaglebone
FLAG=-DAM335X
CONSOLE=tty00

Change-Id: Ide0341a255bc7f41dc5c30d0a43e71b01a8ea55c
2013-05-30 13:01:05 +02:00
Xiaoguang Sun
26428d4bc6 Add acpi poweroff
Use acpi poweroff if it's possible.

Change-Id: I103cc288523bf63fa536750b1d408ac88bbe35fb
Signed-off-by: Ben Gras <ben@minix3.org>
Signed-off-by: Tomas Hruby <tom@minix3.org>
2013-05-29 16:12:33 +00:00
Ben Gras
4fb3945025 vm: a bit more informative about failed pagefaults
Change-Id: I2b72dfb9291670cb837dfdb279f519892575d4a6
2013-05-29 15:25:45 +00:00
Ben Gras
624e7c37d7 gen_uEnv.txt.sh shell neutraling
Change-Id: I52d5ac548373db1c4db9af79a24c2c9e2c1c1dcb
2013-05-29 12:10:22 +00:00
Thomas Cort
0d70265775 syslog.conf: correct PID file path in comments.
The syslogd.pid file has moved from /usr/run to /var/run. The comments
in syslog.conf direct the user to restart syslogd using the old PID
file location. This patch updates the comment to match the code.

Change-Id: Ib40cd1199ce201e1cbc74e1f1393d55a166ef343
2013-05-28 23:04:50 +02:00
f0d23d912d servers/pm: Fix EFAULT check for SETGROUPS
The previous test would return EFAULT as soon as the group pointer
was NULL, while it is sensible when the count is also 0.

In that case, the SETGROUP syscall is expected to clear all the
group entries as the new set is empty.

Change-Id: I07b7e1d1f023a52e3035d53f7d9b42b660e039e8
2013-05-28 21:07:04 +02:00
Qi Yong
61f6e2f5f0 fix some comment typo's
Change-Id: Ic9f4333613abb858bfc28f72685424557cf2cd40
2013-05-26 14:12:54 +00:00
Kees Jongenburger
5e5ea947e8 arm:build add flags for AM335X
Change-Id: I1fd25d5ada52972fd2f6ec5057ff273544c65390
2013-05-24 15:47:04 +02:00
Kees Jongenburger
ffea6706f0 arm:also use 1MB sections for mapping AM335X device memory.
Change-Id: Idc0b285fcbabe8ec4c0be9a600b6a720c0bd3ffc
2013-05-24 15:47:04 +02:00
Kees Jongenburger
758c8eaf41 arm:adapt MMC driver to also work on the AM335X platform.
Change-Id: I30e69b7bfd377d1dd2b0b458dd00ee411b060285
2013-05-24 15:47:04 +02:00
Kees Jongenburger
0748a95f88 arm:mmc only compile mmchs when targeting arm.
Change-Id: Ie8d0b6461b58c2a7becda98401dece81be607a01
2013-05-24 15:46:59 +02:00
Kees Jongenburger
742cf53aa9 arm:adapt tty driver for AM335X.
Change-Id: Ic861d68d0576c2abcdcb265a450c013ea2b28499
2013-05-24 14:03:14 +02:00
Kees Jongenburger
167c4d972f arm:build also generate cmdline.txt
Also generate cmdline.txt as we need to use a different serial
for the AM335X boards.

Change-Id: I18c1b5911b5d7238d4a765e0aa01613908d9f2e6
2013-05-24 14:03:14 +02:00
Kees Jongenburger
3139ce9631 arm:omap timers remove hardcoded base address.
Omap timers remove hardcoded base address and add some initial
support for the beaglebone's timers. Frclock_util will need
refactoring to remain independent of the ARM flavour.

Change-Id: I2b5d04e930364262c81b5686de634c0a51796b23
2013-05-24 14:03:14 +02:00
Kees Jongenburger
534b19187e arm:configure tick per ms to reflect the free running clock.
Change-Id: Ifc02658d6ae48dd01a868bfaa3d60f77bc6cc800
2013-05-24 13:59:04 +02:00
Kees Jongenburger
2856cec5b9 arm:interupt handling remove hardcoded base address.
Remove hardcoded base address for the omap interrupt handler and add
interrupt names for AM335X in omap_intr.h.

Change-Id: Ie606d8612f55990d55f9db655583052f53950e8e
2013-05-24 13:59:04 +02:00
Kees Jongenburger
c40df92bf2 arm:add AM335X serial
Change-Id: I728622ddd4f59529d15e8ac2499c41fa815eee3b
2013-05-24 11:17:52 +02:00
Kees Jongenburger
69dc6a4f15 arm:keep kernel and modules in the first 256MB of memory.
Keep kernel and modules in the first 256MB of memory in preparation
for the beaglebone. That target only has 256 MB of memory.

Change-Id: I3d92247b5d4e5d3aab7388fe01c2f5713d6a4593
2013-05-24 11:17:52 +02:00
Kees Jongenburger
571ea5b4d7 arm:remove hardcoded base address for the in kernel serial.
Removed hardcoded base address for in kernel serial. This will ease
porting to different boards and allow us to remap i/o at later stage.

Change-Id: I4a4e00ed2aa2f94dfe928dc43a6816d3b94576b7
2013-05-24 11:17:52 +02:00
Kees Jongenburger
5d15ac7c20 arm:kernel simplify the in kernel serial.
Simplify the in kernel serial header to a minimum. The driver doing
the real handling is the tty driver.

Change-Id: I5d487d71a3d22906313aa8af5e9d84b0751a6868
2013-05-24 11:17:52 +02:00
Kees Jongenburger
6364989e36 arm:add DDM37XX cflag
We are planning on using the NetBSD config system to perform build
system configuration when targeting different hardware variants.
This functionality however is not integrated yet and we currently
rely on using ifdef's in the code. This commit add the DDM37XX flag.

Change-Id: Ia25dfa520c7df4b648f4d1a583808de774acff63
2013-05-24 11:17:52 +02:00
Kees Jongenburger
ad68d15e39 arm:build generate uEnv.txt
Generate uEnv.txt to allow to generate an uEnv containing commands
to boot over the network.

Change-Id: I8bcd831ee474d837411568bf1c1e2c2d96ec931b
2013-05-24 11:16:59 +02:00
881ff3f6e5 releasetools/arm_sdimage.sh: Improvements
- Added the possibility to define the number of parallel jobs from the
   command line with (example, default is 1):
   $ JOBS=8 ./releasetools/arm_sdimage.sh

 - Generate filesystem filling the reserved partition area, instead of
   being smaller.

 - Added a possibility to specify additional parameter to the build.sh
   script from the command line with (example):
   $ BUILDVARS='-N0 -V MYVAR=yes' ./releasetools/arm_sdimage.sh

Change-Id: I5c34268ebf7d45a8d3408b45b1dc5051d775826c
2013-05-24 11:08:15 +02:00
e1acf37d77 usr.sbin/mkfs: Allow -b SIZE with proto file
Previously, if a proto file was given, the -b argument would be ignored.

Also added:
 - if the number of inodes is not given, then an estimation is used.
 - sanity checks where moved from one special case to the general case.

Change-Id: I2abfa52bf34206c9087c64b5bfc26af866eb47cb
2013-05-24 11:08:15 +02:00
154b6d7486 Fix symlink issue when generating an ARM image
A few symlinks were pointing to a nonexistent file named '(null)'
instead of their intended target. This was only seen when using the
arm_sdimage.sh script.

There is two ways of specifying links and directories. the first one
using an entry in one of the mtree files, and the second one in
/etc/Makefile.

Those entries where doubled, and one of them would specify some rights,
while the other had the target.

By removing those entries, I make sure there is only one definition of
these symlinks, which solves the problem I was seeing on an ARM image.

These symlinks are still present on a generated system, as they are
required.

Change-Id: I9ced8860f72d7c4d686a09720de4d8257d6e04fa
2013-05-24 11:08:15 +02:00
Ben Gras
fd5f2edf35 mkfs: only complain about failing stat with -d
mkfs -d is a feature that needs a stat() of the mkfs binary, which
often fails (as mkfs is often not invoked with a full path or from
the same directory). it makes setup look a bit messy as the error
is always printed while installing the system, for each created FS,
even though the situation is harmless. This change only complains
when the stat is actually needed (-d).

Change-Id: I54ac01505aa97c1cbe40456c04a35aed5a7ee953
2013-05-23 12:09:38 +02:00
Ben Gras
d12d57dcd8 arm: recognize instruction fetch pagefault
. an instruction fetch pagefault generates a prefetch
	  abort exception, this should also be a source of
	  a pagefault event
	. the saved_lr argument to the C exception handler was
	  sometimes an address, sometimes a pointer to that address;
	  the kernel sometimes dereferences it, so it should always be
	  an in-kernel address, never a userspace address. fix in mpx.S
	  makes it always a pointer.
	. move dumping of all processes over serial out of
	  the arch-specific arch_system.c
2013-05-21 15:05:06 +02:00
Ben Gras
225ed6d7bd at_wini: enable busmastering in pci if necessary 2013-05-18 15:57:30 +00:00
Ben Gras
e8681e9929 virtio_blk: always start if found
Change-Id: Iec70c67e1b675297b5ffb800a9fb263feffa9271
2013-05-17 11:32:45 +00:00
Kees Jongenburger
1e1ff96aea arm:vm caching fix.
Improve reliability by using write trough cache.
2013-05-16 20:39:20 +02:00
Kees Jongenburger
a3f6529ee2 arm:vm header cleanup. 2013-05-16 20:39:19 +02:00
Kees Jongenburger
b9cb8251bc arm:make no assumptions about TRE and AFE
The bootloader can leave the system control register
in at state that doesn't match our setup. make no assumptions
and configure TRE and AFE.
2013-05-16 20:39:19 +02:00
Kees Jongenburger
84eeb1e681 build:arm enable verbose mode by default. 2013-05-16 20:39:19 +02:00
Kees Jongenburger
f6c762b5d3 build:arm disable I and D cache before loading the kernel. 2013-05-16 20:39:19 +02:00
Kees Jongenburger
0aeb7d85d1 build:copy uEnv and cmdline.txt onto OBJ 2013-05-16 20:39:19 +02:00
Kees Jongenburger
7e2c8b516d build:make sdimage more silent.
Change-Id: I9bba37c93c27c599ec914d1f069ca21e6cbfe111
2013-05-16 20:39:18 +02:00
Kees Jongenburger
4ab5b32edf build:add sbin and bin to path.
normal users don't have sbin in their path where sfdisk is
installed.

Change-Id: I7ee3412ca0f6fb208310aa7a0ee8cd88c0f3f80c
2013-05-16 20:39:18 +02:00
Ben Gras
062d5d7811 Revert "virtio_blk: always start if found"
Wrong commit pushed, investigating.

This reverts commit a476662532.
2013-05-16 13:34:17 +00:00
Ben Gras
a476662532 virtio_blk: always start if found
Change-Id: Iec70c67e1b675297b5ffb800a9fb263feffa9271
2013-05-16 12:02:48 +00:00
Ben Gras
7a0497feae mk.conf: workaround for pkgin sourcing it
Change-Id: Ie01c5781ff3372d6415bc8878270002988320c56
2013-05-16 11:13:00 +00:00
Antoine Leca
e35821b207 mkfs.mfs: various programs
Split in as many programs as needed to support various variants of MFS
Manual page updated (in mandoc format)
2013-05-13 11:18:15 +02:00
Antoine Leca
49fe5d1617 mkfs reloaded
* restored the zone>block stuff
* generalized the support for more-than-1-block bitmaps to also deal
  with big inodes maps in small blocks
* improved pexit() to printf-like syntax; also replaced pexit() with
  err() or errx() where there are no reference to proto lines
* unified the allocation of blocks to all use alloc_block() instead
  of raw malloc half of the time
* removed the V2_ d2_ etc. prefixes which are obscure and obsolete

While here, also
* used new-form definitions, and closer to KNF style in general
* used often-built-ins such as mem* or strncpy where relevant
* pruned a fair amount of constants which are irrelevant

Thanks to Thomas V. and Lionel who did a good amount of work with the
cross-compilation stuff and made that change to be much smoother.
2013-05-13 11:17:34 +02:00
Ben Gras
717425320f kernel, random: adaptive entropy gathering
kernel: stop gathering timestamps once the bin is full per interrupt

random: once seeded, retrieve new entropy at a lower rate

Change-Id: I4ce6081d39274728d82c6889686d1650cfd5fc2e
2013-05-07 17:19:06 +00:00
Ben Gras
4ebb889e7a libsys: panic hook feature
. vfs: use it to dump threads stacks

Change-Id: I7ae3521fc153a407505f11049629e6d4142cf7c7
2013-05-07 17:18:40 +00:00
Ben Gras
80846c4a79 kernel ipc debug: various fixes
. add receive hooks in the kernel to print asynchronously
	  delivered messages
	. do not rely on MF_REPLY_PEND to decide between calls and errors,
	  as that isn't reliable for asynchronous messages; try both instead
	. add _sendcall() that extract-mfield.sh can then reliably recognize
	  the fields for messages that are sent with just send()
	. add DEBUG_DUMPIPC_NAMES to restrict printed messages to
	  from/to given process names

Change-Id: Ia65eb02a69a2b58e73bf9f009987be06dda774a3
2013-05-01 21:40:23 +00:00
Ben Gras
85fd078707 tty: non-overlapping code for FKEY_CONTROL
. to decode it in kernel/debug.c

Change-Id: I0d2cc66e87d97a362fa549b364b4d1b0e1225e66
2013-05-01 21:36:43 +00:00
Kees Jongenburger
dfbe2f16ee build:Updated proto.dev from mkproto -s /dev
proto.dev was missing some entries and is currently used as base version for
the ARM root file system.
2013-04-29 11:47:40 +02:00
Kees Jongenburger
e6bac75a8b ARM:Rename ARM_BIG_PAGE to ARM_SECTION.
The natural term to use when talking about MINIX big pages on ARM
is SECTION. A section is a level 1 page table entry pointing to
a 1MB area.

Change-Id: I9bd27ca99bc772126c31c27a537b1415db20c4a6
2013-04-29 11:42:26 +02:00
Ben Gras
236a320240 mkfs.mfs: double indirect block support
. allows >4MB files for default 4k block size

Change-Id: I09277fc3704fac1a44af82202c11435dc7ae8d55
2013-04-27 16:25:45 +02:00
Ben Gras
f497d9b9c4 ext2: annotate cache blocks with inode metadata
. allows mmap() to work on it

Change-Id: I33af8b86ebb408d971478d00ed2caacf15afc7a5
2013-04-26 15:39:07 +00:00
Ben Gras
f0cc010614 libminixfs, mfs, ext2: may re-evaluate cache size
libminixfs may now be informed of changes to the block usage on the
filesystem. if the net change becomes big enough, libminixfs may
resize the cache based on the new usage.

	. update the 2 FSes to provide this information to libminixfs

Change-Id: I158815a11da801fd5572a8de89c9e6c039b82650
2013-04-26 13:57:08 +00:00
Kees Jongenburger
988c7e39c0 libelf:use self hosted m4.
Change-Id: Ia836aa6c43d7ccbb02047e63424923fdc74eb42d
2013-04-24 17:22:59 +02:00
Kees Jongenburger
dca81e0581 toproto:convert special execute bits to chars
Convert the special execute bits of the METALOG file mode entries into mkfs.mfs
compatible u and g flags.
2013-04-24 13:22:45 +02:00
Ben Gras
44f34e53d5 VFS: Implement REQ_BPEEK.
This commit introduces a new request type called REQ_BPEEK. It
requests minor device blocks from the FS.  Analogously to REQ_PEEK,
it requests the filesystem to get the requested blocks into its
cache, without actually copying the result anywhere.

Change-Id: If1d06645b0e17553a64b3167091e9d12efeb3d6f
2013-04-24 10:18:16 +00:00
Ben Gras
0cfff08e56 libexec: mmap support, prealloc variants
In libexec, split the memory allocation method into cleared and
non-cleared. Cleared gives zeroed memory, non-cleared gives 'junk'
memory (that will be overwritten anyway, and so needn't be cleared)
that is faster to get.

Also introduce the 'memmap' method that can be used, if available,
to map code and data from executables into a process using the
third-party mmap() mode.

Change-Id: I26694fd3c21deb8b97e01ed675dfc14719b0672b
2013-04-24 10:18:16 +00:00
Ben Gras
6fa5ce74ce MFS: annotate cache blocks with inode metadata
. use lmfs_* cache functions that provide the cache with inode
	  metadata whenever applicable, i.e. tell the cache code which
	  inode number and in-inode offset a particular cache block
	  corresponds to.
	. needed for mmap implementation

Change-Id: Ic7d3c0c49029880f86a31368278722e907bc2896
2013-04-24 10:18:16 +00:00
Ben Gras
49eb1f4806 vm: new secondary cache code
Primary purpose of change: to support the mmap implementation, VM must
know both (a) about some block metadata for FS cache blocks, i.e.
inode numbers and inode offsets where applicable; and (b) know about
*all* cache blocks, i.e.  also of the FS primary caches and not just
the blocks that spill into the secondary one. This changes the
interface and VM data structures.

This change is only for the interface (libminixfs) and VM data
structures; the filesystem code is unmodified, so although the
secondary cache will be used as normal, blocks will not be annotated
with inode information until the FS is modified to provide this
information. Until it is modified, mmap of files will fail gracefully
on such filesystems.

This is indicated to VFS/VM by returning ENOSYS for REQ_PEEK.

Change-Id: I1d2df6c485e6c5e89eb28d9055076cc02629594e
2013-04-24 10:18:16 +00:00
Ben Gras
7421728360 VM: memtype fix
Memory types in VM are described by methods. Each mapped region has
a type, and all pages instantiated get that type on creation.
Individual page types has to be able to change though. This commit
changes the code to use the memory types of the individual pages,
where appropriate, instead of just the higher-level region, in case
it has changed. This is needed to e.g. support future copy-on-write
MAP_PRIVATE mmap modes.

Change-Id: I5523db14ac036ec774a54392fb67f9acb8725731
2013-04-24 10:18:15 +00:00
Ben Gras
9e88c40e40 VM: 64-bit mmap()
Some (backwards-compatible) changes in mmap() call message fields
that allow for a 64-bit offset. minix_mmap() takes an off_t and
minix_mmap64() takes a u64_t. Some mmap() work in VM goes into a
separate function, using the new fields, so that that can be re-used
when files are to be mapped (future commit).

Change-Id: Ifb77a90b593dd3c33cf81b396068e4da1ec5fb1c
2013-04-24 10:18:15 +00:00
Ben Gras
75c5fe4c26 filesystems: return ENOSYS for REQ_PEEK
The filesystems already implement REQ_PEEK, but do not fully
use the new filesystem cache code yet. (Because it isn't committed
yet..) REQ_PEEK should be disabled for them until they do.

This indicates to VFS that they are not annotating their cache
blocks (in VM) with inode number/offset info, and therefore mmap()
shouldn't succeed on any of their files. (Most importantly exec()
won't fallback elegantly otherwise.)

Change-Id: Ic57ee422864b4bbc031eadba32973270907b02fd
2013-04-24 10:18:10 +00:00
Ben Gras
adf2032bc0 vm: remove secondary cache code
This commit removes the secondary cache code implementation from
VM and its usage from libminixfs. It is to be replaced by a new
implementation.

Change-Id: I8fa3af06330e7604c7e0dd4cbe39d3ce353a05b1
2013-04-24 10:18:10 +00:00
Xiaoguang Sun
20e6c9329f Change function prototype to use endpoint_t instead of int 2013-04-23 17:15:15 +02:00
Kees Jongenburger
8a3677def0 build:refactor arm_sdimage.sh as to no longer require root.
There where two reasons for needing root access while making ARM builds. The
first reason was that we needed root permissions to create device nodes and
assign permissions to files. The second reason we needed root was that we used
loop mounted files to copy the build output to the file backed storage.

The first problem is solved by building in unprivileged mode (adding -U) during
compilation. The second problem is solved by using mcopy to put files on the
fat partition and use the mkfs.mfs proto files to create MFS file system.

Future work might be to replace this script by the netbsd makefs tool.

Change-Id: Ibba61d4cad053f7c1ede26169d5214065a4939d8
2013-04-23 11:24:12 +02:00
Kees Jongenburger
fd7bb1786e build:add tool to convert from METALOG to proto files.
Change-Id: I5c4e15b1a2bac5a4ca3a0530f8d6aa2643ac720a
2013-04-21 21:36:30 +02:00
Kees Jongenburger
f8dbcfa7f2 build:add script to sort netbsd sets and sort minix/mi.
Change-Id: I309d8bbcfe2f5b6d5e1ae7626422c4402985ad1d
2013-04-21 21:35:49 +02:00
Kees Jongenburger
fcb66ed1b5 run script:return 1 upon test failure.
Change-Id: If3c9d636a04da7f7b4098b58d29c492c664dab1a
2013-04-21 20:18:11 +02:00
Ben Gras
32a4e0d84d many new tests
. test70: regression test for m_out vfs race condition

The following tests use testcache.c to generate test i/o
patterns, generate random write data and verify the reads.

	. test71: blackbox full-stack test of FS operation, testing
	  using the regular VFS interface crazy i/o patterns
	  with various working set sizes, triggering only
	  primary cache, also secondary cache, and finally
	  disk i/o and verifying contents all the time
	. test72: unit test of libminixfs, implementing
	  functions it needs from -lsys and -lblockdriver
	  and the client in order to simulate a working
	  cache client and backend environment.
	. test73: blackbox test of secondary vm cache in isolation

Change-Id: I1287e9753182b8719e634917ad158e3c1e079ceb
2013-04-19 16:21:48 +00:00
Ben Gras
072d916c1c vfs: fix null deref, pfs: add fchmod()
. vfs read_only() assumes vnode->v_vmnt is non-NULL, but it can
	  be NULL sometimes
	. e.g. fchmod() on UDS triggered NULL deref; add a check and
	  add REQ_CHMOD to pfs so unix domain sockets can be fchmod()ded
	. add to test56

Change-Id: I83c840f101b647516897cc99fcf472116d762012
2013-04-19 17:06:56 +02:00
Kees Jongenburger
04ad4fa1a2 mkfs.mfs:add comment about the overflow check.
Change-Id: I1f09c3a62377164296037f6dc9b7874023123311
2013-04-19 13:10:06 +02:00
Kees Jongenburger
a4eca06cca mkfs.mfs:fix to allow to fill larger file systems.
Allow the number of written blocks to exceed 8 * block_size.

Change-Id: I301ce46a92d86c6220c3af2acee22db26a4b4496
2013-04-19 13:10:06 +02:00
Kees Jongenburger
15bb31ed99 mkfs.mfs:remove MFS V1 related headers.
Change-Id: I46a8128f54112ee0092ef60160d88cadd0038be0
2013-04-19 13:10:06 +02:00
Kees Jongenburger
1beca4b7f5 mkfs.mfs:remove some globals
Remove the gobal inocount, zonecount and blockcount.

Change-Id: I77d120bb79bcf183e0c6b5abed736343af7badf2
2013-04-19 13:10:06 +02:00
Ben Gras
0245723d5f run script: correction, clarity
Change-Id: Ibf583c6277c67646dd90d7c49482daf4e76b78b6
2013-04-19 10:24:50 +00:00
Ben Gras
2a44efb1c0 test run: feature for nicer jenkins interaction
. add -l option to list available tests
	. add -t option to specify tests to run
	. also improve the root check a bit by
	  not relying on an environment var
	. do not print the human-friendly banner & summary
	  if a test list is given to make the test
	  results easy to parse

Change-Id: Id0f87d485240b1924d667af788338ae31c3dc94c
2013-04-18 14:28:03 +00:00
Ben Gras
5977114c42 tests cleanup
. make common.o link with the tests instead of being
	  #included as common.c
	. fix warnings about missing prototypes by declaring functions
	  static
	. reduces some duplicated code

Change-Id: Ic2a765d7f5886add5863190efec3fdd2d2ea2137
2013-04-17 22:00:59 +00:00
Ben Gras
cef94e096e vfs: make m_out non-global
m_out is shared between threads as the reply message, and it can happen
results get overwritten by another thread before the reply is sent. This
change

	. makes m_out local to the message handling function,
	  declared on the stack of the caller
	. forces callers of reply() to give it a message, or
	  declare the reply message has no significant fields except
	  for the return code by calling replycode()

Change-Id: Id06300083a63c72c00f34f86a5c7d96e4bbdf9f6
2013-04-12 23:40:38 +00:00
Michael W. Bombardieri
cb51426c6a rs232: remove unneeded lock()/unlock() functions
Change-Id: Ie1d2a7f460132aa59791cd7d16c9068b79675f1b
2013-04-12 21:37:26 +02:00
Thomas Cort
a0a1440a52 remove utimes() workarounds
With the addition of utimes(), we can remove the workarounds
and use the original NetBSD code for timestamping files.

Also restore use of -p & -r for install while building
2013-04-12 18:55:40 +00:00
Antoine Leca
3ae6c600a9 Add tests for utime*s() functions 2013-04-12 18:55:40 +00:00
Antoine Leca
9131e98a7d utimens(2) system call
Variant of utime(2) with struct timespec (with ns precision)
instead of time_t values; also allows for tv_nsec members
the values UTIME_NOW (force update to current time) or
UTIME_OMIT (allow to set either atim or mtim independently.)

Provides a superset of utimes(2), futimes(2), lutimes(2),
and futimens(2).
Provides the same subset of utimensat(2) as does NetBSD 6.
Also import utimens() and lutimeNS() from NetBSD-current.
2013-04-12 18:55:39 +00:00
Kees Jongenburger
88414c568c cleanup:misc documentation fix. 2013-04-12 20:52:58 +02:00
Kees Jongenburger
99c5247453 arm_sdimage:hide non fatal errors.
Redirect the output of the command that are supposed to fail to
/dev/null.
2013-04-12 20:52:58 +02:00
Kees Jongenburger
9d9456ef7d arm:cleanup add assert. 2013-04-12 20:52:57 +02:00
Kees Jongenburger
1e9492a8b8 arm:cleanup omap serial, remove unused defines. 2013-04-12 20:52:57 +02:00
Kees Jongenburger
037aeb5a13 arm:rs232 fix.
The kernel API for requesting interrupts and the associated callback
have a somewhat strange behaviour. Requesting an interrupts is done
by calling sys_irqsetpolicy using an interrupt and a given id. This
id can be modified by the sys_irqsetpolicy and must be used for
subsequent calls to sys_irqenable/sys_irqdisable. However upon an
incoming call from the kernel NOTIFY_ARG contains the original value
encoded in a set e.g. if  1 << id == true the interrupt was raised.
2013-04-12 20:52:57 +02:00
Kees Jongenburger
aa3db0e0e2 mmc:Change startup message in rc script. 2013-04-12 20:52:57 +02:00
Kees Jongenburger
7015c66bfa arm:increase the amount of interrup vectors
Increase the amount of interrup vectors in preparation for the AM335X.
2013-04-12 20:52:57 +02:00
Kees Jongenburger
390f852bd1 arm:cleanup remove special case memory handling.
We used to load the memory driver above the other modules to allow
the memory driver (ramdisk) to grow. We no longer want or need this
this as we have a working mmc driver.
2013-04-12 20:52:57 +02:00
08ff44c446 Reducing external/bsd/file differences
Change-Id: I0d025059ba0b200ac1162ea5a764fd756600ecd0
2013-04-12 13:25:18 +02:00
Antoine Leca
c979136e4e Also apply sub-second UTIME to libpuffs 2013-04-12 11:11:59 +02:00
Antoine Leca
4069cef7f9 Subsecond timestamps support for FS
Expand REQ_UTIME to include tv_nsec members
(as in struct timespec) in addition to tv_sec==time_t

Designed with help from David van Moolenbroek
2013-04-12 11:11:59 +02:00
Antoine Leca
df9d28ebe7 Libpuffs: use struct timespec instead of time_t 2013-04-12 11:11:59 +02:00
Antoine Leca
9315ea8299 sys/stat.h: better align with NetBSD-current 2013-04-12 11:11:58 +02:00
Michael W. Bombardieri
a806c5feb1 make minix lwip make explicit use of 'int'
makes lwip use "unsigned int" instead of "unsigned" since this is
more obvious (i.e. type is not implied).

Change-Id: I852eb80484516e1235241d55be3e15174fa24109
2013-04-11 22:37:30 +02:00
435f2b0095 Downgrading to netbsd zlib version
Change-Id: I83cf73d8357ea34ab5e49fe15bd4c45ce54cac01
2013-04-09 16:43:13 +02:00
dd6b239665 Removing include/minix/limits.h
This files defines two constants which are only used through
sys/syslimits. So they where moved there instead of including the file
and it was removed.

Change-Id: Iba3d220144dddf5d6411a6c66e2f223a1aafb50f
2013-04-09 16:43:02 +02:00
78cbcc9750 Adding missing dependency on libraries for hdboot
* Also cleanup a bit the makefile.
 * Also removing small inconsistency for arm builds where log would be
   skipped if doing a make hdboot, but not when cross-compiling.

Change-Id: Ic9e20655234a667ea8a967d05589d4df46c2d521
2013-04-09 16:41:52 +02:00
Thomas Cort
b3cb63379e tests/run: add test69 to setuids.
test69 requires superuser powers to adjust the time. This caused
the test to fail when run as a normal user. The patch adds test69
to the setuid list which will allow regular users to execute it.

Patch contributed by Antoine Leca.
2013-04-08 14:22:27 +02:00
Thomas Cort
8357e3a442 Importing usr.sbin/rdate
Import the NetBSD rdate command and remove the Minix rdate command.
The default behaviour for both is the same. The NetBSD version adds
options to just display the time, adjust the time using adjtime(),
and set the time without printing the time.

Porting Notes:
 - Compiles cleanly out of the box without any warnings
 - Path changes from /usr/bin/rdate to /usr/sbin/rdate
 - checked pkgsrc for any usages of rdate (none found)
 - checked src for any usages of rdate (none found)

Testing:
 - all command line options work (tested with time.nist.gov server)
 - Native and cross build OK

Change-Id: I613449763891a896527f337999c006a970c3924c
2013-04-08 08:37:04 +02:00
Antoine Leca
0f487a702b etcfiles: Improve the "install" message 2013-04-07 00:38:00 +02:00
Thomas Cort
04203a83a6 Importing usr.bin/ftp 2013-04-05 19:02:06 +00:00
Ben Gras
2db46bcfa1 top: a few fixes
. fixed overflow in ticks compare function, causing
	  occasionally esp. the kernel to be mis-ordered by cpu
	  time
	. fixed some const string related warnings
	. fixed some variable name shadowing warnings

Change-Id: I02c177b1579bce164372f9b03f6b472537cc9e3e
2013-04-05 15:27:09 +00:00
a264c7ec4c Remove obsolete warning in sys/sys/sysctl header
Change-Id: Idb9b10922d00d4b3886c8247f352cc4ec5fe17b4
2013-04-05 13:24:18 +02:00
Thomas Cort
f05ad905a8 inet: silence message about exceptions
. inet: silence message about exceptions not being implemented
	  for select(UDP)

This message generates a lot of noise with openntpd. Hide it unless DEBUG is
turned on.

Change-Id: I1527a9ca2583601d6087456062b4f675c80dd711
2013-04-04 15:06:18 +02:00
Thomas Cort
15b3d77268 libc: add adjtime() system call.
Implement the adjtime() system call and add a test for it to test69.
Additionally, install the adjtime.2 and clock_*.2 man pages.
2013-04-04 15:04:54 +02:00
Thomas Cort
516fec97d9 libc: add clock_settime() system call.
This also adds the sys_settime() kernel call which allows for the adjusting
of the clock named realtime in the kernel. The existing sys_stime()
function is still needed for a separate job (setting the boottime). The
boottime is set in the readclock driver. The sys_settime() interface is
meant to be flexible and will support both clock_settime() and adjtime()
when adjtime() is implemented later.

settimeofday() was adjusted to use the clock_settime() interface.

One side note discovered during testing: uptime(1) (part of the last(1)),
uses wtmp to determine boottime (not Minix's times(2)). This leads `uptime`
to report odd results when you set the time to a time prior to boottime.
This isn't a new bug introduced by my changes. It's been there for a while.
2013-04-04 15:04:54 +02:00
Thomas Cort
18ad4c0799 test69: add clock_getres() and clock_gettime() tests. 2013-04-04 15:04:53 +02:00
Thomas Cort
e67fc5771d libc: add clock_getres()/clock_gettime() system calls.
In order to make it more clear that ticks should be used for timers
and realtime should be used for timestamps / displaying the date/time,
getuptime() was renamed to getticks() and getuptime2() was renamed to
getuptime().

Servers, drivers, libraries, tests, etc that use getuptime()/getuptime2()
have been updated. In instances where a realtime was calculated, the
calculation was changed to use realtime.

System calls clock_getres() and clock_gettime() were added to PM/libc.
2013-04-04 15:04:53 +02:00
Thomas Cort
5142b1f388 kernel: rename realtime to monotonic, add realtime
Old realtime was used for both timers (where an accurate count of
all ticks is needed) and the system time. In order to implement
adjtime(2), these duties must be separated as changing the time
of day by a small amount shouldn't affect timers in any way nor
should it change the boot time.

Following the naming of the clocks used by clock_gettime(2). The
clock named 'realtime' will represent the best guess at the
current wall clock time, and the clock named 'monotonic' will
represent the absolute time the system has been running.
Use monotonic for timers in kernel and in drivers. Use realtime
for determining time of day, dates, etc.

This commit simply renames realtime to monotonic and adds a new
tick counter named realtime. There are no functional changes in
this commit. It just lays the foundation for future work.
2013-04-04 15:04:52 +02:00
Ben Gras
d6bc6cb44b some etc fixes
. split user-editable and system-owned files in etc/Makefile
	. mtab is a symlink, not a file now; remove it
	. force-install of certain system-controlled /etc files from
	  top Makefile
	. rename /etc/make.conf to /etc/mk.conf; and don't set $ARCH;
	  reduce difference in bsd.own.mk

Change-Id: I9f4bbb8d37ba80cba7dcfcf1a9a89e934910f579
2013-04-04 12:50:12 +00:00
b622d2b795 mkfs.mfs fixup
For the special case of crossbuilding minix on minix.
2013-04-03 15:57:04 +02:00
Ben Gras
aafef7f9ff etc: force system.conf install
Change-Id: I5f88b108248fb3cee457de8a2f2baa2f30b0a335
2013-03-30 15:01:15 +01:00
Tomas Hruby
a1fa603ed5 lwip (inet's alternative) is compiled by default 2013-03-25 16:51:25 +01:00
Tomas Hruby
ee0cc364a8 core is not cleaned in libraries
- according to Lionel, no such files are generated

- it conflicts with the core subdirectory in liblwip
2013-03-25 16:51:25 +01:00
Tomas Hruby
9582cbffc5 LWIP - avoid an assert when a driver restarts 2013-03-25 16:51:25 +01:00
Tomas Hruby
00f08c4868 LWIP - avoid crash when an unknown driver come up 2013-03-25 16:51:25 +01:00
Tomas Hruby
f6b5201f64 LWIP - fixed TCP panic when shutting down
- listening sockets do not handle some callbacks
2013-03-25 16:51:25 +01:00
Tomas Hruby
566af1516a LIBLWIP - ARP fix
- does not crash KVM anymore
2013-03-25 16:51:25 +01:00
Ambarisha B
2d9009b0ab LWIP - fixed makefiles
- Modified libnetsock/Makefile and servers/lwip/Makefile to
  include ipvX headers

Signed-off-by: Tomas Hruby <tom@minix3.org>
2013-03-25 16:51:25 +01:00
Ambarisha B
7e55dbac33 LIBLWIP - updated to LwIP trunk
commit a4a41b9023ef5b3a7c4a1cd82fb167fc63e706df
Author: goldsimon <goldsimon@gmx.de>
Date:   Wed Sep 26 21:50:42 2012 +0200

- This also brings in LwIP's IPv6 codebase

Signed-off-by: Tomas Hruby <tom@minix3.org>
2013-03-25 16:51:24 +01:00
Tomas Hruby
9d66e2299d LIBLWIP - fixed clang warnings 2013-03-25 16:51:24 +01:00
Thomas Cort
1d4c0ebe0f Importing usr.bin/from 2013-03-23 16:11:11 +01:00
Thomas Cort
66601c7f92 Importing usr.bin/whatis
- LSC: fixed missing entry in minix/mi

Change-Id: I5766dd72819e3b15ef24ab49c5ee3a5aa42049c4
2013-03-23 16:10:23 +01:00
Thomas Cort
ab046ee6ea Importing usr.bin/head 2013-03-23 14:37:39 +01:00
Thomas Cort
d5a4c35980 include/paths.h: correct _PATH_MAILDIR 2013-03-23 13:29:55 +01:00
David Höppner
4de64f892a Importing NetBSD banner 2013-03-22 10:15:11 +01:00
Thomas Veerman
6ee180f5f7 VFS: wikify README
Change-Id: I746f7c8ddabd1e047b8d536df14586c5b1594d55
2013-03-21 15:20:34 +00:00
Ben Gras
4f9139778d vfs: coredump fix: write zeroes for missing memory 2013-03-20 20:05:31 +00:00
David van Moolenbroek
50e46307de Move MINIX reboot definitions into minix/reboot.h
Also fix a buffer overflow in commands/reboot/sh_wall.c.

Change-Id: I3a61057c4f0221d1700e14d44520b4ad17f1dbe1
2013-03-20 16:50:01 +00:00
David van Moolenbroek
3be9c7c33b Rename "struct partition" to "struct part_geom"
Change-Id: Ifaf9795ba70f5b933599b2a6ec9415e6bd13200c
2013-03-20 16:14:21 +00:00
Thomas Cort
32bef00fec release.sh: pkg_install should be installed 1st
pkgin now depends on pkg_install. If pkg_install appears after pkgin
in PREINSTALLED_PACKAGES, there will be an error because pkg_install
was installed as a dependency for pkgin.
2013-03-19 00:29:45 +01:00
Thomas Cort
cfefa17ed7 packages.install: remove obsolete minix-all pkg.
The minix-all package was placed by the pkgin_all command.
2013-03-19 00:29:44 +01:00
Thomas Cort
a99e83a2dc Importing usr.bin/cal 2013-03-18 11:27:44 +01:00
Thomas Cort
85468eb5c8 Importing usr.bin/yes
Change-Id: Ia76d7ce9c6b2bf7523d2ecbc6470e3e1e7ab5ee5
2013-03-18 11:27:25 +01:00
Thomas Cort
b6d4a4c155 Importing usr.bin/who 2013-03-18 11:23:59 +01:00
Ben Gras
0022ee2cb5 VM: ARM/I386 PDE/PTE macro unification
. further reduces special cases in pagetable.c

Change-Id: Ifd7dd9ee10ca618a47bb4a372467205fbe6da90e
2013-03-14 13:55:04 +00:00
Thomas Cort
2718b5688b Importing bin/ksh 2013-03-14 11:33:10 +01:00
173f4de7a1 Change the group of ast to users instead of others
Change-Id: I3c92554f209fa39597e55a6b407dddd447111f2f
2013-03-14 11:32:09 +01:00
fc39546350 Adapt ARM print macro to match used types
Change-Id: I987c669dce30d97ff67e33a50106a07163f7d7f1
2013-03-13 13:51:56 +01:00
Ben Gras
718a9ef472 VM: pagetable.c: harmonize x86/ARM findhole() code
ARM needs to be able to find N consecutive free slots; use same
code for x86.

Change-Id: Ic79677961c8adfca2aeb5385962942ae0d76867c
2013-03-13 12:09:32 +00:00
Ben Gras
90d777f053 VM: pagequeue data structure
. data structure that automatically keeps a set
	  of pages in reserve, to replace sparepages and
	  possibly re-used in the future for similar situations,
	  e.g. if in-filesystem-cache block eviction is
	  implemented and FS asks for a new block

Change-Id: I149d46c14b9c8e75df16cb94e08907f008c339a6
2013-03-13 12:09:32 +00:00
a212fd1ba5 Install default users directly
Install /home/ast and /home/bin as part of the system build procedure,
as the setup script is not ran on the arm image.

/home/bin is needed for successful completion of our test suite.

This patch does not change the setup script, as it is not bothered by
those files/directiories being already there, and may be useful during
reinstallation on intel systems.

Change-Id: I358c881df09223c343442673aa0822937f9ea33c
2013-03-13 10:43:40 +01:00
5180c3cfb9 Installing posix tests in /usr/tests/minix-posix
The goal is to enable anyone to simply run our current test suite.

Change-Id: I27d8856cb82a4be2baa5dc5273526383b7f4fc2c
2013-03-13 10:43:16 +01:00
Thomas Cort
fe7b9c06f9 Importing usr.bin/getopt 2013-03-11 11:31:55 +01:00
Thomas Veerman
24ac5ce3f9 test56: unlink proper test file
Change-Id: I215f0d00b8e077930c4e93d192553eaf0d2a353f
2013-03-08 15:45:53 +00:00
Thomas Veerman
76ddef10da UDS: terminate canonical path string
When you provided a string with junk after the terminating nul to a
UNIX domain socket and used bind(2), the canonical path function would
not properly terminate the new string. This caused VFS to return
ENAMETOOLONG on an otherwise valid path name.

Test case is added to test56.

Change-Id: I883b6be23d9e4ea13c3cee28cbb3726343df037f
2013-03-08 15:42:32 +00:00
08283d6d4d pax: Replace bsdtar.1 by a symlink to tar.1
Change-Id: I4b80080e9420e89525c73f03ed68717fb59c1e40
2013-03-08 14:33:07 +01:00
Kees Jongenburger
149ed6cff5 build:small fixes to arm_sdimage.
* Use the same output directory as was previously the standard.
* Add copying of uEnv and cmdline to the obj directory to allow booting from tftp.
* No longer start qemu at the end of the process.
* Use sudo if the script was called as non root user.

Change-Id: I53143b1ce6633e764d173c3eb883c2efa3e6a5b7
2013-03-08 10:50:57 +01:00
fbd82e76a4 Let the build system manage compilation flags
Do not hardcode warning and optimisation flags, otherwise the
main options (i.e. DBG, CPPFLAGS) will not work as expected.

You can still provide specific default by using DBG?=<value>.

Doing so leaves the opportunity to override the setting from the
commandline, while the default value from the build system is
then ignored for that particular package.

When crosscompiling, and using build.sh, adding -V DBG=<value> has
this same effect as make DBG=<value>.

Change-Id: Ic610e4d33b945acad64571e1431f1814291e2d84
2013-03-08 09:41:49 +01:00
10f4c3fbb1 Reduce differences in libgcc Makefiles for ARM
Change-Id: I1b6b18bce063550907aa6e9ea2061e12b0855de4
2013-03-08 09:41:49 +01:00
ce42c706d2 ASH: Fix clean target.
Also include code generators in the cleaning targets.

Change-Id: Ic1eeece5152f2b13a0357363d5e902b182022fdf
2013-03-08 09:41:49 +01:00
Ben Gras
5acaa0814f kernel, ramdisk: some boot unification
To use the new SD building script, Linux has to be configured with
loop.max_part=15 on the command line (or set at module load time)
to make the loopback device see the partitions.

This commit removes a lot of differences between the ARM and x86
boot ramdisk and rc scripts. It changes the ARM build from running
from ramdisk to requiring a full filesystem on the SD image and
booting into it.

	. ramdisk: remove some arm-only utilities only used for running
	  from the shell
	. remove ARM-only rc.arm, proto.arm.small, ttys and mylogin.sh
	  boot-time ramdisk files
	. change kernel to add "arch" variable so userland knows what
	  we're running on from sysenv
	. make ARM use the regular ramdisk rc file, changed to distinguish
	  i386-only and ARM-only drivers; requires rootdevname to be set
	. change /etc/rc and /usr/etc/rc to start i386-only drivers only on
	  i386 systems
	. change the kernel/arm to have a special case for the memory
	  driver to load it higher so it can be bigger
	. add uEnv.txt, cmdline.txt and a for now highly linux-dependent
	  SD preparation script arm_sdimage.sh to the git repository in
	  releasetools/

Change-Id: I68910ba4e96ee80f7a12b65e48b5d39b43ca6397
2013-03-07 14:29:27 +00:00
b9674650f1 Fix signal handling for services on abort/exit
Change-Id: I970a25ae0dd52f0d928fda376296e7b39e3e17eb
2013-03-07 13:11:31 +01:00
Ben Gras
a9f55a2e46 VFS, FSes: add REQ_PEEK request type
REQ_PEEK behaves just like REQ_READ except that it does not copy
data anywhere, just obtains the blocks from the FS into the cache.

To be used by the future mmap implementation.

Change-Id: I1b56de304f0a7152b69a72c8962d04258adb44f9
2013-03-07 10:57:38 +00:00
Thomas Veerman
1ba514e19c UDS: check connection state better
Select(2)ing on UNIX domain sockets was not working properly because
connection state wasn't properly checked/propagated. So selecting for
a read descriptor and closing the write descriptor on the other end
didn't cause select to return. Similarly, read(2) kept blocking while
it should return an error when the other end closed the socket.

Change-Id: I3f5bb52af1a6b03313d508bf915fc838357ba450
2013-03-07 10:49:21 +00:00
Ben Gras
449ed17833 VM: shared memory pagefault fix
. if there is no memory there, it's not writable; this
	  check bug by the shared memory's writable() method causes
	  pagefaults not to be handled  at all in certain situations,
	  triggering an assert() in pt_writemap()
	. added some assert()s to catch this and similar situations
	  in the future

Change-Id: Ife89bfab4f9a3aa7bf4e33dfb0b13b89dcd5bb94
2013-03-07 10:40:22 +01:00
Antoine Leca
df04d571b1 Spanish keymap with tilde
and several small changes in keymaps, like cleaner
support for extended keypresses (those preceded with E0)
2013-03-06 18:13:46 +01:00
Antoine Leca
211cab38e2 make etcfiles: small fix in Makefile
Keep the MKUNPRIVED=yes stuff with the installation
of master.passwd, i.e. away from make etcfiles
2013-03-06 18:12:29 +01:00
8f3fbf7cc1 Cleanup: Remove minix.bootprog.mk
The build system distinction between "bootprog" and "service" is
meaningless as boot programs are standard services.

As minix.service.mk simply imports minix.bootprog.mk, reduce confusion
by removing minix.bootprog.mk and placing the rules in minix.service.mk.

Change-Id: I4056b1e574bed59a8c890239b41b1a7c7cad63e8
2013-03-06 11:56:56 +01:00
Thomas Veerman
fcdf1f4a55 Kernel: remove compile warnings 2013-03-06 09:20:00 +00:00
Thomas Veerman
49ad4e8888 Spring cleanup
Remove old versions of system calls and system calls that don't have
a libc api interface anymore (dup, dup2, creat).

VFS still contains support for old system call numbers for the new stat
system calls (i.e., 65, 66, 67) to keep supporting old binaries built for
MINIX 3.2.1 (prior to the release).

Change-Id: I721779b58a50c7eeae20669de24658d55d69b25b
2013-03-06 09:56:08 +00:00
Thomas Cort
7b9673cd55 Importing usr.bin/col 2013-03-05 16:44:54 +01:00
Thomas Veerman
e232e0cbf0 Kernel: make shutdown more verbose
Change-Id: Iab5fed4cb617a9dbce164ff81c7dedf408e9fd98
2013-03-04 10:13:50 +00:00
Thomas Veerman
2e723784ff test68: test pipe2 functionality
Change-Id: Idb15ec83983d0b052232c9533f89d637229d19df
2013-02-28 10:08:54 +00:00
Thomas Veerman
9c99b3b3b9 test67: test opening files and sockets with O_CLOEXEC
Change-Id: If71e61f830c6d3b5154368e189baa4f70bd73850
2013-02-28 10:08:54 +00:00
Thomas Veerman
39fad09a94 libc: drop Minix popen and use NetBSD's
Change-Id: I56f253d855671a6e1c8d53c7383107565164ab8d
2013-02-28 10:08:54 +00:00
Thomas Veerman
473547c777 VFS: implement pipe2
Change-Id: Iedc8042dd73a903456b25ba665d12577f5589ca2
2013-02-28 10:08:53 +00:00
Thomas Veerman
fa78dc389f socket: implement SOCK_CLOEXEC and SOCK_NONBLOCK
Change-Id: I3fa36fa999c82a192d402cb4d913bd397e106e53
2013-02-28 10:08:53 +00:00
Thomas Veerman
fd610ba1b0 VFS: add ability to open files O_CLOEXEC
.adjust libc to make use of it (undo __minix diff)

Change-Id: I90a1aa219fcd1b12b6bc60e72176f326eac8184a
2013-02-28 10:08:53 +00:00
David van Moolenbroek
2ea6149f7c sprofalyze: fix profile data parsing 2013-02-27 17:53:27 +00:00
Antoine Leca
be93a3e156 Fix permissions for term(1)
LSC: Small correction, using the group name is not secure in cross-build
     setups, replaced by the numerical gid to ensure proper operation.

Change-Id: I7657b77f29eaa513fe24d8c4e2eb6de9afd53950
2013-02-27 11:35:10 +01:00
46fcb04d36 Simplification in drivers/ramdisk
Periods are allowed in Make variable names, which let us simplify
a bit the Makefile.

Based on a proposition by Antoine LECA

Change-Id: I759d7dc7721905a4775e8ab28e0371e48a443f25
2013-02-27 11:35:01 +01:00
0ca2111817 Removing forgotten, useless, renegade defines
Change-Id: I3ff12b42e2815c8f3d72bb577a58552f3a0dc662
2013-02-27 10:54:04 +01:00
c1bfecc185 Compatibility check for autotools
This add an explicit test on the obsolete _MINIX define, unset it and
replace it with _NETBSD_SOURCE.

This should help compile a lot of packages relying on autotools in pkgsrc.

Change-Id: Ie7da4ed5172f1b9f1f89e7a5d788ec2aed4d2563
2013-02-26 09:44:25 +00:00
f640210005 Removing obsolete _NBSD_LIBC define
Change-Id: Ia6ce84ccdf36cf6f64540b990baaa7d85c53533d
2013-02-26 09:44:24 +00:00
afa4fd56ac Removing obsolete _MINIX_COMPAT define
Change-Id: If1f5901a53bbc454c04ee33ebb469a58f0566df7
2013-02-26 09:44:23 +00:00
813d4c6a36 Removing obsolete _MINIX_SOURCE define
Change-Id: I924d5af294cd5daf17c73f71803f060cea3c3d8b
2013-02-26 09:44:21 +00:00
8e4736f2df Removing obsolete _MINIX define
Change-Id: Id33ac7e973d1c0e249b690fe44a597474fac6076
2013-02-26 09:44:20 +00:00
Ben Gras
f360500351 getdirs.awk: restore regexp to original
Change-Id: I7f9714e1b0e079299c87b036dea8e91ffc701342
2013-02-24 13:50:53 +01:00
Thomas Veerman
e176fa00ef RS: refresh service upon init failure
When a service fails to initialize, RS exits the service. When injecting
faults this is undesired behavior. With this patch, we're going to assume
that when starting services with the -b flag (no binary exponential
offset), we don't want to exit the service but simply restart the
initialization.

Change-Id: Ie8b9c89e16fe4df8a89ec30ec678a216b4ec5fd0
2013-02-22 16:06:25 +00:00
Thomas Veerman
4de18d528b Remove unintentionally commited file
Change-Id: I2e0f66f5d8033e98c4e9e20d60773548af9e8c35
2013-02-22 13:56:25 +00:00
Thomas Veerman
67434e545b fb: use timeout instead of microdelay for restart logo
Change-Id: I1cb192aae502ed917e757cf17f67a9a355d0059a
2013-02-22 13:08:21 +00:00
Thomas Veerman
2b793e4945 libsys: refactor frclock api
Make the frclock functions similar to the tsc utility functions. This
way, we can call frclock functions from the framebuffer driver which
will use frclock on ARM and tsc on X86.

Also, frclock_64_to_micros computed seconds, not microseconds

Change-Id: I6718ae0fb7db050794f6f032205923e1a32dc1ac
2013-02-22 13:08:21 +00:00
Ben Gras
4d09b8408a compile & install the unixbenchmark netbsd style
for convenient crosscompiling & running.

Change-Id: I7dfcea109c00e1457f9de9b2e6437fe6cf925ba7
2013-02-22 12:49:56 +01:00
Thomas Veerman
e104b46005 test set: use clear 2013-02-21 10:29:09 +00:00
Thomas Veerman
2b90964e33 VFS: don't garbage collect if file is already closed 2013-02-21 10:29:08 +00:00
Thomas Veerman
cfcce207c1 VFS: prevent unmapping drivers that don't support reopening
libchardriver does not support DEV_REOPEN and will return ERESTART
when you do try it. This made VFS unhappy and concluded erroneously
that the driver was EDEADEPT.
2013-02-21 10:29:08 +00:00
Thomas Veerman
ba49a155b5 fb: introduce framebuffer support to Minix
This patch introduces a framebuffer to Minix. It's written for the ARM
port of Minix, but has an architectural split that separates the
hardware dependent part from the non-hardware dependent part. Futhermore,
this driver was developed using a screen that has a native resolution of
1024x600 pixels and having lack of support for obtaining EDID from the
screen. Consequently, it uses a hardcoded resolution of 1024x600.

The driver uses an interface based on the Linux ioctl API, but supports
only a very limited subset.
2013-02-21 10:29:08 +00:00
Ben Gras
2aa82a9c7b ARM: kernel: fix sanity check for copying
. phys_copy() (taken from memcpy) can legitimately
	  cause pagefaults below the source/dest address due
	  to word-alignment

Change-Id: Ibee8f069781d16caea671246c021fb17a2a892b1
2013-02-20 20:34:40 +01:00
Ben Gras
7a07b58aa8 test66: float smoke test, floating point fixes (arm)
Change-Id: Idd209ab6f341fbfb6b2dca77290ff440695bc2c1
2013-02-20 12:29:37 +00:00
Kees Jongenburger
d47f512a13 kernel:handle improper svc calls gracefully.
Change-Id: Id0f694dd2a8c5981900601fcdb2112ee266d0d76
2013-02-19 17:02:29 +01:00
Ben Gras
b18224051a kernel: more stack for vm 2013-02-19 13:53:56 +01:00
e4fa9802cb ARM: Enable caches
First round, some more optimizations are possible and should be
activated.

Change-Id: I3b7dee7c82fbffd823a08bec1c5d5ebcf769f92f
2013-02-18 09:08:26 +01:00
b36292e232 ARM: Fix interrupt management
Interrupts where not correctly masked while in kernel, which
breaks one of the current main assumptions.

Also remove some duplication on ARM asm files, and add a function
to check the status of ARM irqs (not compiled by default)

Change-Id: I3c25d2b388f93fd8fe423998b94b3c4f140ba831
2013-02-18 09:07:55 +01:00
Kees Jongenburger
eff37b8a8b kernel:enable trace on arm.
Change-Id: Iabe6dfd758e8f1cdb4a18e2f2ab8f8ca988f3c86
2013-02-17 08:40:38 +01:00
David van Moolenbroek
16440d9b8f installboot: allow installation into disk
Previously, installboot would require that the given target device is
a partition. This is not strictly necessary: MINIX3 can also be
installed (manually) into one or more primary partitions, requiring
that the installboot target be the entire disk. With this patch,
specifying a disk as target is now allowed, as long as the -f (force)
option is given.
2013-02-16 22:58:53 +01:00
c3ae1bdfcd Switch to disable bin. exp. wait time in RS 2013-02-16 19:35:19 +01:00
Kees Jongenburger
f240e1eaf5 vm:Display boot process name upon failure to load or execute.
Change-Id: I80fdaca09ae255622083b16dee72715f009dc0ee
2013-02-16 11:20:45 +01:00
Ben Gras
ea79fdc29d packages.install: remove a few, too big to fit.
. the world will look better with base & packages dynamically
	  linked.

Change-Id: Ifce80ad7002b530e583422d23c2ab6f4dd7841e0
2013-02-15 12:34:48 +01:00
Thomas Cort
8d5bf08308 kernel: correct typo in clock.c
Change-Id: Iae7f482268809c5675d023d10104f49e5bd65484
2013-02-15 12:10:56 +01:00
1895 changed files with 516226 additions and 35255 deletions

View File

@@ -141,7 +141,11 @@ _SUBDIR= tools lib .WAIT include gnu external crypto/external bin games
_SUBDIR+= libexec sbin usr.bin
_SUBDIR+= commands man
_SUBDIR+= common drivers kernel servers
_SUBDIR+= usr.sbin share rescue sys etc tests compat .WAIT distrib regress
_SUBDIR+= usr.sbin share rescue sys etc test compat .WAIT distrib regress
.if defined(__MINIX)
_SUBDIR+= benchmarks
.endif
.for dir in ${_SUBDIR}
.if "${dir}" == ".WAIT" \
@@ -168,11 +172,9 @@ afterinstall: .PHONY .MAKE
${MAKEDIRTARGET} man makedb
.endif # !defined(__MINIX)
.endif
.if !defined(__MINIX)
.if (${MKUNPRIVED} != "no" && ${MKINFO} != "no")
${MAKEDIRTARGET} gnu/usr.bin/texinfo/install-info infodir-meta
.endif
.endif # !defined(__MINIX)
.if !defined(NOPOSTINSTALL)
${MAKEDIRTARGET} . postinstall-check
.endif
@@ -293,6 +295,7 @@ build: .PHONY .MAKE
.endfor
${MAKEDIRTARGET} etc install-etc-release
.if defined(__MINIX)
${MAKEDIRTARGET} etc install-etc-files-safe DESTDIR=${DESTDIR:U/}
${MAKEDIRTARGET} releasetools do-hdboot
.endif # defined(__MINIX)
@echo "Build started at: ${START_TIME}"

View File

@@ -1,7 +1,5 @@
# Makefile for the benchmarks.
all::
chmod 755 run
SUBDIR=unixbench-5.1.2
all clean::
for b in *bench*; do cd $$b && $(MAKE) $@; done
.include <bsd.subdir.mk>

View File

@@ -1,246 +1,5 @@
##############################################################################
# UnixBench v5.1.1
# Based on The BYTE UNIX Benchmarks - Release 3
# Module: Makefile SID: 3.9 5/15/91 19:30:15
#
##############################################################################
# Bug reports, patches, comments, suggestions should be sent to:
# David C Niemi <niemi@tux.org>
#
# Original Contacts at Byte Magazine:
# Ben Smith or Tom Yager at BYTE Magazine
# bensmith@bytepb.byte.com tyager@bytepb.byte.com
#
##############################################################################
# Modification Log: 7/28/89 cleaned out workload files
# 4/17/90 added routines for installing from shar mess
# 7/23/90 added compile for dhrystone version 2.1
# (this is not part of Run file. still use old)
# removed HZ from everything but dhry.
# HZ is read from the environment, if not
# there, you must define it in this file
# 10/30/90 moved new dhrystone into standard set
# new pgms (dhry included) run for a specified
# time rather than specified number of loops
# 4/5/91 cleaned out files not needed for
# release 3 -- added release 3 files -ben
# 10/22/97 added compiler options for strict ANSI C
# checking for gcc and DEC's cc on
# Digital Unix 4.x (kahn@zk3.dec.com)
# 09/26/07 changes for UnixBench 5.0
# 09/30/07 adding ubgears, GRAPHIC_TESTS switch
# 10/14/07 adding large.txt
##############################################################################
##############################################################################
# CONFIGURATION
##############################################################################
SHELL = /bin/sh
# GRAPHICS TESTS: Uncomment the definition of "GRAPHIC_TESTS" to enable
# the building of the graphics benchmarks. This will require the
# X11 libraries on your system.
#
# Comment the line out to disable these tests.
# GRAPHIC_TESTS = defined
# Set "GL_LIBS" to the libraries needed to link a GL program.
GL_LIBS = -lGL -lXext -lX11
# OPTIMISATION SETTINGS:
## Very generic
OPTON = -O
## For Linux 486/Pentium, GCC 2.7.x and 2.8.x
#OPTON = -O2 -fomit-frame-pointer -fforce-addr -fforce-mem -ffast-math \
# -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2
## For Linux, GCC previous to 2.7.0
#OPTON = -O2 -fomit-frame-pointer -fforce-addr -fforce-mem -ffast-math -m486
#OPTON = -O2 -fomit-frame-pointer -fforce-addr -fforce-mem -ffast-math \
# -m386 -malign-loops=1 -malign-jumps=1 -malign-functions=1
## For Solaris 2, or general-purpose GCC 2.7.x
#OPTON = -O2 -fomit-frame-pointer -fforce-addr -ffast-math -Wall
## For Digital Unix v4.x, with DEC cc v5.x
#OPTON = -O4
#CFLAGS = -DTIME -std1 -verbose -w0
## generic gcc CFLAGS. -DTIME must be included.
CFLAGS += $(CPPFLAGS) -DTIME -DMINIX=1 -D_MINIX=1 -D_POSIX_SOURCE=1
##############################################################################
# END CONFIGURATION
##############################################################################
# local directories
PROGDIR = ./pgms
SRCDIR = ./src
TESTDIR = ./testdir
RESULTDIR = ./results
TMPDIR = ./tmp
# other directories
INCLDIR = /usr/include
LIBDIR = /lib
SCRIPTS = unixbench.logo multi.sh tst.sh index.base
SOURCES = arith.c big.c context1.c \
dummy.c execl.c \
fstime.c hanoi.c \
pipe.c spawn.c \
syscall.c looper.c timeit.c time-polling.c \
dhry_1.c dhry_2.c dhry.h whets.c ubgears.c
TESTS = sort.src cctest.c dc.dat large.txt
# ifdef GRAPHIC_TESTS
# GRAPHIC_BINS = $(PROGDIR)/ubgears
# else
GRAPHIC_BINS =
# endif
# Program binaries.
BINS = $(PROGDIR)/arithoh $(PROGDIR)/register $(PROGDIR)/short \
$(PROGDIR)/int $(PROGDIR)/long $(PROGDIR)/float $(PROGDIR)/double \
$(PROGDIR)/hanoi $(PROGDIR)/syscall $(PROGDIR)/context1 \
$(PROGDIR)/pipe $(PROGDIR)/spawn $(PROGDIR)/execl \
$(PROGDIR)/dhry2 $(PROGDIR)/dhry2reg $(PROGDIR)/looper \
$(PROGDIR)/fstime $(PROGDIR)/whetstone-double $(GRAPHIC_BINS)
## These compile only on some platforms...
# $(PROGDIR)/poll $(PROGDIR)/poll2 $(PROGDIR)/select
# Required non-binary files.
REQD = $(BINS) $(PROGDIR)/unixbench.logo \
$(PROGDIR)/multi.sh $(PROGDIR)/tst.sh $(PROGDIR)/index.base \
$(PROGDIR)/gfx-x11 \
$(TESTDIR)/sort.src $(TESTDIR)/cctest.c $(TESTDIR)/dc.dat \
$(TESTDIR)/large.txt
# ######################### the big ALL ############################
all: distr programs
## Ick!!! What is this about??? How about let's not chmod everything bogusly.
# @chmod 744 * $(SRCDIR)/* $(PROGDIR)/* $(TESTDIR)/* $(DOCDIR)/*
# ####################### a check for Run ######################
check: $(REQD)
make all
# ##############################################################
# distribute the files out to subdirectories if they are in this one
distr:
@echo "Checking distribution of files"
# scripts
@if test ! -d $(PROGDIR) \
; then \
mkdir $(PROGDIR) \
; mv $(SCRIPTS) $(PROGDIR) \
; else \
echo "$(PROGDIR) exists" \
; fi
# C sources
@if test ! -d $(SRCDIR) \
; then \
mkdir $(SRCDIR) \
; mv $(SOURCES) $(SRCDIR) \
; else \
echo "$(SRCDIR) exists" \
; fi
# test data
@if test ! -d $(TESTDIR) \
; then \
mkdir $(TESTDIR) \
; mv $(TESTS) $(TESTDIR) \
; else \
echo "$(TESTDIR) exists" \
; fi
# temporary work directory
@if test ! -d $(TMPDIR) \
; then \
mkdir $(TMPDIR) \
; else \
echo "$(TMPDIR) exists" \
; fi
# directory for results
@if test ! -d $(RESULTDIR) \
; then \
mkdir $(RESULTDIR) \
; else \
echo "$(RESULTDIR) exists" \
; fi
programs: $(BINS)
# Individual programs
$(PROGDIR)/arithoh: $(SRCDIR)/arith.c
$(CC) -o $(PROGDIR)/arithoh ${CFLAGS} ${OPTON} -Darithoh $(SRCDIR)/arith.c
$(PROGDIR)/register: $(SRCDIR)/arith.c
$(CC) -o $(PROGDIR)/register ${CFLAGS} ${OPTON} -Ddatum='register int' $(SRCDIR)/arith.c
$(PROGDIR)/short: $(SRCDIR)/arith.c
$(CC) -o $(PROGDIR)/short ${CFLAGS} ${OPTON} -Ddatum=short $(SRCDIR)/arith.c
$(PROGDIR)/int: $(SRCDIR)/arith.c
$(CC) -o $(PROGDIR)/int ${CFLAGS} ${OPTON} -Ddatum=int $(SRCDIR)/arith.c
$(PROGDIR)/long: $(SRCDIR)/arith.c
$(CC) -o $(PROGDIR)/long ${CFLAGS} ${OPTON} -Ddatum=long $(SRCDIR)/arith.c
$(PROGDIR)/float: $(SRCDIR)/arith.c
$(CC) -o $(PROGDIR)/float ${CFLAGS} ${OPTON} -Ddatum=float $(SRCDIR)/arith.c
$(PROGDIR)/double: $(SRCDIR)/arith.c
$(CC) -o $(PROGDIR)/double ${CFLAGS} ${OPTON} -Ddatum=double $(SRCDIR)/arith.c
$(PROGDIR)/whetstone-double: $(SRCDIR)/whets.c
$(CC) -o $(PROGDIR)/whetstone-double ${CFLAGS} ${OPTON} -DDP -DUNIX -DUNIXBENCH $(SRCDIR)/whets.c -lm
$(PROGDIR)/hanoi: $(SRCDIR)/hanoi.c
$(CC) -o $(PROGDIR)/hanoi ${CFLAGS} ${OPTON} $(SRCDIR)/hanoi.c
$(PROGDIR)/poll: $(SRCDIR)/time-polling.c
$(CC) -DHAS_POLL -DUNIXBENCH -o $(PROGDIR)/poll ${CFLAGS} ${OPTON} $(SRCDIR)/time-polling.c
$(PROGDIR)/poll2: $(SRCDIR)/time-polling.c
$(CC) -DHAS_POLL2 -DUNIXBENCH -o $(PROGDIR)/poll2 ${CFLAGS} ${OPTON} $(SRCDIR)/time-polling.c
$(PROGDIR)/select: $(SRCDIR)/time-polling.c
$(CC) -DHAS_SELECT -DUNIXBENCH -o $(PROGDIR)/select ${CFLAGS} ${OPTON} $(SRCDIR)/time-polling.c
$(PROGDIR)/fstime: $(SRCDIR)/fstime.c
$(CC) -o $(PROGDIR)/fstime ${CFLAGS} ${OPTON} $(SRCDIR)/fstime.c
$(PROGDIR)/syscall: $(SRCDIR)/syscall.c
$(CC) -o $(PROGDIR)/syscall ${CFLAGS} ${OPTON} $(SRCDIR)/syscall.c
$(PROGDIR)/context1: $(SRCDIR)/context1.c
$(CC) -o $(PROGDIR)/context1 ${CFLAGS} ${OPTON} $(SRCDIR)/context1.c
$(PROGDIR)/pipe: $(SRCDIR)/pipe.c
$(CC) -o $(PROGDIR)/pipe ${CFLAGS} ${OPTON} $(SRCDIR)/pipe.c
$(PROGDIR)/spawn: $(SRCDIR)/spawn.c
$(CC) -o $(PROGDIR)/spawn ${CFLAGS} ${OPTON} $(SRCDIR)/spawn.c
$(PROGDIR)/execl: $(SRCDIR)/execl.c $(SRCDIR)/big.c
$(CC) -o $(PROGDIR)/execl ${CFLAGS} ${OPTON} $(SRCDIR)/execl.c
$(PROGDIR)/dhry2: $(SRCDIR)/dhry_1.c $(SRCDIR)/dhry_2.c $(SRCDIR)/dhry.h
cd $(SRCDIR); $(CC) -c ${CFLAGS} -DHZ=${HZ} ${OPTON} dhry_1.c
cd $(SRCDIR); $(CC) -c ${CFLAGS} -DHZ=${HZ} ${OPTON} dhry_2.c
$(CC) -o $(PROGDIR)/dhry2 ${CFLAGS} ${OPTON} $(SRCDIR)/dhry_1.o $(SRCDIR)/dhry_2.o
cd $(SRCDIR); rm -f dhry_1.o dhry_2.o
$(PROGDIR)/dhry2reg: $(SRCDIR)/dhry_1.c $(SRCDIR)/dhry_2.c $(SRCDIR)/dhry.h
cd $(SRCDIR); $(CC) -c ${CFLAGS} -DREG=register -DHZ=${HZ} ${OPTON} dhry_1.c
cd $(SRCDIR); $(CC) -c ${CFLAGS} -DREG=register -DHZ=${HZ} ${OPTON} dhry_2.c
$(CC) -o $(PROGDIR)/dhry2reg ${CFLAGS} ${OPTON} $(SRCDIR)/dhry_1.o $(SRCDIR)/dhry_2.o
cd $(SRCDIR); rm -f dhry_1.o dhry_2.o
$(PROGDIR)/looper: $(SRCDIR)/looper.c
$(CC) -o $(PROGDIR)/looper ${CFLAGS} ${OPTON} $(SRCDIR)/looper.c
$(PROGDIR)/ubgears: $(SRCDIR)/ubgears.c
$(CC) -o $(PROGDIR)/ubgears ${CFLAGS} ${OPTON} $(SRCDIR)/ubgears.c $(GL_LIBS)
# Run the benchmarks and create the reports
run:
sh ./Run
clean:
rm -f $(BINS) core *~ */*~
spotless: clean
rm -f $(RESULTDIR)/* $(TMPDIR)/*
## END ##
SCRIPTS=Run
SUBDIR=pgms testdir run.sh
.include "Makefile.inc"
.include <bsd.prog.mk>
.include <bsd.subdir.mk>

View File

@@ -0,0 +1 @@
BINDIR=/usr/benchmarks/unixbench

View File

@@ -796,6 +796,7 @@ sub preChecks {
$ENV{'LANG'} = $language;
# Check that the required files are in the proper places.
if (!$ENV{MINIX}) {
system("make check");
if ($? != 0) {
system("make all");
@@ -803,6 +804,7 @@ sub preChecks {
abortRun("\"make all\" failed");
}
}
}
# Create a script to kill this run.
system("echo \"kill -9 $$\" > \"${TMPDIR}/kill_run\"");

View File

@@ -0,0 +1,6 @@
SUBDIR=arithoh register short int long float double whetstone-double hanoi \
poll select fstime syscall context1 pipe spawn execl dhry2 \
dhry2reg looper multi.sh tst.sh unixbench.logo index.base # ubgears poll2BB
.include <bsd.subdir.mk>

View File

@@ -0,0 +1,5 @@
CPPFLAGS+=-DTIME -DMINIX=1 -I../../src/
HZ=60
BINDIR=/usr/benchmarks/unixbench/pgms
.PATH: ${.CURDIR}/../../src

View File

@@ -0,0 +1,7 @@
PROG=arithoh
SRCS=arith.c
CPPFLAGS+=-Darithoh
MAN=
.include <bsd.prog.mk>

View File

@@ -0,0 +1,5 @@
PROG=context1
MAN=
.include <bsd.prog.mk>

View File

@@ -0,0 +1,7 @@
PROG=dhry2
SRCS=dhry_1.c dhry_2.c
CPPFLAGS+=-DHZ=${HZ}
MAN=
.include <bsd.prog.mk>

View File

@@ -0,0 +1,7 @@
PROG=dhry2reg
SRCS=dhry_1.c dhry_2.c
CPPFLAGS+=-DHZ=${HZ} -DREG=register
MAN=
.include <bsd.prog.mk>

View File

@@ -0,0 +1,7 @@
PROG=double
SRCS=arith.c
CPPFLAGS=-Ddatum='double'
MAN=
.include <bsd.prog.mk>

View File

@@ -1,4 +1,5 @@
PROG= head
PROG=execl
MAN=
.include <bsd.prog.mk>

View File

@@ -0,0 +1,7 @@
PROG=float
SRCS=arith.c
CPPFLAGS=-Ddatum='float'
MAN=
.include <bsd.prog.mk>

View File

@@ -1,4 +1,5 @@
PROG= banner
PROG=fstime
MAN=
.include <bsd.prog.mk>

View File

@@ -1,4 +1,5 @@
PROG= rdate
PROG=hanoi
MAN=
.include <bsd.prog.mk>

View File

@@ -0,0 +1,3 @@
SCRIPTS=index.base
SCRIPTSNAME=index.base
.include <bsd.prog.mk>

View File

@@ -0,0 +1,7 @@
PROG=int
SRCS=arith.c
CPPFLAGS=-Ddatum='int'
MAN=
.include <bsd.prog.mk>

View File

@@ -0,0 +1,7 @@
PROG=long
SRCS=arith.c
CPPFLAGS=-Ddatum='long'
MAN=
.include <bsd.prog.mk>

View File

@@ -0,0 +1,5 @@
PROG=looper
MAN=
.include <bsd.prog.mk>

View File

@@ -0,0 +1,3 @@
SCRIPTS=multi.sh
SCRIPTSNAME=multi.sh
.include <bsd.prog.mk>

View File

@@ -1,4 +1,5 @@
PROG= yes
PROG=pipe
MAN=
.include <bsd.prog.mk>

View File

@@ -0,0 +1,7 @@
PROG=poll
SRCS=time-polling.c
CPPFLAGS+=-DHAS_POLL -DUNIXBENCH
MAN=
.include <bsd.prog.mk>

View File

@@ -0,0 +1,7 @@
PROG=poll2
SRCS=time-polling.c
CPPFLAGS+=-DHAS_POLL2 -DUNIXBENCH
MAN=
.include <bsd.prog.mk>

View File

@@ -0,0 +1,7 @@
PROG=register
SRCS=arith.c
CPPFLAGS=-Ddatum='register int'
MAN=
.include <bsd.prog.mk>

View File

@@ -0,0 +1,7 @@
PROG=select
SRCS=time-polling.c
CPPFLAGS+=-DHAS_SELECT -DUNIXBENCH
MAN=
.include <bsd.prog.mk>

View File

@@ -0,0 +1,7 @@
PROG=short
SRCS=arith.c
CPPFLAGS=-Ddatum='short'
MAN=
.include <bsd.prog.mk>

View File

@@ -1,4 +1,5 @@
PROG= who
PROG=spawn
MAN=
.include <bsd.prog.mk>

View File

@@ -0,0 +1,5 @@
PROG=syscall
MAN=
.include <bsd.prog.mk>

View File

@@ -0,0 +1,3 @@
SCRIPTS=tst.sh
SCRIPTSNAME=tst.sh
.include <bsd.prog.mk>

View File

@@ -0,0 +1,5 @@
PROG=ubgears
MAN=
.include <bsd.prog.mk>

View File

@@ -0,0 +1,3 @@
SCRIPTS=unixbench.logo
SCRIPTSNAME=unixbench.logo
.include <bsd.prog.mk>

View File

@@ -0,0 +1,8 @@
PROG=whetstone-double
SRCS=whets.c
CPPFLAGS+= -DDP -DUNIX -DUNIXBENCH
LDADD+=-lm
MAN=
.include <bsd.prog.mk>

View File

@@ -0,0 +1,3 @@
SCRIPTS=run.sh
SCRIPTSNAME=run.sh
.include <bsd.prog.mk>

View File

@@ -581,7 +581,7 @@ void dumpwork(void)
void fatal(char *s)
{
int i;
fprintf(stderr, s);
fprintf(stderr, "%s", s);
fflush(stderr);
perror("Reason?");
fflush(stderr);

View File

@@ -53,8 +53,6 @@ char SCCSid[] = "@(#) @(#)fstime.c:3.5 -- 5/15/91 19:30:19";
#ifndef MINIX
extern void sync(void);
#else
extern int sync(void);
#endif
int w_test(int timeSecs);

View File

@@ -62,6 +62,9 @@
#ifdef HAS_POLL2
# include <linux/poll2.h>
#endif
#ifdef HAS_SELECT
# include <sys/select.h>
#endif
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
@@ -80,6 +83,7 @@
typedef int flag;
#ifndef HAS_POLL
/*
static inline int find_first_set_bit (CONST void *array, int size)
*/
@@ -143,6 +147,7 @@ static int find_next_set_bit (CONST void *array, int size, int offset)
index += ul_size - offset;
return (find_first_set_bit (++ul_array, size - index) + index);
} /* End Function find_next_set_bit */
#endif
struct callback_struct

View File

@@ -0,0 +1,2 @@
SUBDIR=cctest.c dc.dat large.txt sort.src
.include <bsd.subdir.mk>

View File

@@ -0,0 +1 @@
BINDIR=/usr/benchmarks/unixbench/testdir

View File

@@ -0,0 +1,3 @@
SCRIPTS=cctest.c
SCRIPTSNAME=cctest.c
.include <bsd.prog.mk>

View File

@@ -0,0 +1,3 @@
SCRIPTS=dc.dat
SCRIPTSNAME=dc.dat
.include <bsd.prog.mk>

View File

@@ -0,0 +1,3 @@
SCRIPTS=large.txt
SCRIPTSNAME=large.txt
.include <bsd.prog.mk>

View File

@@ -0,0 +1,3 @@
SCRIPTS=sort.src
SCRIPTSNAME=sort.src
.include <bsd.prog.mk>

View File

@@ -1,7 +1,7 @@
# $NetBSD: Makefile,v 1.22 2007/12/31 15:31:24 ad Exp $
# @(#)Makefile 8.1 (Berkeley) 5/31/93
SUBDIR= cat date echo ed expr kill ln ls \
SUBDIR= cat date echo ed expr kill ksh ln ls \
mkdir pax pwd rm rmdir sync test
.include <bsd.subdir.mk>

50
bin/ksh/Makefile Normal file
View File

@@ -0,0 +1,50 @@
# $NetBSD: Makefile,v 1.30 2011/10/16 17:12:11 joerg Exp $
WARNS=3
.include <bsd.own.mk>
CPPFLAGS+= -I.
PROG= ksh
SRCS= alloc.c c_ksh.c c_sh.c c_test.c c_ulimit.c edit.c emacs.c \
eval.c exec.c expr.c history.c io.c jobs.c lex.c mail.c \
main.c misc.c path.c shf.c sigact.c syn.c table.c trap.c \
tree.c tty.c var.c version.c vi.c
DPSRCS= emacs.out siglist.out
.if (${MKMAN} != "no")
DPSRCS+=ksh.1
.endif
# needs tbl for the man page.
USETBL=
# Environment for scripts executed during build.
SCRIPT_ENV= \
AWK=${TOOL_AWK:Q} \
SED=${TOOL_SED:Q}
CLEANFILES+= siglist.out siglist.out.tmp
# two steps to prevent the creation of a bogus siglist.out
siglist.out: config.h sh.h siglist.in siglist.sh
${_MKTARGET_CREATE}
${SCRIPT_ENV} \
${HOST_SH} $(.CURDIR)/siglist.sh "$(CC) -E $(CPPFLAGS) $(DEFS) -I. -I$(.CURDIR)" < $(.CURDIR)/siglist.in > siglist.out.tmp \
&& mv siglist.out.tmp siglist.out
# two steps to prevent the creation of a bogus emacs.out
CLEANFILES+= emacs.out emacs.out.tmp
emacs.out: emacs.c
${_MKTARGET_CREATE}
${SCRIPT_ENV} \
${HOST_SH} $(.CURDIR)/emacs-gen.sh $(.CURDIR)/emacs.c > emacs.out.tmp \
&& mv emacs.out.tmp emacs.out
CLEANFILES+= ksh.1 ksh.1.tmp
ksh.1: ksh.Man mkman
${_MKTARGET_CREATE}
${SCRIPT_ENV} \
${HOST_SH} $(.CURDIR)/mkman ksh $(.CURDIR)/ksh.Man >ksh.1.tmp \
&& mv ksh.1.tmp ksh.1
.include <bsd.prog.mk>

127
bin/ksh/alloc.c Normal file
View File

@@ -0,0 +1,127 @@
/* $NetBSD: alloc.c,v 1.10 2007/12/12 22:55:42 lukem Exp $ */
/*
* Copyright (c) 2002 Marc Espie.
*
* 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 OPENBSD PROJECT 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 OPENBSD
* PROJECT 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.
*/
/*
* area-based allocation built on malloc/free
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: alloc.c,v 1.10 2007/12/12 22:55:42 lukem Exp $");
#include "sh.h"
struct link {
struct link *prev;
struct link *next;
};
Area *
ainit(Area *ap)
{
ap->freelist = NULL;
return ap;
}
void
afreeall(Area *ap)
{
struct link *l, *l2;
for (l = ap->freelist; l != NULL; l = l2) {
l2 = l->next;
free(l);
}
ap->freelist = NULL;
}
#define L2P(l) ( (void *)(((char *)(l)) + sizeof(struct link)) )
#define P2L(p) ( (struct link *)(((char *)(p)) - sizeof(struct link)) )
/* coverity[+alloc] */
void *
alloc(size_t size, Area *ap)
{
struct link *l;
l = malloc(sizeof(struct link) + size);
if (l == NULL)
internal_errorf(1, "unable to allocate memory");
l->next = ap->freelist;
l->prev = NULL;
if (ap->freelist)
ap->freelist->prev = l;
ap->freelist = l;
return L2P(l);
}
/* coverity[+alloc] */
/* coverity[+free : arg-0] */
void *
aresize(void *ptr, size_t size, Area *ap)
{
struct link *l, *l2, *lprev, *lnext;
if (ptr == NULL)
return alloc(size, ap);
l = P2L(ptr);
lprev = l->prev;
lnext = l->next;
l2 = realloc(l, sizeof(struct link) + size);
if (l2 == NULL)
internal_errorf(1, "unable to allocate memory");
if (lprev)
lprev->next = l2;
else
ap->freelist = l2;
if (lnext)
lnext->prev = l2;
return L2P(l2);
}
/* coverity[+free : arg-0] */
void
afree(void *ptr, Area *ap)
{
struct link *l;
if (!ptr)
return;
l = P2L(ptr);
if (l->prev)
l->prev->next = l->next;
else
ap->freelist = l->next;
if (l->next)
l->next->prev = l->prev;
free(l);
}

1490
bin/ksh/c_ksh.c Normal file

File diff suppressed because it is too large Load Diff

917
bin/ksh/c_sh.c Normal file
View File

@@ -0,0 +1,917 @@
/* $NetBSD: c_sh.c,v 1.14 2011/08/31 16:24:54 plunky Exp $ */
/*
* built-in Bourne commands
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: c_sh.c,v 1.14 2011/08/31 16:24:54 plunky Exp $");
#endif
#include "sh.h"
#include "ksh_stat.h" /* umask() */
#include "ksh_time.h"
#include "ksh_times.h"
static char *clocktos ARGS((clock_t t));
/* :, false and true */
int
c_label(wp)
char **wp;
{
return wp[0][0] == 'f' ? 1 : 0;
}
int
c_shift(wp)
char **wp;
{
register struct block *l = e->loc;
register int n;
long val;
char *arg;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
return 1;
arg = wp[builtin_opt.optind];
if (arg) {
evaluate(arg, &val, KSH_UNWIND_ERROR);
n = val;
} else
n = 1;
if (n < 0) {
bi_errorf("%s: bad number", arg);
return (1);
}
if (l->argc < n) {
bi_errorf("nothing to shift");
return (1);
}
l->argv[n] = l->argv[0];
l->argv += n;
l->argc -= n;
return 0;
}
int
c_umask(wp)
char **wp;
{
register int i;
register char *cp;
int symbolic = 0;
int old_umask;
int optc;
while ((optc = ksh_getopt(wp, &builtin_opt, "S")) != EOF)
switch (optc) {
case 'S':
symbolic = 1;
break;
case '?':
return 1;
}
cp = wp[builtin_opt.optind];
if (cp == NULL) {
old_umask = umask(0);
umask(old_umask);
if (symbolic) {
char buf[18];
int j;
old_umask = ~old_umask;
cp = buf;
for (i = 0; i < 3; i++) {
*cp++ = "ugo"[i];
*cp++ = '=';
for (j = 0; j < 3; j++)
if (old_umask & (1 << (8 - (3*i + j))))
*cp++ = "rwx"[j];
*cp++ = ',';
}
cp[-1] = '\0';
shprintf("%s\n", buf);
} else
shprintf("%#3.3o\n", old_umask);
} else {
int new_umask;
if (digit(*cp)) {
for (new_umask = 0; *cp >= '0' && *cp <= '7'; cp++)
new_umask = new_umask * 8 + (*cp - '0');
if (*cp) {
bi_errorf("bad number");
return 1;
}
} else {
/* symbolic format */
int positions, new_val;
char op;
old_umask = umask(0);
umask(old_umask); /* in case of error */
old_umask = ~old_umask;
new_umask = old_umask;
positions = 0;
while (*cp) {
while (*cp && strchr("augo", *cp))
switch (*cp++) {
case 'a': positions |= 0111; break;
case 'u': positions |= 0100; break;
case 'g': positions |= 0010; break;
case 'o': positions |= 0001; break;
}
if (!positions)
positions = 0111; /* default is a */
if (!strchr("=+-", op = *cp))
break;
cp++;
new_val = 0;
while (*cp && strchr("rwxugoXs", *cp))
switch (*cp++) {
case 'r': new_val |= 04; break;
case 'w': new_val |= 02; break;
case 'x': new_val |= 01; break;
case 'u': new_val |= old_umask >> 6;
break;
case 'g': new_val |= old_umask >> 3;
break;
case 'o': new_val |= old_umask >> 0;
break;
case 'X': if (old_umask & 0111)
new_val |= 01;
break;
case 's': /* ignored */
break;
}
new_val = (new_val & 07) * positions;
switch (op) {
case '-':
new_umask &= ~new_val;
break;
case '=':
new_umask = new_val
| (new_umask & ~(positions * 07));
break;
case '+':
new_umask |= new_val;
}
if (*cp == ',') {
positions = 0;
cp++;
} else if (!strchr("=+-", *cp))
break;
}
if (*cp) {
bi_errorf("bad mask");
return 1;
}
new_umask = ~new_umask;
}
umask(new_umask);
}
return 0;
}
int
c_dot(wp)
char **wp;
{
char *file, *cp;
char **argv;
int argc;
int i;
int err;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
return 1;
if ((cp = wp[builtin_opt.optind]) == NULL)
return 0;
file = search(cp, path, R_OK, &err);
if (file == NULL) {
bi_errorf("%s: %s", cp, err ? strerror(err) : "not found");
return 1;
}
/* Set positional parameters? */
if (wp[builtin_opt.optind + 1]) {
argv = wp + builtin_opt.optind;
argv[0] = e->loc->argv[0]; /* preserve $0 */
for (argc = 0; argv[argc + 1]; argc++)
;
} else {
argc = 0;
argv = (char **) 0;
}
i = include(file, argc, argv, 0);
if (i < 0) { /* should not happen */
bi_errorf("%s: %s", cp, strerror(errno));
return 1;
}
return i;
}
int
c_wait(wp)
char **wp;
{
int UNINITIALIZED(rv);
int sig;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
return 1;
wp += builtin_opt.optind;
if (*wp == (char *) 0) {
while (waitfor((char *) 0, &sig) >= 0)
;
rv = sig;
} else {
for (; *wp; wp++)
rv = waitfor(*wp, &sig);
if (rv < 0)
rv = sig ? sig : 127; /* magic exit code: bad job-id */
}
return rv;
}
int
c_read(wp)
char **wp;
{
register int c = 0;
int expandv = 1, history = 0;
int expanding;
int ecode = 0;
register char *cp;
int fd = 0;
struct shf *shf;
int optc;
const char *emsg;
XString cs, xs;
struct tbl *vp;
char UNINITIALIZED(*xp);
static char REPLY[] = "REPLY";
while ((optc = ksh_getopt(wp, &builtin_opt, "prsu,")) != EOF)
switch (optc) {
#ifdef KSH
case 'p':
if ((fd = coproc_getfd(R_OK, &emsg)) < 0) {
bi_errorf("-p: %s", emsg);
return 1;
}
break;
#endif /* KSH */
case 'r':
expandv = 0;
break;
case 's':
history = 1;
break;
case 'u':
if (!*(cp = builtin_opt.optarg))
fd = 0;
else if ((fd = check_fd(cp, R_OK, &emsg)) < 0) {
bi_errorf("-u: %s: %s", cp, emsg);
return 1;
}
break;
case '?':
return 1;
}
wp += builtin_opt.optind;
if (*wp == NULL)
*--wp = REPLY;
/* Since we can't necessarily seek backwards on non-regular files,
* don't buffer them so we can't read too much.
*/
shf = shf_reopen(fd, SHF_RD | SHF_INTERRUPT | can_seek(fd), shl_spare);
if ((cp = strchr(*wp, '?')) != NULL) {
*cp = 0;
if (isatty(fd)) {
/* at&t ksh says it prints prompt on fd if it's open
* for writing and is a tty, but it doesn't do it
* (it also doesn't check the interactive flag,
* as is indicated in the Kornshell book).
*/
shellf("%s", cp+1);
}
}
#ifdef KSH
/* If we are reading from the co-process for the first time,
* make sure the other side of the pipe is closed first. This allows
* the detection of eof.
*
* This is not compatible with at&t ksh... the fd is kept so another
* coproc can be started with same output, however, this means eof
* can't be detected... This is why it is closed here.
* If this call is removed, remove the eof check below, too.
* coproc_readw_close(fd);
*/
#endif /* KSH */
if (history)
Xinit(xs, xp, 128, ATEMP);
expanding = 0;
Xinit(cs, cp, 128, ATEMP);
for (; *wp != NULL; wp++) {
for (cp = Xstring(cs, cp); ; ) {
if (c == '\n' || c == EOF)
break;
while (1) {
c = shf_getc(shf);
if (c == '\0'
#ifdef OS2
|| c == '\r'
#endif /* OS2 */
)
continue;
if (c == EOF && shf_error(shf)
&& shf_errno(shf) == EINTR)
{
/* Was the offending signal one that
* would normally kill a process?
* If so, pretend the read was killed.
*/
ecode = fatal_trap_check();
/* non fatal (eg, CHLD), carry on */
if (!ecode) {
shf_clearerr(shf);
continue;
}
}
break;
}
if (history) {
Xcheck(xs, xp);
Xput(xs, xp, c);
}
Xcheck(cs, cp);
if (expanding) {
expanding = 0;
if (c == '\n') {
c = 0;
if (Flag(FTALKING_I) && isatty(fd)) {
/* set prompt in case this is
* called from .profile or $ENV
*/
set_prompt(PS2, (Source *) 0);
pprompt(prompt, 0);
}
} else if (c != EOF)
Xput(cs, cp, c);
continue;
}
if (expandv && c == '\\') {
expanding = 1;
continue;
}
if (c == '\n' || c == EOF)
break;
if (ctype(c, C_IFS)) {
if (Xlength(cs, cp) == 0 && ctype(c, C_IFSWS))
continue;
if (wp[1])
break;
}
Xput(cs, cp, c);
}
/* strip trailing IFS white space from last variable */
if (!wp[1])
while (Xlength(cs, cp) && ctype(cp[-1], C_IFS)
&& ctype(cp[-1], C_IFSWS))
cp--;
Xput(cs, cp, '\0');
vp = global(*wp);
/* Must be done before setting export. */
if (vp->flag & RDONLY) {
shf_flush(shf);
bi_errorf("%s is read only", *wp);
return 1;
}
if (Flag(FEXPORT))
typeset(*wp, EXPORT, 0, 0, 0);
if (!setstr(vp, Xstring(cs, cp), KSH_RETURN_ERROR)) {
shf_flush(shf);
return 1;
}
}
shf_flush(shf);
if (history) {
Xput(xs, xp, '\0');
source->line++;
histsave(source->line, Xstring(xs, xp), 1);
Xfree(xs, xp);
}
#ifdef KSH
/* if this is the co-process fd, close the file descriptor
* (can get eof if and only if all processes are have died, ie,
* coproc.njobs is 0 and the pipe is closed).
*/
if (c == EOF && !ecode)
coproc_read_close(fd);
#endif /* KSH */
return ecode ? ecode : c == EOF;
}
int
c_eval(wp)
char **wp;
{
register struct source *s;
int rv;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
return 1;
s = pushs(SWORDS, ATEMP);
s->u.strv = wp + builtin_opt.optind;
if (!Flag(FPOSIX)) {
/*
* Handle case where the command is empty due to failed
* command substitution, eg, eval "$(false)".
* In this case, shell() will not set/change exstat (because
* compiled tree is empty), so will use this value.
* subst_exstat is cleared in execute(), so should be 0 if
* there were no substitutions.
*
* A strict reading of POSIX says we don't do this (though
* it is traditionally done). [from 1003.2-1992]
* 3.9.1: Simple Commands
* ... If there is a command name, execution shall
* continue as described in 3.9.1.1. If there
* is no command name, but the command contained a command
* substitution, the command shall complete with the exit
* status of the last command substitution
* 3.9.1.1: Command Search and Execution
* ...(1)...(a) If the command name matches the name of
* a special built-in utility, that special built-in
* utility shall be invoked.
* 3.14.5: Eval
* ... If there are no arguments, or only null arguments,
* eval shall return an exit status of zero.
*/
exstat = subst_exstat;
}
rv = shell(s, FALSE);
afree(s, ATEMP);
return rv;
}
int
c_trap(wp)
char **wp;
{
int i;
char *s;
register Trap *p;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
return 1;
wp += builtin_opt.optind;
if (*wp == NULL) {
int anydfl = 0;
for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) {
if (p->trap == NULL)
anydfl = 1;
else {
shprintf("trap -- ");
print_value_quoted(p->trap);
shprintf(" %s\n", p->name);
}
}
#if 0 /* this is ugly and not clear POSIX needs it */
/* POSIX may need this so output of trap can be saved and
* used to restore trap conditions
*/
if (anydfl) {
shprintf("trap -- -");
for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
if (p->trap == NULL && p->name)
shprintf(" %s", p->name);
shprintf(newline);
}
#endif
return 0;
}
/*
* Use case sensitive lookup for first arg so the
* command 'exit' isn't confused with the pseudo-signal
* 'EXIT'.
*/
s = (gettrap(*wp, FALSE) == NULL) ? *wp++ : NULL; /* get command */
if (s != NULL && s[0] == '-' && s[1] == '\0')
s = NULL;
/* set/clear traps */
while (*wp != NULL) {
p = gettrap(*wp++, TRUE);
if (p == NULL) {
bi_errorf("bad signal %s", wp[-1]);
return 1;
}
settrap(p, s);
}
return 0;
}
int
c_exitreturn(wp)
char **wp;
{
int how = LEXIT;
int n;
char *arg;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
return 1;
arg = wp[builtin_opt.optind];
if (arg) {
if (!getn(arg, &n)) {
exstat = 1;
warningf(TRUE, "%s: bad number", arg);
} else
exstat = n;
}
if (wp[0][0] == 'r') { /* return */
struct env *ep;
/* need to tell if this is exit or return so trap exit will
* work right (POSIX)
*/
for (ep = e; ep; ep = ep->oenv)
if (STOP_RETURN(ep->type)) {
how = LRETURN;
break;
}
}
if (how == LEXIT && !really_exit && j_stopped_running()) {
really_exit = 1;
how = LSHELL;
}
quitenv(); /* get rid of any i/o redirections */
unwind(how);
/*NOTREACHED*/
return 0;
}
int
c_brkcont(wp)
char **wp;
{
int n, quit;
struct env *ep, *last_ep = (struct env *) 0;
char *arg;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
return 1;
arg = wp[builtin_opt.optind];
if (!arg)
n = 1;
else if (!bi_getn(arg, &n))
return 1;
quit = n;
if (quit <= 0) {
/* at&t ksh does this for non-interactive shells only - weird */
bi_errorf("%s: bad value", arg);
return 1;
}
/* Stop at E_NONE, E_PARSE, E_FUNC, or E_INCL */
for (ep = e; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv)
if (ep->type == E_LOOP) {
if (--quit == 0)
break;
ep->flags |= EF_BRKCONT_PASS;
last_ep = ep;
}
if (quit) {
/* at&t ksh doesn't print a message - just does what it
* can. We print a message 'cause it helps in debugging
* scripts, but don't generate an error (ie, keep going).
*/
if (n == quit) {
warningf(TRUE, "%s: cannot %s", wp[0], wp[0]);
return 0;
}
/* POSIX says if n is too big, the last enclosing loop
* shall be used. Doesn't say to print an error but we
* do anyway 'cause the user messed up.
*/
if (last_ep)
last_ep->flags &= ~EF_BRKCONT_PASS;
warningf(TRUE, "%s: can only %s %d level(s)",
wp[0], wp[0], n - quit);
}
unwind(*wp[0] == 'b' ? LBREAK : LCONTIN);
/*NOTREACHED*/
}
int
c_set(wp)
char **wp;
{
int argi, setargs;
struct block *l = e->loc;
register char **owp = wp;
if (wp[1] == NULL) {
static const char *const args [] = { "set", "-", NULL };
return c_typeset((char **)__UNCONST(args));
}
argi = parse_args(wp, OF_SET, &setargs);
if (argi < 0)
return 1;
/* set $# and $* */
if (setargs) {
owp = wp += argi - 1;
wp[0] = l->argv[0]; /* save $0 */
while (*++wp != NULL)
*wp = str_save(*wp, &l->area);
l->argc = wp - owp - 1;
l->argv = (char **) alloc(sizeofN(char *, l->argc+2), &l->area);
for (wp = l->argv; (*wp++ = *owp++) != NULL; )
;
}
/* POSIX says set exit status is 0, but old scripts that use
* getopt(1), use the construct: set -- `getopt ab:c "$@"`
* which assumes the exit value set will be that of the ``
* (subst_exstat is cleared in execute() so that it will be 0
* if there are no command substitutions).
*/
return Flag(FPOSIX) ? 0 : subst_exstat;
}
int
c_unset(wp)
char **wp;
{
register char *id;
int optc, unset_var = 1;
int ret = 0;
while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != EOF)
switch (optc) {
case 'f':
unset_var = 0;
break;
case 'v':
unset_var = 1;
break;
case '?':
return 1;
}
wp += builtin_opt.optind;
for (; (id = *wp) != NULL; wp++)
if (unset_var) { /* unset variable */
struct tbl *vp = global(id);
if (!(vp->flag & ISSET))
ret = 1;
if ((vp->flag&RDONLY)) {
bi_errorf("%s is read only", vp->name);
return 1;
}
unset(vp, strchr(id, '[') ? 1 : 0);
} else { /* unset function */
if (define(id, NULL))
ret = 1;
}
return ret;
}
int
c_times(wp)
char **wp;
{
struct tms all;
(void) ksh_times(&all);
shprintf("Shell: %8ss user ", clocktos(all.tms_utime));
shprintf("%8ss system\n", clocktos(all.tms_stime));
shprintf("Kids: %8ss user ", clocktos(all.tms_cutime));
shprintf("%8ss system\n", clocktos(all.tms_cstime));
return 0;
}
/*
* time pipeline (really a statement, not a built-in command)
*/
int
timex(t, f)
struct op *t;
int f;
{
#define TF_NOARGS BIT(0)
#define TF_NOREAL BIT(1) /* don't report real time */
#define TF_POSIX BIT(2) /* report in posix format */
int rv = 0;
struct tms t0, t1, tms;
clock_t t0t, t1t = 0;
int tf = 0;
extern clock_t j_usrtime, j_systime; /* computed by j_wait */
char opts[1];
t0t = ksh_times(&t0);
if (t->left) {
/*
* Two ways of getting cpu usage of a command: just use t0
* and t1 (which will get cpu usage from other jobs that
* finish while we are executing t->left), or get the
* cpu usage of t->left. at&t ksh does the former, while
* pdksh tries to do the later (the j_usrtime hack doesn't
* really work as it only counts the last job).
*/
j_usrtime = j_systime = 0;
if (t->left->type == TCOM)
t->left->str = opts;
opts[0] = 0;
rv = execute(t->left, f | XTIME);
tf |= opts[0];
t1t = ksh_times(&t1);
} else
tf = TF_NOARGS;
if (tf & TF_NOARGS) { /* ksh93 - report shell times (shell+kids) */
tf |= TF_NOREAL;
tms.tms_utime = t0.tms_utime + t0.tms_cutime;
tms.tms_stime = t0.tms_stime + t0.tms_cstime;
} else {
tms.tms_utime = t1.tms_utime - t0.tms_utime + j_usrtime;
tms.tms_stime = t1.tms_stime - t0.tms_stime + j_systime;
}
if (!(tf & TF_NOREAL))
shf_fprintf(shl_out,
tf & TF_POSIX ? "real %8s\n" : "%8ss real ",
clocktos(t1t - t0t));
shf_fprintf(shl_out, tf & TF_POSIX ? "user %8s\n" : "%8ss user ",
clocktos(tms.tms_utime));
shf_fprintf(shl_out, tf & TF_POSIX ? "sys %8s\n" : "%8ss system\n",
clocktos(tms.tms_stime));
shf_flush(shl_out);
return rv;
}
void
timex_hook(t, app)
struct op *t;
char ** volatile *app;
{
char **wp = *app;
int optc;
int i, j;
Getopt opt;
ksh_getopt_reset(&opt, 0);
opt.optind = 0; /* start at the start */
while ((optc = ksh_getopt(wp, &opt, ":p")) != EOF)
switch (optc) {
case 'p':
t->str[0] |= TF_POSIX;
break;
case '?':
errorf("time: -%s unknown option", opt.optarg);
case ':':
errorf("time: -%s requires an argument",
opt.optarg);
}
/* Copy command words down over options. */
if (opt.optind != 0) {
for (i = 0; i < opt.optind; i++)
afree(wp[i], ATEMP);
for (i = 0, j = opt.optind; (wp[i] = wp[j]); i++, j++)
;
}
if (!wp[0])
t->str[0] |= TF_NOARGS;
*app = wp;
}
static char *
clocktos(t)
clock_t t;
{
static char temp[22]; /* enough for 64 bit clock_t */
register int i;
register char *cp = temp + sizeof(temp);
/* note: posix says must use max precision, ie, if clk_tck is
* 1000, must print 3 places after decimal (if non-zero, else 1).
*/
if (CLK_TCK != 100) /* convert to 1/100'ths */
t = (t < (clock_t)(1000000000/CLK_TCK)) ?
(t * 100) / CLK_TCK : (t / CLK_TCK) * 100;
*--cp = '\0';
for (i = -2; i <= 0 || t > 0; i++) {
if (i == 0)
*--cp = '.';
*--cp = '0' + (char)(t%10);
t /= 10;
}
return cp;
}
/* exec with no args - args case is taken care of in comexec() */
int
c_exec(wp)
char ** wp;
{
int i;
/* make sure redirects stay in place */
if (e->savefd != NULL) {
for (i = 0; i < NUFILE; i++) {
if (e->savefd[i] > 0)
close(e->savefd[i]);
/*
* For ksh keep anything > 2 private,
* for sh, let them be (POSIX says what
* happens is unspecified and the bourne shell
* keeps them open).
*/
#ifdef KSH
if (i > 2 && e->savefd[i])
fd_clexec(i);
#endif /* KSH */
}
e->savefd = NULL;
}
return 0;
}
/* dummy function, special case in comexec() */
int
c_builtin(wp)
char ** wp;
{
return 0;
}
extern int c_test ARGS((char **wp)); /* in c_test.c */
extern int c_ulimit ARGS((char **wp)); /* in c_ulimit.c */
/* A leading = means assignments before command are kept;
* a leading * means a POSIX special builtin;
* a leading + means a POSIX regular builtin
* (* and + should not be combined).
*/
const struct builtin shbuiltins [] = {
{"*=.", c_dot},
{"*=:", c_label},
{"[", c_test},
{"*=break", c_brkcont},
{"=builtin", c_builtin},
{"*=continue", c_brkcont},
{"*=eval", c_eval},
{"*=exec", c_exec},
{"*=exit", c_exitreturn},
{"+false", c_label},
{"*=return", c_exitreturn},
{"*=set", c_set},
{"*=shift", c_shift},
{"=times", c_times},
{"*=trap", c_trap},
{"+=wait", c_wait},
{"+read", c_read},
{"test", c_test},
{"+true", c_label},
{"ulimit", c_ulimit},
{"+umask", c_umask},
{"*=unset", c_unset},
#ifdef OS2
/* In OS2, the first line of a file can be "extproc name", which
* tells the command interpreter (cmd.exe) to use name to execute
* the file. For this to be useful, ksh must ignore commands
* starting with extproc and this does the trick...
*/
{"extproc", c_label},
#endif /* OS2 */
{NULL, NULL}
};

666
bin/ksh/c_test.c Normal file
View File

@@ -0,0 +1,666 @@
/* $NetBSD: c_test.c,v 1.6 2005/06/26 19:09:00 christos Exp $ */
/*
* test(1); version 7-like -- author Erik Baalbergen
* modified by Eric Gisin to be used as built-in.
* modified by Arnold Robbins to add SVR3 compatibility
* (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
* modified by Michael Rendell to add Korn's [[ .. ]] expressions.
* modified by J.T. Conklin to add POSIX compatibility.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: c_test.c,v 1.6 2005/06/26 19:09:00 christos Exp $");
#endif
#include "sh.h"
#include "ksh_stat.h"
#include "c_test.h"
/* test(1) accepts the following grammar:
oexpr ::= aexpr | aexpr "-o" oexpr ;
aexpr ::= nexpr | nexpr "-a" aexpr ;
nexpr ::= primary | "!" nexpr ;
primary ::= unary-operator operand
| operand binary-operator operand
| operand
| "(" oexpr ")"
;
unary-operator ::= "-a"|"-r"|"-w"|"-x"|"-e"|"-f"|"-d"|"-c"|"-b"|"-p"|
"-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|
"-L"|"-h"|"-S"|"-H";
binary-operator ::= "="|"=="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
"-nt"|"-ot"|"-ef"|
"<"|">" # rules used for [[ .. ]] expressions
;
operand ::= <any thing>
*/
#define T_ERR_EXIT 2 /* POSIX says > 1 for errors */
struct t_op {
char op_text[4];
Test_op op_num;
};
static const struct t_op u_ops [] = {
{"-a", TO_FILAXST },
{"-b", TO_FILBDEV },
{"-c", TO_FILCDEV },
{"-d", TO_FILID },
{"-e", TO_FILEXST },
{"-f", TO_FILREG },
{"-G", TO_FILGID },
{"-g", TO_FILSETG },
{"-h", TO_FILSYM },
{"-H", TO_FILCDF },
{"-k", TO_FILSTCK },
{"-L", TO_FILSYM },
{"-n", TO_STNZE },
{"-O", TO_FILUID },
{"-o", TO_OPTION },
{"-p", TO_FILFIFO },
{"-r", TO_FILRD },
{"-s", TO_FILGZ },
{"-S", TO_FILSOCK },
{"-t", TO_FILTT },
{"-u", TO_FILSETU },
{"-w", TO_FILWR },
{"-x", TO_FILEX },
{"-z", TO_STZER },
{"", TO_NONOP }
};
static const struct t_op b_ops [] = {
{"=", TO_STEQL },
#ifdef KSH
{"==", TO_STEQL },
#endif /* KSH */
{"!=", TO_STNEQ },
{"<", TO_STLT },
{">", TO_STGT },
{"-eq", TO_INTEQ },
{"-ne", TO_INTNE },
{"-gt", TO_INTGT },
{"-ge", TO_INTGE },
{"-lt", TO_INTLT },
{"-le", TO_INTLE },
{"-ef", TO_FILEQ },
{"-nt", TO_FILNT },
{"-ot", TO_FILOT },
{"", TO_NONOP }
};
static int test_stat ARGS((const char *, struct stat *));
static int test_eaccess ARGS((const char *, int));
static int test_oexpr ARGS((Test_env *, int));
static int test_aexpr ARGS((Test_env *, int));
static int test_nexpr ARGS((Test_env *, int));
static int test_primary ARGS((Test_env *, int));
static int ptest_isa ARGS((Test_env *, Test_meta));
static const char *ptest_getopnd ARGS((Test_env *, Test_op, int));
static int ptest_eval ARGS((Test_env *, Test_op, const char *,
const char *, int));
static void ptest_error ARGS((Test_env *, int, const char *));
int
c_test(wp)
char **wp;
{
int argc;
int res;
Test_env te;
te.flags = 0;
te.isa = ptest_isa;
te.getopnd = ptest_getopnd;
te.eval = ptest_eval;
te.error = ptest_error;
for (argc = 0; wp[argc]; argc++)
;
if (strcmp(wp[0], "[") == 0) {
if (strcmp(wp[--argc], "]") != 0) {
bi_errorf("missing ]");
return T_ERR_EXIT;
}
}
te.pos.wp = wp + 1;
te.wp_end = wp + argc;
/*
* Handle the special cases from POSIX.2, section 4.62.4.
* Implementation of all the rules isn't necessary since
* our parser does the right thing for the omitted steps.
*/
if (argc <= 5) {
char **owp = wp;
int invert = 0;
Test_op op;
const char *opnd1, *opnd2;
while (--argc >= 0) {
if ((*te.isa)(&te, TM_END))
return !0;
if (argc == 3) {
opnd1 = (*te.getopnd)(&te, TO_NONOP, 1);
if ((op = (Test_op) (*te.isa)(&te, TM_BINOP))) {
opnd2 = (*te.getopnd)(&te, op, 1);
res = (*te.eval)(&te, op, opnd1, opnd2,
1);
if (te.flags & TEF_ERROR)
return T_ERR_EXIT;
if (invert & 1)
res = !res;
return !res;
}
/* back up to opnd1 */
te.pos.wp--;
}
if (argc == 1) {
opnd1 = (*te.getopnd)(&te, TO_NONOP, 1);
/* Historically, -t by itself test if fd 1
* is a file descriptor, but POSIX says its
* a string test...
*/
if (!Flag(FPOSIX) && strcmp(opnd1, "-t") == 0)
break;
res = (*te.eval)(&te, TO_STNZE, opnd1,
(char *) 0, 1);
if (invert & 1)
res = !res;
return !res;
}
if ((*te.isa)(&te, TM_NOT)) {
invert++;
} else
break;
}
te.pos.wp = owp + 1;
}
return test_parse(&te);
}
/*
* Generic test routines.
*/
Test_op
test_isop(te, meta, s)
Test_env *te;
Test_meta meta;
const char *s;
{
char sc1;
const struct t_op *otab;
otab = meta == TM_UNOP ? u_ops : b_ops;
if (*s) {
sc1 = s[1];
for (; otab->op_text[0]; otab++)
if (sc1 == otab->op_text[1]
&& strcmp(s, otab->op_text) == 0
&& ((te->flags & TEF_DBRACKET)
|| (otab->op_num != TO_STLT
&& otab->op_num != TO_STGT)))
return otab->op_num;
}
return TO_NONOP;
}
int
test_eval(te, op, opnd1, opnd2, do_eval)
Test_env *te;
Test_op op;
const char *opnd1;
const char *opnd2;
int do_eval;
{
int res;
int not;
struct stat b1, b2;
if (!do_eval)
return 0;
switch ((int) op) {
/*
* Unary Operators
*/
case TO_STNZE: /* -n */
return *opnd1 != '\0';
case TO_STZER: /* -z */
return *opnd1 == '\0';
case TO_OPTION: /* -o */
if ((not = *opnd1 == '!'))
opnd1++;
if ((res = option(opnd1)) < 0)
res = 0;
else {
res = Flag(res);
if (not)
res = !res;
}
return res;
case TO_FILRD: /* -r */
return test_eaccess(opnd1, R_OK) == 0;
case TO_FILWR: /* -w */
return test_eaccess(opnd1, W_OK) == 0;
case TO_FILEX: /* -x */
return test_eaccess(opnd1, X_OK) == 0;
case TO_FILAXST: /* -a */
return test_stat(opnd1, &b1) == 0;
case TO_FILEXST: /* -e */
/* at&t ksh does not appear to do the /dev/fd/ thing for
* this (unless the os itself handles it)
*/
return stat(opnd1, &b1) == 0;
case TO_FILREG: /* -r */
return test_stat(opnd1, &b1) == 0 && S_ISREG(b1.st_mode);
case TO_FILID: /* -d */
return test_stat(opnd1, &b1) == 0 && S_ISDIR(b1.st_mode);
case TO_FILCDEV: /* -c */
#ifdef S_ISCHR
return test_stat(opnd1, &b1) == 0 && S_ISCHR(b1.st_mode);
#else
return 0;
#endif
case TO_FILBDEV: /* -b */
#ifdef S_ISBLK
return test_stat(opnd1, &b1) == 0 && S_ISBLK(b1.st_mode);
#else
return 0;
#endif
case TO_FILFIFO: /* -p */
#ifdef S_ISFIFO
return test_stat(opnd1, &b1) == 0 && S_ISFIFO(b1.st_mode);
#else
return 0;
#endif
case TO_FILSYM: /* -h -L */
#ifdef S_ISLNK
return lstat(opnd1, &b1) == 0 && S_ISLNK(b1.st_mode);
#else
return 0;
#endif
case TO_FILSOCK: /* -S */
#ifdef S_ISSOCK
return test_stat(opnd1, &b1) == 0 && S_ISSOCK(b1.st_mode);
#else
return 0;
#endif
case TO_FILCDF:/* -H HP context dependent files (directories) */
#ifdef S_ISCDF
{
/* Append a + to filename and check to see if result is a
* setuid directory. CDF stuff in general is hookey, since
* it breaks for the following sequence: echo hi > foo+;
* mkdir foo; echo bye > foo/default; chmod u+s foo
* (foo+ refers to the file with hi in it, there is no way
* to get at the file with bye in it - please correct me if
* I'm wrong about this).
*/
int len = strlen(opnd1);
char *p = str_nsave(opnd1, len + 1, ATEMP);
p[len++] = '+';
p[len] = '\0';
return stat(p, &b1) == 0 && S_ISCDF(b1.st_mode);
}
#else
return 0;
#endif
case TO_FILSETU: /* -u */
#ifdef S_ISUID
return test_stat(opnd1, &b1) == 0
&& (b1.st_mode & S_ISUID) == S_ISUID;
#else
return 0;
#endif
case TO_FILSETG: /* -g */
#ifdef S_ISGID
return test_stat(opnd1, &b1) == 0
&& (b1.st_mode & S_ISGID) == S_ISGID;
#else
return 0;
#endif
case TO_FILSTCK: /* -k */
return test_stat(opnd1, &b1) == 0
&& (b1.st_mode & S_ISVTX) == S_ISVTX;
case TO_FILGZ: /* -s */
return test_stat(opnd1, &b1) == 0 && b1.st_size > 0L;
case TO_FILTT: /* -t */
if (opnd1 && !bi_getn(opnd1, &res)) {
te->flags |= TEF_ERROR;
res = 0;
} else {
/* generate error if in FPOSIX mode? */
res = isatty(opnd1 ? res : 0);
}
return res;
case TO_FILUID: /* -O */
return test_stat(opnd1, &b1) == 0 && b1.st_uid == ksheuid;
case TO_FILGID: /* -G */
return test_stat(opnd1, &b1) == 0 && b1.st_gid == getegid();
/*
* Binary Operators
*/
case TO_STEQL: /* = */
if (te->flags & TEF_DBRACKET)
return gmatch(opnd1, opnd2, FALSE);
return strcmp(opnd1, opnd2) == 0;
case TO_STNEQ: /* != */
if (te->flags & TEF_DBRACKET)
return !gmatch(opnd1, opnd2, FALSE);
return strcmp(opnd1, opnd2) != 0;
case TO_STLT: /* < */
return strcmp(opnd1, opnd2) < 0;
case TO_STGT: /* > */
return strcmp(opnd1, opnd2) > 0;
case TO_INTEQ: /* -eq */
case TO_INTNE: /* -ne */
case TO_INTGE: /* -ge */
case TO_INTGT: /* -gt */
case TO_INTLE: /* -le */
case TO_INTLT: /* -lt */
{
long v1, v2;
if (!evaluate(opnd1, &v1, KSH_RETURN_ERROR)
|| !evaluate(opnd2, &v2, KSH_RETURN_ERROR))
{
/* error already printed.. */
te->flags |= TEF_ERROR;
return 1;
}
switch ((int) op) {
case TO_INTEQ:
return v1 == v2;
case TO_INTNE:
return v1 != v2;
case TO_INTGE:
return v1 >= v2;
case TO_INTGT:
return v1 > v2;
case TO_INTLE:
return v1 <= v2;
case TO_INTLT:
return v1 < v2;
}
}
case TO_FILNT: /* -nt */
{
int s2;
/* ksh88/ksh93 succeed if file2 can't be stated
* (subtly different from `does not exist').
*/
return stat(opnd1, &b1) == 0
&& (((s2 = stat(opnd2, &b2)) == 0
&& b1.st_mtime > b2.st_mtime) || s2 < 0);
}
case TO_FILOT: /* -ot */
{
int s1;
/* ksh88/ksh93 succeed if file1 can't be stated
* (subtly different from `does not exist').
*/
return stat(opnd2, &b2) == 0
&& (((s1 = stat(opnd1, &b1)) == 0
&& b1.st_mtime < b2.st_mtime) || s1 < 0);
}
case TO_FILEQ: /* -ef */
return stat (opnd1, &b1) == 0 && stat (opnd2, &b2) == 0
&& b1.st_dev == b2.st_dev
&& b1.st_ino == b2.st_ino;
}
(*te->error)(te, 0, "internal error: unknown op");
return 1;
}
/* Nasty kludge to handle Korn's bizarre /dev/fd hack */
static int
test_stat(pathx, statb)
const char *pathx;
struct stat *statb;
{
#if !defined(HAVE_DEV_FD)
int fd;
if (strncmp(pathx, "/dev/fd/", 8) == 0 && getn(pathx + 8, &fd))
return fstat(fd, statb);
#endif /* !HAVE_DEV_FD */
return stat(pathx, statb);
}
/* Routine to handle Korn's /dev/fd hack, and to deal with X_OK on
* non-directories when running as root.
*/
static int
test_eaccess(pathx, mode)
const char *pathx;
int mode;
{
int res;
#if !defined(HAVE_DEV_FD)
int fd;
/* Note: doesn't handle //dev/fd, etc.. (this is ok) */
if (strncmp(pathx, "/dev/fd/", 8) == 0 && getn(pathx + 8, &fd)) {
int flags;
if ((flags = fcntl(fd, F_GETFL, 0)) < 0
|| (mode & X_OK)
|| ((mode & W_OK) && (flags & O_ACCMODE) == O_RDONLY)
|| ((mode & R_OK) && (flags & O_ACCMODE) == O_WRONLY))
return -1;
return 0;
}
#endif /* !HAVE_DEV_FD */
res = eaccess(pathx, mode);
/*
* On most (all?) unixes, access() says everything is executable for
* root - avoid this on files by using stat().
*/
if (res == 0 && ksheuid == 0 && (mode & X_OK)) {
struct stat statb;
if (stat(pathx, &statb) < 0)
res = -1;
else if (S_ISDIR(statb.st_mode))
res = 0;
else
res = (statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
? 0 : -1;
}
return res;
}
int
test_parse(te)
Test_env *te;
{
int res;
res = test_oexpr(te, 1);
if (!(te->flags & TEF_ERROR) && !(*te->isa)(te, TM_END))
(*te->error)(te, 0, "unexpected operator/operand");
return (te->flags & TEF_ERROR) ? T_ERR_EXIT : !res;
}
static int
test_oexpr(te, do_eval)
Test_env *te;
int do_eval;
{
int res;
res = test_aexpr(te, do_eval);
if (res)
do_eval = 0;
if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_OR))
return test_oexpr(te, do_eval) || res;
return res;
}
static int
test_aexpr(te, do_eval)
Test_env *te;
int do_eval;
{
int res;
res = test_nexpr(te, do_eval);
if (!res)
do_eval = 0;
if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_AND))
return test_aexpr(te, do_eval) && res;
return res;
}
static int
test_nexpr(te, do_eval)
Test_env *te;
int do_eval;
{
if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_NOT))
return !test_nexpr(te, do_eval);
return test_primary(te, do_eval);
}
static int
test_primary(te, do_eval)
Test_env *te;
int do_eval;
{
const char *opnd1, *opnd2;
int res;
Test_op op;
if (te->flags & TEF_ERROR)
return 0;
if ((*te->isa)(te, TM_OPAREN)) {
res = test_oexpr(te, do_eval);
if (te->flags & TEF_ERROR)
return 0;
if (!(*te->isa)(te, TM_CPAREN)) {
(*te->error)(te, 0, "missing closing paren");
return 0;
}
return res;
}
if ((op = (Test_op) (*te->isa)(te, TM_UNOP))) {
/* unary expression */
opnd1 = (*te->getopnd)(te, op, do_eval);
if (!opnd1) {
(*te->error)(te, -1, "missing argument");
return 0;
}
return (*te->eval)(te, op, opnd1, (const char *) 0, do_eval);
}
opnd1 = (*te->getopnd)(te, TO_NONOP, do_eval);
if (!opnd1) {
(*te->error)(te, 0, "expression expected");
return 0;
}
if ((op = (Test_op) (*te->isa)(te, TM_BINOP))) {
/* binary expression */
opnd2 = (*te->getopnd)(te, op, do_eval);
if (!opnd2) {
(*te->error)(te, -1, "missing second argument");
return 0;
}
return (*te->eval)(te, op, opnd1, opnd2, do_eval);
}
if (te->flags & TEF_DBRACKET) {
(*te->error)(te, -1, "missing expression operator");
return 0;
}
return (*te->eval)(te, TO_STNZE, opnd1, (const char *) 0, do_eval);
}
/*
* Plain test (test and [ .. ]) specific routines.
*/
/* Test if the current token is a whatever. Accepts the current token if
* it is. Returns 0 if it is not, non-zero if it is (in the case of
* TM_UNOP and TM_BINOP, the returned value is a Test_op).
*/
static int
ptest_isa(te, meta)
Test_env *te;
Test_meta meta;
{
/* Order important - indexed by Test_meta values */
static const char *const tokens[] = {
"-o", "-a", "!", "(", ")"
};
int ret;
if (te->pos.wp >= te->wp_end)
return meta == TM_END;
if (meta == TM_UNOP || meta == TM_BINOP)
ret = (int) test_isop(te, meta, *te->pos.wp);
else if (meta == TM_END)
ret = 0;
else
ret = strcmp(*te->pos.wp, tokens[(int) meta]) == 0;
/* Accept the token? */
if (ret)
te->pos.wp++;
return ret;
}
static const char *
ptest_getopnd(te, op, do_eval)
Test_env *te;
Test_op op;
int do_eval;
{
if (te->pos.wp >= te->wp_end)
return op == TO_FILTT ? "1" : (const char *) 0;
return *te->pos.wp++;
}
static int
ptest_eval(te, op, opnd1, opnd2, do_eval)
Test_env *te;
Test_op op;
const char *opnd1;
const char *opnd2;
int do_eval;
{
return test_eval(te, op, opnd1, opnd2, do_eval);
}
static void
ptest_error(te, offset, msg)
Test_env *te;
int offset;
const char *msg;
{
const char *op = te->pos.wp + offset >= te->wp_end ?
(const char *) 0 : te->pos.wp[offset];
te->flags |= TEF_ERROR;
if (op)
bi_errorf("%s: %s", op, msg);
else
bi_errorf("%s", msg);
}

55
bin/ksh/c_test.h Normal file
View File

@@ -0,0 +1,55 @@
/* $NetBSD: c_test.h,v 1.3 2004/07/07 19:20:09 mycroft Exp $ */
/* Various types of operations. Keeping things grouped nicely
* (unary,binary) makes switch() statements more efficient.
*/
enum Test_op {
TO_NONOP = 0, /* non-operator */
/* unary operators */
TO_STNZE, TO_STZER, TO_OPTION,
TO_FILAXST,
TO_FILEXST,
TO_FILREG, TO_FILBDEV, TO_FILCDEV, TO_FILSYM, TO_FILFIFO, TO_FILSOCK,
TO_FILCDF, TO_FILID, TO_FILGID, TO_FILSETG, TO_FILSTCK, TO_FILUID,
TO_FILRD, TO_FILGZ, TO_FILTT, TO_FILSETU, TO_FILWR, TO_FILEX,
/* binary operators */
TO_STEQL, TO_STNEQ, TO_STLT, TO_STGT, TO_INTEQ, TO_INTNE, TO_INTGT,
TO_INTGE, TO_INTLT, TO_INTLE, TO_FILEQ, TO_FILNT, TO_FILOT
};
typedef enum Test_op Test_op;
/* Used by Test_env.isa() (order important - used to index *_tokens[] arrays) */
enum Test_meta {
TM_OR, /* -o or || */
TM_AND, /* -a or && */
TM_NOT, /* ! */
TM_OPAREN, /* ( */
TM_CPAREN, /* ) */
TM_UNOP, /* unary operator */
TM_BINOP, /* binary operator */
TM_END /* end of input */
};
typedef enum Test_meta Test_meta;
#define TEF_ERROR BIT(0) /* set if we've hit an error */
#define TEF_DBRACKET BIT(1) /* set if [[ .. ]] test */
typedef struct test_env Test_env;
struct test_env {
int flags; /* TEF_* */
union {
char **wp; /* used by ptest_* */
XPtrV *av; /* used by dbtestp_* */
} pos;
char **wp_end; /* used by ptest_* */
int (*isa) ARGS((Test_env *te, Test_meta meta));
const char *(*getopnd) ARGS((Test_env *te, Test_op op, int do_eval));
int (*eval) ARGS((Test_env *te, Test_op op, const char *opnd1,
const char *opnd2, int do_eval));
void (*error) ARGS((Test_env *te, int offset, const char *msg));
};
Test_op test_isop ARGS((Test_env *te, Test_meta meta, const char *s));
int test_eval ARGS((Test_env *te, Test_op op, const char *opnd1,
const char *opnd2, int do_eval));
int test_parse ARGS((Test_env *te));

285
bin/ksh/c_ulimit.c Normal file
View File

@@ -0,0 +1,285 @@
/* $NetBSD: c_ulimit.c,v 1.10 2012/06/09 02:51:50 christos Exp $ */
/*
ulimit -- handle "ulimit" builtin
Reworked to use getrusage() and ulimit() at once (as needed on
some schizophrenic systems, eg, HP-UX 9.01), made argument parsing
conform to at&t ksh, added autoconf support. Michael Rendell, May, '94
Eric Gisin, September 1988
Adapted to PD KornShell. Removed AT&T code.
last edit: 06-Jun-1987 D A Gwyn
This started out as the BRL UNIX System V system call emulation
for 4.nBSD, and was later extended by Doug Kingston to handle
the extended 4.nBSD resource limits. It now includes the code
that was originally under case SYSULIMIT in source file "xec.c".
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: c_ulimit.c,v 1.10 2012/06/09 02:51:50 christos Exp $");
#endif
#include "sh.h"
#include "ksh_time.h"
#ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
#endif /* HAVE_SYS_RESOURCE_H */
#ifdef HAVE_ULIMIT_H
# include <ulimit.h>
#else /* HAVE_ULIMIT_H */
# ifdef HAVE_ULIMIT
extern long ulimit();
# endif /* HAVE_ULIMIT */
#endif /* HAVE_ULIMIT_H */
#define SOFT 0x1
#define HARD 0x2
#ifdef RLIM_INFINITY
# define KSH_RLIM_INFINITY RLIM_INFINITY
#else
# define KSH_RLIM_INFINITY ((rlim_t) 1 << (sizeof(rlim_t) * 8 - 1) - 1)
#endif /* RLIM_INFINITY */
int
c_ulimit(wp)
char **wp;
{
static const struct limits {
const char *name;
enum { RLIMIT, ULIMIT } which;
int gcmd; /* get command */
int scmd; /* set command (or -1, if no set command) */
int factor; /* multiply by to get rlim_{cur,max} values */
char option;
} limits[] = {
/* Do not use options -H, -S or -a */
#ifdef RLIMIT_CPU
{ "time(cpu-seconds)", RLIMIT, RLIMIT_CPU, RLIMIT_CPU, 1, 't' },
#endif
#ifdef RLIMIT_FSIZE
{ "file(blocks)", RLIMIT, RLIMIT_FSIZE, RLIMIT_FSIZE, 512, 'f' },
#else /* RLIMIT_FSIZE */
# ifdef UL_GETFSIZE /* x/open */
{ "file(blocks)", ULIMIT, UL_GETFSIZE, UL_SETFSIZE, 1, 'f' },
# else /* UL_GETFSIZE */
# ifdef UL_GFILLIM /* svr4/xenix */
{ "file(blocks)", ULIMIT, UL_GFILLIM, UL_SFILLIM, 1, 'f' },
# else /* UL_GFILLIM */
{ "file(blocks)", ULIMIT, 1, 2, 1, 'f' },
# endif /* UL_GFILLIM */
# endif /* UL_GETFSIZE */
#endif /* RLIMIT_FSIZE */
#ifdef RLIMIT_CORE
{ "coredump(blocks)", RLIMIT, RLIMIT_CORE, RLIMIT_CORE, 512, 'c' },
#endif
#ifdef RLIMIT_DATA
{ "data(kbytes)", RLIMIT, RLIMIT_DATA, RLIMIT_DATA, 1024, 'd' },
#endif
#ifdef RLIMIT_STACK
{ "stack(kbytes)", RLIMIT, RLIMIT_STACK, RLIMIT_STACK, 1024, 's' },
#endif
#ifdef RLIMIT_MEMLOCK
{ "lockedmem(kbytes)", RLIMIT, RLIMIT_MEMLOCK, RLIMIT_MEMLOCK, 1024, 'l' },
#endif
#ifdef RLIMIT_RSS
{ "memory(kbytes)", RLIMIT, RLIMIT_RSS, RLIMIT_RSS, 1024, 'm' },
#endif
#ifdef RLIMIT_NOFILE
{ "nofiles(descriptors)", RLIMIT, RLIMIT_NOFILE, RLIMIT_NOFILE, 1, 'n' },
#else /* RLIMIT_NOFILE */
# ifdef UL_GDESLIM /* svr4/xenix */
{ "nofiles(descriptors)", ULIMIT, UL_GDESLIM, -1, 1, 'n' },
# endif /* UL_GDESLIM */
#endif /* RLIMIT_NOFILE */
#ifdef RLIMIT_NPROC
{ "processes", RLIMIT, RLIMIT_NPROC, RLIMIT_NPROC, 1, 'p' },
#endif
#ifdef RLIMIT_NTHR
{ "threads", RLIMIT, RLIMIT_NTHR, RLIMIT_NTHR, 1, 'r' },
#endif
#ifdef RLIMIT_VMEM
{ "vmemory(kbytes)", RLIMIT, RLIMIT_VMEM, RLIMIT_VMEM, 1024, 'v' },
#else /* RLIMIT_VMEM */
/* These are not quite right - really should subtract etext or something */
# ifdef UL_GMEMLIM /* svr4/xenix */
{ "vmemory(maxaddr)", ULIMIT, UL_GMEMLIM, -1, 1, 'v' },
# else /* UL_GMEMLIM */
# ifdef UL_GETBREAK /* osf/1 */
{ "vmemory(maxaddr)", ULIMIT, UL_GETBREAK, -1, 1, 'v' },
# else /* UL_GETBREAK */
# ifdef UL_GETMAXBRK /* hpux */
{ "vmemory(maxaddr)", ULIMIT, UL_GETMAXBRK, -1, 1, 'v' },
# endif /* UL_GETMAXBRK */
# endif /* UL_GETBREAK */
# endif /* UL_GMEMLIM */
#endif /* RLIMIT_VMEM */
#ifdef RLIMIT_SWAP
{ "swap(kbytes)", RLIMIT, RLIMIT_SWAP, RLIMIT_SWAP, 1024, 'w' },
#endif
#ifdef RLIMIT_SBSIZE
{ "sbsize(bytes)", RLIMIT, RLIMIT_SBSIZE, RLIMIT_SBSIZE, 1, 'b' },
#endif
{ .name = NULL }
};
static char options[3 + NELEM(limits)];
rlim_t UNINITIALIZED(val);
int how = SOFT | HARD;
const struct limits *l;
int set, all = 0;
int optc, what;
#ifdef HAVE_SETRLIMIT
struct rlimit limit;
#endif /* HAVE_SETRLIMIT */
if (!options[0]) {
/* build options string on first call - yuck */
char *p = options;
*p++ = 'H'; *p++ = 'S'; *p++ = 'a';
for (l = limits; l->name; l++)
*p++ = l->option;
*p = '\0';
}
what = 'f';
while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF)
switch (optc) {
case 'H':
how = HARD;
break;
case 'S':
how = SOFT;
break;
case 'a':
all = 1;
break;
case '?':
return 1;
default:
what = optc;
}
for (l = limits; l->name && l->option != what; l++)
;
if (!l->name) {
internal_errorf(0, "ulimit: %c", what);
return 1;
}
wp += builtin_opt.optind;
set = *wp ? 1 : 0;
if (set) {
if (all || wp[1]) {
bi_errorf("too many arguments");
return 1;
}
if (strcmp(wp[0], "unlimited") == 0)
val = KSH_RLIM_INFINITY;
else {
long rval;
if (!evaluate(wp[0], &rval, KSH_RETURN_ERROR))
return 1;
/* Avoid problems caused by typos that
* evaluate misses due to evaluating unset
* parameters to 0...
* If this causes problems, will have to
* add parameter to evaluate() to control
* if unset params are 0 or an error.
*/
if (!rval && !digit(wp[0][0])) {
bi_errorf("invalid limit: %s", wp[0]);
return 1;
}
val = (u_long)rval * l->factor;
}
}
if (all) {
for (l = limits; l->name; l++) {
#ifdef HAVE_SETRLIMIT
if (l->which == RLIMIT) {
getrlimit(l->gcmd, &limit);
if (how & SOFT)
val = limit.rlim_cur;
else if (how & HARD)
val = limit.rlim_max;
} else
#endif /* HAVE_SETRLIMIT */
#ifdef HAVE_ULIMIT
{
val = ulimit(l->gcmd, (rlim_t) 0);
}
#else /* HAVE_ULIMIT */
;
#endif /* HAVE_ULIMIT */
shprintf("%-20s ", l->name);
#ifdef RLIM_INFINITY
if (val == RLIM_INFINITY)
shprintf("unlimited\n");
else
#endif /* RLIM_INFINITY */
{
val /= l->factor;
shprintf("%ld\n", (long) val);
}
}
return 0;
}
#ifdef HAVE_SETRLIMIT
if (l->which == RLIMIT) {
getrlimit(l->gcmd, &limit);
if (set) {
if (how & SOFT)
limit.rlim_cur = val;
if (how & HARD)
limit.rlim_max = val;
if (setrlimit(l->scmd, &limit) < 0) {
if (errno == EPERM)
bi_errorf("exceeds allowable limit");
else
bi_errorf("bad limit: %s",
strerror(errno));
return 1;
}
} else {
if (how & SOFT)
val = limit.rlim_cur;
else if (how & HARD)
val = limit.rlim_max;
}
} else
#endif /* HAVE_SETRLIMIT */
#ifdef HAVE_ULIMIT
{
if (set) {
if (l->scmd == -1) {
bi_errorf("can't change limit");
return 1;
} else if (ulimit(l->scmd, val) < 0) {
bi_errorf("bad limit: %s", strerror(errno));
return 1;
}
} else
val = ulimit(l->gcmd, (rlim_t) 0);
}
#else /* HAVE_ULIMIT */
;
#endif /* HAVE_ULIMIT */
if (!set) {
#ifdef RLIM_INFINITY
if (val == RLIM_INFINITY)
shprintf("unlimited\n");
else
#endif /* RLIM_INFINITY */
{
val /= l->factor;
shprintf("%ld\n", (long) val);
}
}
return 0;
}

57
bin/ksh/conf-end.h Normal file
View File

@@ -0,0 +1,57 @@
/* $NetBSD: conf-end.h,v 1.2 1997/01/12 19:11:43 tls Exp $ */
/*
* End of configuration stuff for PD ksh.
*
* RCSid: $NetBSD: conf-end.h,v 1.2 1997/01/12 19:11:43 tls Exp $
*/
#if defined(EMACS) || defined(VI)
# define EDIT
#else
# undef EDIT
#endif
/* Editing implies history */
#if defined(EDIT) && !defined(HISTORY)
# define HISTORY
#endif /* EDIT */
/*
* if you don't have mmap() you can't use Peter Collinson's history
* mechanism. If that is the case, then define EASY_HISTORY
*/
#if defined(HISTORY) && (!defined(COMPLEX_HISTORY) || !defined(HAVE_MMAP) || !defined(HAVE_FLOCK))
# undef COMPLEX_HISTORY
# define EASY_HISTORY /* sjg's trivial history file */
#endif
/* Can we safely catch sigchld and wait for processes? */
#if (defined(HAVE_WAITPID) || defined(HAVE_WAIT3)) \
&& (defined(POSIX_SIGNALS) || defined(BSD42_SIGNALS))
# define JOB_SIGS
#endif
#if !defined(JOB_SIGS) || !(defined(POSIX_PGRP) || defined(BSD_PGRP))
# undef JOBS /* if no JOB_SIGS, no job control support */
#endif
/* pdksh assumes system calls return EINTR if a signal happened (this so
* the signal handler doesn't have to longjmp()). I don't know if this
* happens (or can be made to happen) with sigset() et. al. (the bsd41 signal
* routines), so, the autoconf stuff checks what they do and defines
* SIGNALS_DONT_INTERRUPT if signals don't interrupt read().
* If SIGNALS_DONT_INTERRUPT isn't defined and your compiler chokes on this,
* delete the hash in front of the error (and file a bug report).
*/
#ifdef SIGNALS_DONT_INTERRUPT
# error pdksh needs interruptable system calls.
#endif /* SIGNALS_DONT_INTERRUPT */
#ifdef HAVE_GCC_FUNC_ATTR
# define GCC_FUNC_ATTR(x) __attribute__((x))
# define GCC_FUNC_ATTR2(x,y) __attribute__((x,y))
#else
# define GCC_FUNC_ATTR(x)
# define GCC_FUNC_ATTR2(x,y)
#endif /* HAVE_GCC_FUNC_ATTR */

366
bin/ksh/config.h Normal file
View File

@@ -0,0 +1,366 @@
/* config.h. Generated automatically by configure. */
/* config.h.in. Generated automatically from configure.in by autoheader. */
/*
* This file, acconfig.h, which is a part of pdksh (the public domain ksh),
* is placed in the public domain. It comes with no licence, warranty
* or guarantee of any kind (i.e., at your own risk).
*/
#ifndef CONFIG_H
#define CONFIG_H
/* Define if on AIX 3.
System headers sometimes define this.
We just want to avoid a redefinition error message. */
#ifndef _ALL_SOURCE
/* #undef _ALL_SOURCE */
#endif
/* Define if the closedir function returns void instead of int. */
/* #undef CLOSEDIR_VOID */
/* Define to empty if the keyword does not work. */
/* #undef const */
/* Define to `int' if <sys/types.h> doesn't define. */
/* #undef gid_t */
/* Define if you have a working `mmap' system call. */
/* #undef HAVE_MMAP */
/* Define if your struct stat has st_rdev. */
#define HAVE_ST_RDEV 1
/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
#define HAVE_SYS_WAIT_H 1
/* Define if you have <unistd.h>. */
#define HAVE_UNISTD_H 1
/* Define if on MINIX. */
#define _MINIX 1
/* Define to `int' if <sys/types.h> doesn't define. */
/* #undef mode_t */
/* Define to `long' if <sys/types.h> doesn't define. */
/* #undef off_t */
/* Define to `int' if <sys/types.h> doesn't define. */
/* #undef pid_t */
/* Define if the system does not provide POSIX.1 features except
with this defined. */
#define _POSIX_1_SOURCE 2
/* Define if you need to in order for stat and other things to work. */
#define _POSIX_SOURCE 1
/* Define as the return type of signal handlers (int or void). */
#define RETSIGTYPE void
/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */
/* #undef STAT_MACROS_BROKEN */
/* Define if `sys_siglist' is declared by <signal.h>. */
#define SYS_SIGLIST_DECLARED 1
/* Define if you can safely include both <sys/time.h> and <time.h>. */
#define TIME_WITH_SYS_TIME 1
/* Define to `int' if <sys/types.h> doesn't define. */
/* #undef uid_t */
/* Define if the closedir function returns void instead of int. */
/* #undef VOID_CLOSEDIR */
/* Define if your kernal doesn't handle scripts starting with #! */
/* #undef SHARPBANG */
/* Define if dup2() preserves the close-on-exec flag (ultrix does this) */
/* #undef DUP2_BROKEN */
/* Define as the return value of signal handlers (0 or ). */
#define RETSIGVAL
/* Define if you have posix signal routines (sigaction(), et. al.) */
#define POSIX_SIGNALS 1
/* Define if you have BSD4.2 signal routines (sigsetmask(), et. al.) */
/* #undef BSD42_SIGNALS */
/* Define if you have BSD4.1 signal routines (sigset(), et. al.) */
/* #undef BSD41_SIGNALS */
/* Define if you have v7 signal routines (signal(), signal reset on delivery) */
/* #undef V7_SIGNALS */
/* Define to use the fake posix signal routines (sigact.[ch]) */
/* #undef USE_FAKE_SIGACT */
/* Define if signals don't interrupt read() */
/* #undef SIGNALS_DONT_INTERRUPT */
/* Define if you have bsd versions of the setpgrp() and getpgrp() routines */
/* #undef BSD_PGRP */
/* Define if you have POSIX versions of the setpgid() and getpgrp() routines */
/* #undef POSIX_PGRP */
/* Define if you have sysV versions of the setpgrp() and getpgrp() routines */
/* #undef SYSV_PGRP */
/* Define if you don't have setpgrp(), setpgid() or getpgrp() routines */
#define NO_PGRP 1
/* Define to char if your compiler doesn't like the void keyword */
/* #undef void */
/* Define to nothing if compiler doesn't like the volatile keyword */
/* #undef volatile */
/* Define if C compiler groks function prototypes */
#define HAVE_PROTOTYPES 1
/* Define if C compiler groks __attribute__((...)) (const, noreturn, format) */
#define HAVE_GCC_FUNC_ATTR 1
/* Define to 32-bit signed integer type if <sys/types.h> doesn't define */
/* #undef clock_t */
/* Define to the type of struct rlimit fields if the rlim_t type is missing */
/* #undef rlim_t */
/* Define if time() is declared in <time.h> */
#define TIME_DECLARED 1
/* Define to `unsigned' if <signal.h> doesn't define */
/* #undef sigset_t */
/* Define if sys_errlist[] and sys_nerr are in the C library */
#define HAVE_SYS_ERRLIST 1
/* Define if sys_errlist[] and sys_nerr are defined in <errno.h> */
#define SYS_ERRLIST_DECLARED 1
/* Define if sys_siglist[] is in the C library */
/* #undef HAVE_SYS_SIGLIST */
/* Define if you have a sane <termios.h> header file */
#define HAVE_TERMIOS_H 1
/* Define if you have a memset() function in your C library */
#define HAVE_MEMSET 1
/* Define if you have a memmove() function in your C library */
#define HAVE_MEMMOVE 1
/* Define if you have a bcopy() function in your C library */
/* #undef HAVE_BCOPY */
/* Define if you have a lstat() function in your C library */
#define HAVE_LSTAT 1
/* Define if you have a sane <termio.h> header file */
/* #undef HAVE_TERMIO_H */
/* Define if you don't have times() or if it always returns 0 */
/* #undef TIMES_BROKEN */
/* Define if opendir() will open non-directory files */
/* #undef OPENDIR_DOES_NONDIR */
/* Define if the pgrp of setpgrp() can't be the pid of a zombie process */
/* #undef NEED_PGRP_SYNC */
/* Define if you arg running SCO unix */
/* #undef OS_SCO */
/* Define if you arg running ISC unix */
/* #undef OS_ISC */
/* Define if you arg running OS2 with the EMX library */
/* #undef OS2 */
/* Define if you have a POSIX.1 compatiable <sys/wait.h> */
#define POSIX_SYS_WAIT 1
/* Define if your OS maps references to /dev/fd/n to file descriptor n */
/* #undef HAVE_DEV_FD */
/* Define if your C library's getwd/getcwd function dumps core in unreadable
* directories. */
/* #undef HPUX_GETWD_BUG */
/* Default PATH (see comments in configure.in for more details) */
#define DEFAULT_PATH "/bin:/usr/bin:/usr/ucb"
/* Include ksh features? (see comments in configure.in for more details) */
#define KSH 1
/* Include emacs editing? (see comments in configure.in for more details) */
#define EMACS 1
/* Include vi editing? (see comments in configure.in for more details) */
#define VI 1
/* Include job control? (see comments in configure.in for more details) */
#define JOBS 1
/* Include brace-expansion? (see comments in configure.in for more details) */
#define BRACE_EXPAND 1
/* Include any history? (see comments in configure.in for more details) */
#define HISTORY 1
/* Include complex history? (see comments in configure.in for more details) */
/* #undef COMPLEX_HISTORY */
/* Strict POSIX behaviour? (see comments in configure.in for more details) */
/* #undef POSIXLY_CORRECT */
/* Specify default $ENV? (see comments in configure.in for more details) */
/* #undef DEFAULT_ENV */
/* Include shl(1) support? (see comments in configure.in for more details) */
/* #undef SWTCH */
/* Include game-of-life? (see comments in configure.in for more details) */
/* #undef SILLY */
/* The number of bytes in a int. */
#define SIZEOF_INT 4
/* The number of bytes in a long. */
#define SIZEOF_LONG 4
/* Define if you have the _setjmp function. */
/* #undef HAVE__SETJMP */
/* Define if you have the confstr function. */
/* #undef HAVE_CONFSTR */
/* Define if you have the dup2 function. */
#define HAVE_DUP2 1
/* Define if you have the flock function. */
#define HAVE_FLOCK 1
/* Define if you have the getcwd function. */
#define HAVE_GETCWD 1
/* Define if you have the getgroups function. */
/* #undef HAVE_GETGROUPS */
/* Define if you have the getpagesize function. */
#define HAVE_GETPAGESIZE 1
/* Define if you have the getrusage function. */
/* #undef HAVE_GETRUSAGE */
/* Define if you have the getwd function. */
/* #undef HAVE_GETWD */
/* Define if you have the killpg function. */
#define HAVE_KILLPG 1
/* Define if you have the nice function. */
#define HAVE_NICE 1
/* Define if you have the setrlimit function. */
/* #undef HAVE_SETRLIMIT */
/* Define if you have the sigsetjmp function. */
#define HAVE_SIGSETJMP 1
/* Define if you have the strcasecmp function. */
#define HAVE_STRCASECMP 1
/* Define if you have the strerror function. */
#define HAVE_STRERROR 1
/* Define if you have the strlcat function. */
#define HAVE_STRLCAT 1
/* Define if you have the strlcpy function. */
#define HAVE_STRLCPY 1
/* Define if you have the strstr function. */
#define HAVE_STRSTR 1
/* Define if you have the sysconf function. */
#define HAVE_SYSCONF 1
/* Define if you have the tcsetpgrp function. */
#define HAVE_TCSETPGRP 1
/* Define if you have the ulimit function. */
#define HAVE_ULIMIT 1
/* Define if you have the valloc function. */
#define HAVE_VALLOC 1
/* Define if you have the wait3 function. */
/* #undef HAVE_WAIT3 */
/* Define if you have the waitpid function. */
#define HAVE_WAITPID 1
/* Define if you have the <dirent.h> header file. */
#define HAVE_DIRENT_H 1
/* Define if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define if you have the <ndir.h> header file. */
/* #undef HAVE_NDIR_H */
/* Define if you have the <paths.h> header file. */
#define HAVE_PATHS_H 1
/* Define if you have the <stddef.h> header file. */
#define HAVE_STDDEF_H 1
/* Define if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define if you have the <sys/dir.h> header file. */
/* #undef HAVE_SYS_DIR_H */
/* Define if you have the <sys/ndir.h> header file. */
/* #undef HAVE_SYS_NDIR_H */
/* Define if you have the <sys/param.h> header file. */
#define HAVE_SYS_PARAM_H 1
/* Define if you have the <sys/resource.h> header file. */
#define HAVE_SYS_RESOURCE_H 1
/* Define if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
/* Define if you have the <sys/wait.h> header file. */
#define HAVE_SYS_WAIT_H 1
/* Define if you have the <ulimit.h> header file. */
#define HAVE_ULIMIT_H 1
/* Define if you have the <values.h> header file. */
/* #undef HAVE_VALUES_H */
/* Need to use a separate file to keep the configure script from commenting
* out the undefs....
*/
#include "conf-end.h"
#endif /* CONFIG_H */

1095
bin/ksh/edit.c Normal file

File diff suppressed because it is too large Load Diff

87
bin/ksh/edit.h Normal file
View File

@@ -0,0 +1,87 @@
/* $NetBSD: edit.h,v 1.3 1999/11/02 22:06:45 jdolecek Exp $ */
/* NAME:
* edit.h - globals for edit modes
*
* DESCRIPTION:
* This header defines various global edit objects.
*
* SEE ALSO:
*
*
* RCSid:
* $NetBSD: edit.h,v 1.3 1999/11/02 22:06:45 jdolecek Exp $
*
*/
/* some useful #defines */
#ifdef EXTERN
# define I__(i) = i
#else
# define I__(i)
# define EXTERN extern
# define EXTERN_DEFINED
#endif
#define BEL 0x07
/* tty driver characters we are interested in */
typedef struct {
int erase;
int kill;
int werase;
int intr;
int quit;
int eof;
} X_chars;
EXTERN X_chars edchars;
/* x_fc_glob() flags */
#define XCF_COMMAND BIT(0) /* Do command completion */
#define XCF_FILE BIT(1) /* Do file completion */
#define XCF_FULLPATH BIT(2) /* command completion: store full path */
#define XCF_COMMAND_FILE (XCF_COMMAND|XCF_FILE)
/* edit.c */
int x_getc ARGS((void));
void x_flush ARGS((void));
void x_putc ARGS((int c));
void x_puts ARGS((const char *s));
bool_t x_mode ARGS((bool_t onoff));
int promptlen ARGS((const char *cp, const char **spp));
int x_do_comment ARGS((char *buf, int bsize, int *lenp));
void x_print_expansions ARGS((int nwords, char *const *words, int is_command));
int x_cf_glob ARGS((int flags, const char *buf, int buflen, int pos, int *startp,
int *endp, char ***wordsp, int *is_commandp));
int x_longest_prefix ARGS((int nwords, char *const *words));
int x_basename ARGS((const char *s, const char *se));
void x_free_words ARGS((int nwords, char **words));
int x_escape ARGS((const char *, size_t, int (*)(const char *s, size_t len)));
/* emacs.c */
int x_emacs ARGS((char *buf, size_t len));
void x_init_emacs ARGS((void));
void x_emacs_keys ARGS((X_chars *ec));
/* vi.c */
int x_vi ARGS((char *buf, size_t len));
#ifdef DEBUG
# define D__(x) x
#else
# define D__(x)
#endif
/* This lot goes at the END */
/* be sure not to interfere with anyone else's idea about EXTERN */
#ifdef EXTERN_DEFINED
# undef EXTERN_DEFINED
# undef EXTERN
#endif
#undef I__
/*
* Local Variables:
* version-control:t
* comment-column:40
* End:
*/

47
bin/ksh/emacs-gen.sh Executable file
View File

@@ -0,0 +1,47 @@
#!/bin/sh
# $NetBSD: emacs-gen.sh,v 1.4 2008/10/25 22:18:15 apb Exp $
: ${AWK:=awk}
: ${SED:=sed}
case $# in
1) file=$1;;
*)
echo "$0: Usage: $0 path-to-emacs.c" 1>&2
exit 1
esac;
if [ ! -r "$file" ] ;then
echo "$0: can't read $file" 1>&2
exit 1
fi
cat << E_O_F || exit 1
/*
* NOTE: THIS FILE WAS GENERATED AUTOMATICALLY FROM $file
*
* DO NOT BOTHER EDITING THIS FILE
*/
E_O_F
# Pass 1: print out lines before @START-FUNC-TAB@
# and generate defines and function declarations,
${SED} -e '1,/@START-FUNC-TAB@/d' -e '/@END-FUNC-TAB@/,$d' < $file |
${AWK} 'BEGIN { nfunc = 0; }
/^[ ]*#/ {
print $0;
next;
}
{
fname = $2;
c = substr(fname, length(fname), 1);
if (c == ",")
fname = substr(fname, 1, length(fname) - 1);
if (fname != "0") {
printf "#define XFUNC_%s %d\n", substr(fname, 3, length(fname) - 2), nfunc;
printf "static int %s ARGS((int c));\n", fname;
nfunc++;
}
}' || exit 1
exit 0

2221
bin/ksh/emacs.c Normal file

File diff suppressed because it is too large Load Diff

1405
bin/ksh/eval.c Normal file

File diff suppressed because it is too large Load Diff

1749
bin/ksh/exec.c Normal file

File diff suppressed because it is too large Load Diff

108
bin/ksh/expand.h Normal file
View File

@@ -0,0 +1,108 @@
/* $NetBSD: expand.h,v 1.4 2001/07/26 15:05:07 wiz Exp $ */
/*
* Expanding strings
*/
/* $Id: expand.h,v 1.4 2001/07/26 15:05:07 wiz Exp $ */
#define X_EXTRA 8 /* this many extra bytes in X string */
#if 0 /* Usage */
XString xs;
char *xp;
Xinit(xs, xp, 128, ATEMP); /* allocate initial string */
while ((c = generate()) {
Xcheck(xs, xp); /* expand string if necessary */
Xput(xs, xp, c); /* add character */
}
return Xclose(xs, xp); /* resize string */
/*
* NOTE:
* The Xcheck and Xinit macros have a magic + X_EXTRA in the lengths.
* This is so that you can put up to X_EXTRA characters in a XString
* before calling Xcheck. (See yylex in lex.c)
*/
#endif /* 0 */
typedef struct XString {
char *end, *beg; /* end, begin of string */
size_t len; /* length */
Area *areap; /* area to allocate/free from */
} XString;
typedef char * XStringP;
/* initialize expandable string */
#define Xinit(xs, xp, length, area) do { \
(xs).len = length; \
(xs).areap = (area); \
(xs).beg = alloc((xs).len + X_EXTRA, (xs).areap); \
(xs).end = (xs).beg + (xs).len; \
xp = (xs).beg; \
} while (0)
/* stuff char into string */
#define Xput(xs, xp, c) (*xp++ = (c))
/* check if there are at least n bytes left */
#define XcheckN(xs, xp, n) do { \
int more = ((xp) + (n)) - (xs).end; \
if (more > 0) \
xp = Xcheck_grow_(&xs, xp, more); \
} while (0)
/* check for overflow, expand string */
#define Xcheck(xs, xp) XcheckN(xs, xp, 1)
/* free string */
#define Xfree(xs, xp) afree((void*) (xs).beg, (xs).areap)
/* close, return string */
#define Xclose(xs, xp) (char*) aresize((void*)(xs).beg, \
(size_t)((xp) - (xs).beg), (xs).areap)
/* begin of string */
#define Xstring(xs, xp) ((xs).beg)
#define Xnleft(xs, xp) ((xs).end - (xp)) /* may be less than 0 */
#define Xlength(xs, xp) ((xp) - (xs).beg)
#define Xsize(xs, xp) ((xs).end - (xs).beg)
#define Xsavepos(xs, xp) ((xp) - (xs).beg)
#define Xrestpos(xs, xp, n) ((xs).beg + (n))
char * Xcheck_grow_ ARGS((XString *xsp, char *xp, int more));
/*
* expandable vector of generic pointers
*/
typedef struct XPtrV {
void **cur; /* next avail pointer */
void **beg, **end; /* begin, end of vector */
} XPtrV;
#define XPinit(x, n) do { \
register void **vp__; \
vp__ = (void**) alloc(sizeofN(void*, n), ATEMP); \
(x).cur = (x).beg = vp__; \
(x).end = vp__ + n; \
} while (0)
#define XPput(x, p) do { \
if ((x).cur >= (x).end) { \
int n = XPsize(x); \
(x).beg = (void**) aresize((void*) (x).beg, \
sizeofN(void*, n*2), ATEMP); \
(x).cur = (x).beg + n; \
(x).end = (x).cur + n; \
} \
*(x).cur++ = (p); \
} while (0)
#define XPptrv(x) ((x).beg)
#define XPsize(x) ((x).cur - (x).beg)
#define XPclose(x) (void**) aresize((void*)(x).beg, \
sizeofN(void*, XPsize(x)), ATEMP)
#define XPfree(x) afree((void*) (x).beg, ATEMP)

613
bin/ksh/expr.c Normal file
View File

@@ -0,0 +1,613 @@
/* $NetBSD: expr.c,v 1.9 2011/10/16 17:12:11 joerg Exp $ */
/*
* Korn expression evaluation
*/
/*
* todo: better error handling: if in builtin, should be builtin error, etc.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: expr.c,v 1.9 2011/10/16 17:12:11 joerg Exp $");
#endif
#include "sh.h"
#include <ctype.h>
/* The order of these enums is constrained by the order of opinfo[] */
enum token {
/* some (long) unary operators */
O_PLUSPLUS = 0, O_MINUSMINUS,
/* binary operators */
O_EQ, O_NE,
/* assignments are assumed to be in range O_ASN .. O_BORASN */
O_ASN, O_TIMESASN, O_DIVASN, O_MODASN, O_PLUSASN, O_MINUSASN,
O_LSHIFTASN, O_RSHIFTASN, O_BANDASN, O_BXORASN, O_BORASN,
O_LSHIFT, O_RSHIFT,
O_LE, O_GE, O_LT, O_GT,
O_LAND,
O_LOR,
O_TIMES, O_DIV, O_MOD,
O_PLUS, O_MINUS,
O_BAND,
O_BXOR,
O_BOR,
O_TERN,
O_COMMA,
/* things after this aren't used as binary operators */
/* unary that are not also binaries */
O_BNOT, O_LNOT,
/* misc */
OPEN_PAREN, CLOSE_PAREN, CTERN,
/* things that don't appear in the opinfo[] table */
VAR, LIT, END, BAD
};
#define IS_BINOP(op) (((int)op) >= (int)O_EQ && ((int)op) <= (int)O_COMMA)
#define IS_ASSIGNOP(op) ((int)(op) >= (int)O_ASN && (int)(op) <= (int)O_BORASN)
enum prec {
P_PRIMARY = 0, /* VAR, LIT, (), ~ ! - + */
P_MULT, /* * / % */
P_ADD, /* + - */
P_SHIFT, /* << >> */
P_RELATION, /* < <= > >= */
P_EQUALITY, /* == != */
P_BAND, /* & */
P_BXOR, /* ^ */
P_BOR, /* | */
P_LAND, /* && */
P_LOR, /* || */
P_TERN, /* ?: */
P_ASSIGN, /* = *= /= %= += -= <<= >>= &= ^= |= */
P_COMMA /* , */
};
#define MAX_PREC P_COMMA
struct opinfo {
char name[4];
int len; /* name length */
enum prec prec; /* precedence: lower is higher */
};
/* Tokens in this table must be ordered so the longest are first
* (eg, += before +). If you change something, change the order
* of enum token too.
*/
static const struct opinfo opinfo[] = {
{ "++", 2, P_PRIMARY }, /* before + */
{ "--", 2, P_PRIMARY }, /* before - */
{ "==", 2, P_EQUALITY }, /* before = */
{ "!=", 2, P_EQUALITY }, /* before ! */
{ "=", 1, P_ASSIGN }, /* keep assigns in a block */
{ "*=", 2, P_ASSIGN },
{ "/=", 2, P_ASSIGN },
{ "%=", 2, P_ASSIGN },
{ "+=", 2, P_ASSIGN },
{ "-=", 2, P_ASSIGN },
{ "<<=", 3, P_ASSIGN },
{ ">>=", 3, P_ASSIGN },
{ "&=", 2, P_ASSIGN },
{ "^=", 2, P_ASSIGN },
{ "|=", 2, P_ASSIGN },
{ "<<", 2, P_SHIFT },
{ ">>", 2, P_SHIFT },
{ "<=", 2, P_RELATION },
{ ">=", 2, P_RELATION },
{ "<", 1, P_RELATION },
{ ">", 1, P_RELATION },
{ "&&", 2, P_LAND },
{ "||", 2, P_LOR },
{ "*", 1, P_MULT },
{ "/", 1, P_MULT },
{ "%", 1, P_MULT },
{ "+", 1, P_ADD },
{ "-", 1, P_ADD },
{ "&", 1, P_BAND },
{ "^", 1, P_BXOR },
{ "|", 1, P_BOR },
{ "?", 1, P_TERN },
{ ",", 1, P_COMMA },
{ "~", 1, P_PRIMARY },
{ "!", 1, P_PRIMARY },
{ "(", 1, P_PRIMARY },
{ ")", 1, P_PRIMARY },
{ ":", 1, P_PRIMARY },
{ "", 0, P_PRIMARY } /* end of table */
};
typedef struct expr_state Expr_state;
struct expr_state {
const char *expression; /* expression being evaluated */
const char *tokp; /* lexical position */
enum token tok; /* token from token() */
int noassign; /* don't do assigns (for ?:,&&,||) */
struct tbl *val; /* value from token() */
struct tbl *evaling; /* variable that is being recursively
* expanded (EXPRINEVAL flag set)
*/
};
enum error_type { ET_UNEXPECTED, ET_BADLIT, ET_RECURSIVE,
ET_LVALUE, ET_RDONLY, ET_STR };
static void evalerr ARGS((Expr_state *es, enum error_type type,
const char *str)) GCC_FUNC_ATTR(noreturn);
static struct tbl *evalexpr ARGS((Expr_state *es, enum prec prec));
static void token ARGS((Expr_state *es));
static struct tbl *do_ppmm ARGS((Expr_state *es, enum token op,
struct tbl *vasn, bool_t is_prefix));
static void assign_check ARGS((Expr_state *es, enum token op,
struct tbl *vasn));
static struct tbl *tempvar ARGS((void));
static struct tbl *intvar ARGS((Expr_state *es, struct tbl *vp));
/*
* parse and evaluate expression
*/
int
evaluate(expr, rval, error_ok)
const char *expr;
long *rval;
int error_ok;
{
struct tbl v;
int ret;
v.flag = DEFINED|INTEGER;
v.type = 0;
ret = v_evaluate(&v, expr, error_ok);
*rval = v.val.i;
return ret;
}
/*
* parse and evaluate expression, storing result in vp.
*/
int
v_evaluate(vp, expr, error_ok)
struct tbl *vp;
const char *expr;
volatile int error_ok;
{
struct tbl *v;
Expr_state curstate;
Expr_state * const es = &curstate;
int i;
/* save state to allow recursive calls */
curstate.expression = curstate.tokp = expr;
curstate.noassign = 0;
curstate.evaling = (struct tbl *) 0;
newenv(E_ERRH);
i = ksh_sigsetjmp(e->jbuf, 0);
if (i) {
/* Clear EXPRINEVAL in of any variables we were playing with */
if (curstate.evaling)
curstate.evaling->flag &= ~EXPRINEVAL;
quitenv();
if (i == LAEXPR) {
if (error_ok == KSH_RETURN_ERROR)
return 0;
errorf("%s", null);
}
unwind(i);
/*NOTREACHED*/
}
token(es);
#if 1 /* ifdef-out to disallow empty expressions to be treated as 0 */
if (es->tok == END) {
es->tok = LIT;
es->val = tempvar();
}
#endif /* 0 */
v = intvar(es, evalexpr(es, MAX_PREC));
if (es->tok != END)
evalerr(es, ET_UNEXPECTED, (char *) 0);
if (vp->flag & INTEGER)
setint_v(vp, v);
else
/* can fail if readonly */
setstr(vp, str_val(v), error_ok);
quitenv();
return 1;
}
static void
evalerr(es, type, str)
Expr_state *es;
enum error_type type;
const char *str;
{
char tbuf[2];
const char *s;
switch (type) {
case ET_UNEXPECTED:
switch (es->tok) {
case VAR:
s = es->val->name;
break;
case LIT:
s = str_val(es->val);
break;
case END:
s = "end of expression";
break;
case BAD:
tbuf[0] = *es->tokp;
tbuf[1] = '\0';
s = tbuf;
break;
default:
s = opinfo[(int)es->tok].name;
}
warningf(TRUE, "%s: unexpected `%s'", es->expression, s);
break;
case ET_BADLIT:
warningf(TRUE, "%s: bad number `%s'", es->expression, str);
break;
case ET_RECURSIVE:
warningf(TRUE, "%s: expression recurses on parameter `%s'",
es->expression, str);
break;
case ET_LVALUE:
warningf(TRUE, "%s: %s requires lvalue",
es->expression, str);
break;
case ET_RDONLY:
warningf(TRUE, "%s: %s applied to read only variable",
es->expression, str);
break;
default: /* keep gcc happy */
case ET_STR:
warningf(TRUE, "%s: %s", es->expression, str);
break;
}
unwind(LAEXPR);
}
static struct tbl *
evalexpr(es, prec)
Expr_state *es;
enum prec prec;
{
struct tbl *vl, UNINITIALIZED(*vr), *vasn;
enum token op;
long UNINITIALIZED(res);
if (prec == P_PRIMARY) {
op = es->tok;
if (op == O_BNOT || op == O_LNOT || op == O_MINUS
|| op == O_PLUS)
{
token(es);
vl = intvar(es, evalexpr(es, P_PRIMARY));
if (op == O_BNOT)
vl->val.i = ~vl->val.i;
else if (op == O_LNOT)
vl->val.i = !vl->val.i;
else if (op == O_MINUS)
vl->val.i = -vl->val.i;
/* op == O_PLUS is a no-op */
} else if (op == OPEN_PAREN) {
token(es);
vl = evalexpr(es, MAX_PREC);
if (es->tok != CLOSE_PAREN)
evalerr(es, ET_STR, "missing )");
token(es);
} else if (op == O_PLUSPLUS || op == O_MINUSMINUS) {
token(es);
vl = do_ppmm(es, op, es->val, TRUE);
token(es);
} else if (op == VAR || op == LIT) {
vl = es->val;
token(es);
} else {
evalerr(es, ET_UNEXPECTED, (char *) 0);
/*NOTREACHED*/
}
if (es->tok == O_PLUSPLUS || es->tok == O_MINUSMINUS) {
vl = do_ppmm(es, es->tok, vl, FALSE);
token(es);
}
return vl;
}
vl = evalexpr(es, ((int) prec) - 1);
for (op = es->tok; IS_BINOP(op) && opinfo[(int) op].prec == prec;
op = es->tok)
{
token(es);
vasn = vl;
if (op != O_ASN) /* vl may not have a value yet */
vl = intvar(es, vl);
if (IS_ASSIGNOP(op)) {
assign_check(es, op, vasn);
vr = intvar(es, evalexpr(es, P_ASSIGN));
} else if (op != O_TERN && op != O_LAND && op != O_LOR)
vr = intvar(es, evalexpr(es, ((int) prec) - 1));
if ((op == O_DIV || op == O_MOD || op == O_DIVASN
|| op == O_MODASN) && vr->val.i == 0)
{
if (es->noassign)
vr->val.i = 1;
else
evalerr(es, ET_STR, "zero divisor");
}
switch ((int) op) {
case O_TIMES:
case O_TIMESASN:
res = vl->val.i * vr->val.i;
break;
case O_DIV:
case O_DIVASN:
res = vl->val.i / vr->val.i;
break;
case O_MOD:
case O_MODASN:
res = vl->val.i % vr->val.i;
break;
case O_PLUS:
case O_PLUSASN:
res = vl->val.i + vr->val.i;
break;
case O_MINUS:
case O_MINUSASN:
res = vl->val.i - vr->val.i;
break;
case O_LSHIFT:
case O_LSHIFTASN:
res = vl->val.i << vr->val.i;
break;
case O_RSHIFT:
case O_RSHIFTASN:
res = vl->val.i >> vr->val.i;
break;
case O_LT:
res = vl->val.i < vr->val.i;
break;
case O_LE:
res = vl->val.i <= vr->val.i;
break;
case O_GT:
res = vl->val.i > vr->val.i;
break;
case O_GE:
res = vl->val.i >= vr->val.i;
break;
case O_EQ:
res = vl->val.i == vr->val.i;
break;
case O_NE:
res = vl->val.i != vr->val.i;
break;
case O_BAND:
case O_BANDASN:
res = vl->val.i & vr->val.i;
break;
case O_BXOR:
case O_BXORASN:
res = vl->val.i ^ vr->val.i;
break;
case O_BOR:
case O_BORASN:
res = vl->val.i | vr->val.i;
break;
case O_LAND:
if (!vl->val.i)
es->noassign++;
vr = intvar(es, evalexpr(es, ((int) prec) - 1));
res = vl->val.i && vr->val.i;
if (!vl->val.i)
es->noassign--;
break;
case O_LOR:
if (vl->val.i)
es->noassign++;
vr = intvar(es, evalexpr(es, ((int) prec) - 1));
res = vl->val.i || vr->val.i;
if (vl->val.i)
es->noassign--;
break;
case O_TERN:
{
int ex = vl->val.i != 0;
if (!ex)
es->noassign++;
vl = evalexpr(es, MAX_PREC);
if (!ex)
es->noassign--;
if (es->tok != CTERN)
evalerr(es, ET_STR, "missing :");
token(es);
if (ex)
es->noassign++;
vr = evalexpr(es, P_TERN);
if (ex)
es->noassign--;
vl = ex ? vl : vr;
}
break;
case O_ASN:
res = vr->val.i;
break;
case O_COMMA:
res = vr->val.i;
break;
}
if (IS_ASSIGNOP(op)) {
vr->val.i = res;
if (vasn->flag & INTEGER)
setint_v(vasn, vr);
else
setint(vasn, res);
vl = vr;
} else if (op != O_TERN)
vl->val.i = res;
}
return vl;
}
static void
token(es)
Expr_state *es;
{
const char *cp;
int c;
char *tvar;
/* skip white space */
for (cp = es->tokp; (c = *cp), isspace((unsigned char)c); cp++)
;
es->tokp = cp;
if (c == '\0')
es->tok = END;
else if (letter(c)) {
for (; letnum(c); c = *cp)
cp++;
if (c == '[') {
int len;
len = array_ref_len(cp);
if (len == 0)
evalerr(es, ET_STR, "missing ]");
cp += len;
}
#ifdef KSH
else if (c == '(' /*)*/ ) {
/* todo: add math functions (all take single argument):
* abs acos asin atan cos cosh exp int log sin sinh sqrt
* tan tanh
*/
;
}
#endif /* KSH */
if (es->noassign) {
es->val = tempvar();
es->val->flag |= EXPRLVALUE;
} else {
tvar = str_nsave(es->tokp, cp - es->tokp, ATEMP);
es->val = global(tvar);
afree(tvar, ATEMP);
}
es->tok = VAR;
} else if (digit(c)) {
for (; c != '_' && (letnum(c) || c == '#'); c = *cp++)
;
tvar = str_nsave(es->tokp, --cp - es->tokp, ATEMP);
es->val = tempvar();
es->val->flag &= ~INTEGER;
es->val->type = 0;
es->val->val.s = tvar;
if (setint_v(es->val, es->val) == NULL)
evalerr(es, ET_BADLIT, tvar);
afree(tvar, ATEMP);
es->tok = LIT;
} else {
int i, n0;
for (i = 0; (n0 = opinfo[i].name[0]); i++)
if (c == n0
&& strncmp(cp, opinfo[i].name, opinfo[i].len) == 0)
{
es->tok = (enum token) i;
cp += opinfo[i].len;
break;
}
if (!n0)
es->tok = BAD;
}
es->tokp = cp;
}
/* Do a ++ or -- operation */
static struct tbl *
do_ppmm(es, op, vasn, is_prefix)
Expr_state *es;
enum token op;
struct tbl *vasn;
bool_t is_prefix;
{
struct tbl *vl;
int oval;
assign_check(es, op, vasn);
vl = intvar(es, vasn);
oval = op == O_PLUSPLUS ? vl->val.i++ : vl->val.i--;
if (vasn->flag & INTEGER)
setint_v(vasn, vl);
else
setint(vasn, vl->val.i);
if (!is_prefix) /* undo the inc/dec */
vl->val.i = oval;
return vl;
}
static void
assign_check(es, op, vasn)
Expr_state *es;
enum token op;
struct tbl *vasn;
{
if (vasn->name[0] == '\0' && !(vasn->flag & EXPRLVALUE))
evalerr(es, ET_LVALUE, opinfo[(int) op].name);
else if (vasn->flag & RDONLY)
evalerr(es, ET_RDONLY, opinfo[(int) op].name);
}
static struct tbl *
tempvar()
{
register struct tbl *vp;
vp = (struct tbl*) alloc(sizeof(struct tbl), ATEMP);
vp->flag = ISSET|INTEGER;
vp->type = 0;
vp->areap = ATEMP;
vp->val.i = 0;
vp->name[0] = '\0';
return vp;
}
/* cast (string) variable to temporary integer variable */
static struct tbl *
intvar(es, vp)
Expr_state *es;
struct tbl *vp;
{
struct tbl *vq;
/* try to avoid replacing a temp var with another temp var */
if (vp->name[0] == '\0'
&& (vp->flag & (ISSET|INTEGER|EXPRLVALUE)) == (ISSET|INTEGER))
return vp;
vq = tempvar();
if (setint_v(vq, vp) == NULL) {
if (vp->flag & EXPRINEVAL)
evalerr(es, ET_RECURSIVE, vp->name);
es->evaling = vp;
vp->flag |= EXPRINEVAL;
v_evaluate(vq, str_val(vp), KSH_UNWIND_ERROR);
vp->flag &= ~EXPRINEVAL;
es->evaling = (struct tbl *) 0;
}
return vq;
}

1229
bin/ksh/history.c Normal file

File diff suppressed because it is too large Load Diff

568
bin/ksh/io.c Normal file
View File

@@ -0,0 +1,568 @@
/* $NetBSD: io.c,v 1.9 2005/06/26 19:09:00 christos Exp $ */
/*
* shell buffered IO and formatted output
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: io.c,v 1.9 2005/06/26 19:09:00 christos Exp $");
#endif
#include <ctype.h>
#include "sh.h"
#include "ksh_stat.h"
static int initio_done;
/*
* formatted output functions
*/
/* A shell error occurred (eg, syntax error, etc.) */
void
#ifdef HAVE_PROTOTYPES
errorf(const char *fmt, ...)
#else
errorf(fmt, va_alist)
const char *fmt;
va_dcl
#endif
{
va_list va;
shl_stdout_ok = 0; /* debugging: note that stdout not valid */
exstat = 1;
if (*fmt) {
error_prefix(TRUE);
SH_VA_START(va, fmt);
shf_vfprintf(shl_out, fmt, va);
va_end(va);
shf_putchar('\n', shl_out);
}
shf_flush(shl_out);
unwind(LERROR);
}
/* like errorf(), but no unwind is done */
void
#ifdef HAVE_PROTOTYPES
warningf(int fileline, const char *fmt, ...)
#else
warningf(fileline, fmt, va_alist)
int fileline;
const char *fmt;
va_dcl
#endif
{
va_list va;
error_prefix(fileline);
SH_VA_START(va, fmt);
shf_vfprintf(shl_out, fmt, va);
va_end(va);
shf_putchar('\n', shl_out);
shf_flush(shl_out);
}
/* Used by built-in utilities to prefix shell and utility name to message
* (also unwinds environments for special builtins).
*/
void
#ifdef HAVE_PROTOTYPES
bi_errorf(const char *fmt, ...)
#else
bi_errorf(fmt, va_alist)
const char *fmt;
va_dcl
#endif
{
va_list va;
shl_stdout_ok = 0; /* debugging: note that stdout not valid */
exstat = 1;
if (*fmt) {
error_prefix(TRUE);
/* not set when main() calls parse_args() */
if (builtin_argv0)
shf_fprintf(shl_out, "%s: ", builtin_argv0);
SH_VA_START(va, fmt);
shf_vfprintf(shl_out, fmt, va);
va_end(va);
shf_putchar('\n', shl_out);
}
shf_flush(shl_out);
/* POSIX special builtins and ksh special builtins cause
* non-interactive shells to exit.
* XXX odd use of KEEPASN; also may not want LERROR here
*/
if ((builtin_flag & SPEC_BI)
|| (Flag(FPOSIX) && (builtin_flag & KEEPASN)))
{
builtin_argv0 = (char *) 0;
unwind(LERROR);
}
}
/* Called when something that shouldn't happen does */
void
#ifdef HAVE_PROTOTYPES
internal_errorf(int jump, const char *fmt, ...)
#else
internal_errorf(jump, fmt, va_alist)
int jump;
const char *fmt;
va_dcl
#endif
{
va_list va;
error_prefix(TRUE);
shf_fprintf(shl_out, "internal error: ");
SH_VA_START(va, fmt);
shf_vfprintf(shl_out, fmt, va);
va_end(va);
shf_putchar('\n', shl_out);
shf_flush(shl_out);
if (jump)
unwind(LERROR);
}
/* used by error reporting functions to print "ksh: .kshrc[25]: " */
void
error_prefix(fileline)
int fileline;
{
/* Avoid foo: foo[2]: ... */
if (!fileline || !source || !source->file
|| strcmp(source->file, kshname) != 0)
shf_fprintf(shl_out, "%s: ", kshname + (*kshname == '-'));
if (fileline && source && source->file != NULL) {
shf_fprintf(shl_out, "%s[%d]: ", source->file,
source->errline > 0 ? source->errline : source->line);
source->errline = 0;
}
}
/* printf to shl_out (stderr) with flush */
void
#ifdef HAVE_PROTOTYPES
shellf(const char *fmt, ...)
#else
shellf(fmt, va_alist)
const char *fmt;
va_dcl
#endif
{
va_list va;
if (!initio_done) /* shl_out may not be set up yet... */
return;
SH_VA_START(va, fmt);
shf_vfprintf(shl_out, fmt, va);
va_end(va);
shf_flush(shl_out);
}
/* printf to shl_stdout (stdout) */
void
#ifdef HAVE_PROTOTYPES
shprintf(const char *fmt, ...)
#else
shprintf(fmt, va_alist)
const char *fmt;
va_dcl
#endif
{
va_list va;
if (!shl_stdout_ok)
internal_errorf(1, "shl_stdout not valid");
SH_VA_START(va, fmt);
shf_vfprintf(shl_stdout, fmt, va);
va_end(va);
}
#ifdef KSH_DEBUG
static struct shf *kshdebug_shf;
void
kshdebug_init_()
{
if (kshdebug_shf)
shf_close(kshdebug_shf);
kshdebug_shf = shf_open("/tmp/ksh-debug.log",
O_WRONLY|O_APPEND|O_CREAT, 0600,
SHF_WR|SHF_MAPHI);
if (kshdebug_shf) {
shf_fprintf(kshdebug_shf, "\nNew shell[pid %d]\n", getpid());
shf_flush(kshdebug_shf);
}
}
/* print to debugging log */
void
# ifdef HAVE_PROTOTYPES
kshdebug_printf_(const char *fmt, ...)
# else
kshdebug_printf_(fmt, va_alist)
const char *fmt;
va_dcl
# endif
{
va_list va;
if (!kshdebug_shf)
return;
SH_VA_START(va, fmt);
shf_fprintf(kshdebug_shf, "[%d] ", getpid());
shf_vfprintf(kshdebug_shf, fmt, va);
va_end(va);
shf_flush(kshdebug_shf);
}
void
kshdebug_dump_(str, mem, nbytes)
const char *str;
const void *mem;
int nbytes;
{
int i, j;
int nprow = 16;
if (!kshdebug_shf)
return;
shf_fprintf(kshdebug_shf, "[%d] %s:\n", getpid(), str);
for (i = 0; i < nbytes; i += nprow) {
char c = '\t';
for (j = 0; j < nprow && i + j < nbytes; j++) {
shf_fprintf(kshdebug_shf, "%c%02x",
c, ((const unsigned char *) mem)[i + j]);
c = ' ';
}
shf_fprintf(kshdebug_shf, "\n");
}
shf_flush(kshdebug_shf);
}
#endif /* KSH_DEBUG */
/* test if we can seek backwards fd (returns 0 or SHF_UNBUF) */
int
can_seek(fd)
int fd;
{
struct stat statb;
return fstat(fd, &statb) == 0 && !S_ISREG(statb.st_mode) ?
SHF_UNBUF : 0;
}
struct shf shf_iob[3];
void
initio()
{
shf_fdopen(1, SHF_WR, shl_stdout); /* force buffer allocation */
shf_fdopen(2, SHF_WR, shl_out);
shf_fdopen(2, SHF_WR, shl_spare); /* force buffer allocation */
initio_done = 1;
kshdebug_init();
}
/* A dup2() with error checking */
int
ksh_dup2(ofd, nfd, errok)
int ofd;
int nfd;
int errok;
{
int ret = dup2(ofd, nfd);
if (ret < 0 && errno != EBADF && !errok)
errorf("too many files open in shell");
#ifdef DUP2_BROKEN
/* Ultrix systems like to preserve the close-on-exec flag */
if (ret >= 0)
(void) fcntl(nfd, F_SETFD, 0);
#endif /* DUP2_BROKEN */
return ret;
}
/*
* move fd from user space (0<=fd<10) to shell space (fd>=10),
* set close-on-exec flag.
*/
int
savefd(fd, noclose)
int fd;
int noclose;
{
int nfd;
if (fd < FDBASE) {
nfd = ksh_dupbase(fd, FDBASE);
if (nfd < 0) {
if (errno == EBADF)
return -1;
else
errorf("too many files open in shell");
}
if (!noclose)
close(fd);
} else
nfd = fd;
fd_clexec(nfd);
return nfd;
}
void
restfd(fd, ofd)
int fd, ofd;
{
if (fd == 2)
shf_flush(&shf_iob[fd]);
if (ofd < 0) /* original fd closed */
close(fd);
else if (fd != ofd) {
ksh_dup2(ofd, fd, TRUE); /* XXX: what to do if this fails? */
close(ofd);
}
}
void
openpipe(pv)
register int *pv;
{
if (pipe(pv) < 0)
errorf("can't create pipe - try again");
pv[0] = savefd(pv[0], 0);
pv[1] = savefd(pv[1], 0);
}
void
closepipe(pv)
register int *pv;
{
close(pv[0]);
close(pv[1]);
}
/* Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn
* a string (the X in 2>&X, read -uX, print -uX) into a file descriptor.
*/
int
check_fd(name, mode, emsgp)
char *name;
int mode;
const char **emsgp;
{
int fd, fl;
if (isdigit((unsigned char)name[0]) && !name[1]) {
fd = name[0] - '0';
if ((fl = fcntl(fd = name[0] - '0', F_GETFL, 0)) < 0) {
if (emsgp)
*emsgp = "bad file descriptor";
return -1;
}
fl &= O_ACCMODE;
#ifdef OS2
if (mode == W_OK ) {
if (setmode(fd, O_TEXT) == -1) {
if (emsgp)
*emsgp = "couldn't set write mode";
return -1;
}
} else if (mode == R_OK)
if (setmode(fd, O_BINARY) == -1) {
if (emsgp)
*emsgp = "couldn't set read mode";
return -1;
}
#else /* OS2 */
/* X_OK is a kludge to disable this check for dups (x<&1):
* historical shells never did this check (XXX don't know what
* posix has to say).
*/
if (!(mode & X_OK) && fl != O_RDWR
&& (((mode & R_OK) && fl != O_RDONLY)
|| ((mode & W_OK) && fl != O_WRONLY)))
{
if (emsgp)
*emsgp = (fl == O_WRONLY) ?
"fd not open for reading"
: "fd not open for writing";
return -1;
}
#endif /* OS2 */
return fd;
}
#ifdef KSH
else if (name[0] == 'p' && !name[1])
return coproc_getfd(mode, emsgp);
#endif /* KSH */
if (emsgp)
*emsgp = "illegal file descriptor name";
return -1;
}
#ifdef KSH
/* Called once from main */
void
coproc_init()
{
coproc.read = coproc.readw = coproc.write = -1;
coproc.njobs = 0;
coproc.id = 0;
}
/* Called by c_read() when eof is read - close fd if it is the co-process fd */
void
coproc_read_close(fd)
int fd;
{
if (coproc.read >= 0 && fd == coproc.read) {
coproc_readw_close(fd);
close(coproc.read);
coproc.read = -1;
}
}
/* Called by c_read() and by iosetup() to close the other side of the
* read pipe, so reads will actually terminate.
*/
void
coproc_readw_close(fd)
int fd;
{
if (coproc.readw >= 0 && coproc.read >= 0 && fd == coproc.read) {
close(coproc.readw);
coproc.readw = -1;
}
}
/* Called by c_print when a write to a fd fails with EPIPE and by iosetup
* when co-process input is dup'd
*/
void
coproc_write_close(fd)
int fd;
{
if (coproc.write >= 0 && fd == coproc.write) {
close(coproc.write);
coproc.write = -1;
}
}
/* Called to check for existence of/value of the co-process file descriptor.
* (Used by check_fd() and by c_read/c_print to deal with -p option).
*/
int
coproc_getfd(mode, emsgp)
int mode;
const char **emsgp;
{
int fd = (mode & R_OK) ? coproc.read : coproc.write;
if (fd >= 0)
return fd;
if (emsgp)
*emsgp = "no coprocess";
return -1;
}
/* called to close file descriptors related to the coprocess (if any)
* Should be called with SIGCHLD blocked.
*/
void
coproc_cleanup(reuse)
int reuse;
{
/* This to allow co-processes to share output pipe */
if (!reuse || coproc.readw < 0 || coproc.read < 0) {
if (coproc.read >= 0) {
close(coproc.read);
coproc.read = -1;
}
if (coproc.readw >= 0) {
close(coproc.readw);
coproc.readw = -1;
}
}
if (coproc.write >= 0) {
close(coproc.write);
coproc.write = -1;
}
}
#endif /* KSH */
/*
* temporary files
*/
struct temp *
maketemp(ap, type, tlist)
Area *ap;
Temp_type type;
struct temp **tlist;
{
#ifndef __NetBSD__
static unsigned int inc;
#endif
struct temp *tp;
int len;
int fd;
char *pathx;
const char *dir;
dir = tmpdir ? tmpdir : "/tmp";
/* The 20 + 20 is a paranoid worst case for pid/inc */
len = strlen(dir) + 3 + 20 + 20 + 1;
tp = (struct temp *) alloc(sizeof(struct temp) + len, ap);
tp->name = pathx = (char *) &tp[1];
tp->shf = (struct shf *) 0;
tp->type = type;
#ifdef __NetBSD__
shf_snprintf(pathx, len, "%s/shXXXXXXXX", dir);
fd = mkstemp(pathx);
if (fd >= 0)
tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0);
#else
while (1) {
/* Note that temp files need to fit 8.3 DOS limits */
shf_snprintf(pathx, len, "%s/sh%05u.%03x",
dir, (unsigned) procpid, inc++);
/* Mode 0600 to be paranoid, O_TRUNC in case O_EXCL isn't
* really there.
*/
fd = open(pathx, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600);
if (fd >= 0) {
tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0);
break;
}
if (errno != EINTR
#ifdef EEXIST
&& errno != EEXIST
#endif /* EEXIST */
#ifdef EISDIR
&& errno != EISDIR
#endif /* EISDIR */
)
/* Error must be printed by caller: don't know here if
* errorf() or bi_errorf() should be used.
*/
break;
}
#endif /* __NetBSD__ */
tp->pid = procpid;
tp->next = *tlist;
*tlist = tp;
return tp;
}

1860
bin/ksh/jobs.c Normal file

File diff suppressed because it is too large Load Diff

3617
bin/ksh/ksh.Man Normal file

File diff suppressed because it is too large Load Diff

27
bin/ksh/ksh_dir.h Normal file
View File

@@ -0,0 +1,27 @@
/* $NetBSD: ksh_dir.h,v 1.2 1997/01/12 19:11:59 tls Exp $ */
/* Wrapper around the ugly dir includes/ifdefs */
/* $NetBSD: ksh_dir.h,v 1.2 1997/01/12 19:11:59 tls Exp $ */
#if defined(HAVE_DIRENT_H)
# include <dirent.h>
# define NLENGTH(dirent) (strlen(dirent->d_name))
#else
# define dirent direct
# define NLENGTH(dirent) (dirent->d_namlen)
# ifdef HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif /* HAVE_SYS_NDIR_H */
# ifdef HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif /* HAVE_SYSDIR_H */
# ifdef HAVE_NDIR_H
# include <ndir.h>
# endif /* HAVE_NDIR_H */
#endif /* HAVE_DIRENT_H */
#ifdef OPENDIR_DOES_NONDIR
extern DIR *ksh_opendir ARGS((const char *d));
#else /* OPENDIR_DOES_NONDIR */
# define ksh_opendir(d) opendir(d)
#endif /* OPENDIR_DOES_NONDIR */

25
bin/ksh/ksh_limval.h Normal file
View File

@@ -0,0 +1,25 @@
/* $NetBSD: ksh_limval.h,v 1.2 1997/01/12 19:11:59 tls Exp $ */
/* Wrapper around the values.h/limits.h includes/ifdefs */
/* $NetBSD: ksh_limval.h,v 1.2 1997/01/12 19:11:59 tls Exp $ */
#ifdef HAVE_VALUES_H
# include <values.h>
#endif /* HAVE_VALUES_H */
/* limits.h is included in sh.h */
#ifndef DMAXEXP
# define DMAXEXP 128 /* should be big enough */
#endif
#ifndef BITSPERBYTE
# ifdef CHAR_BIT
# define BITSPERBYTE CHAR_BIT
# else
# define BITSPERBYTE 8 /* probably true.. */
# endif
#endif
#ifndef BITS
# define BITS(t) (BITSPERBYTE * sizeof(t))
#endif

60
bin/ksh/ksh_stat.h Normal file
View File

@@ -0,0 +1,60 @@
/* $NetBSD: ksh_stat.h,v 1.2 1997/01/12 19:12:00 tls Exp $ */
/* Wrapper around the ugly sys/stat includes/ifdefs */
/* $NetBSD: ksh_stat.h,v 1.2 1997/01/12 19:12:00 tls Exp $ */
/* assumes <sys/types.h> already included */
#include <sys/stat.h>
#ifndef HAVE_LSTAT
# define lstat(path, buf) stat(path, buf)
#endif /* HAVE_LSTAT */
#ifdef STAT_MACROS_BROKEN
# undef S_ISREG
# undef S_ISDIR
# undef S_ISCHR
# undef S_ISBLK
# undef S_ISFIFO
# undef S_ISSOCK
# undef S_ISLNK
#endif /* STAT_MACROS_BROKEN */
#if !defined(S_ISREG) && defined(S_IFREG)
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#endif /* S_ISREG */
#if !defined(S_ISDIR) && defined(S_IFDIR)
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif /* S_ISDIR */
#if !defined(S_ISCHR) && defined(S_IFCHR)
# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
#endif /* S_ISCHR */
#if !defined(S_ISBLK) && defined(S_IFBLK)
# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
#endif /* S_ISBLK */
#if !defined(S_ISFIFO) && defined(S_IFIFO)
# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
#endif /* S_ISFIFO */
#if !defined(S_ISLNK) && defined(S_IFLNK)
# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
#endif /* S_ISLNK */
#if !defined(S_ISSOCK) && defined(S_IFSOCK)
# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
#endif /* S_ISSOCK */
#if !defined(S_ISCDF) && defined(S_CDF)
# define S_ISCDF(m) (S_ISDIR(m) && ((m) & S_CDF))
#endif /* S_ISSOCK */
#ifndef S_ISVTX
# define S_ISVTX 01000 /* sticky bit */
#endif /* S_ISVTX */
#ifndef S_IXUSR
# define S_IXUSR 00100 /* user execute bit */
#endif /* S_IXUSR */
#ifndef S_IXGRP
# define S_IXGRP 00010 /* user execute bit */
#endif /* S_IXGRP */
#ifndef S_IXOTH
# define S_IXOTH 00001 /* user execute bit */
#endif /* S_IXOTH */

27
bin/ksh/ksh_time.h Normal file
View File

@@ -0,0 +1,27 @@
/* $NetBSD: ksh_time.h,v 1.2 1997/01/12 19:12:01 tls Exp $ */
#ifndef KSH_TIME_H
# define KSH_TIME_H
/* Wrapper around the ugly time.h,sys/time.h includes/ifdefs */
/* $NetBSD: ksh_time.h,v 1.2 1997/01/12 19:12:01 tls Exp $ */
#ifdef TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else /* TIME_WITH_SYS_TIME */
# ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif /* TIME_WITH_SYS_TIME */
#ifndef TIME_DECLARED
extern time_t time ARGS((time_t *));
#endif
#ifndef CLK_TCK
# define CLK_TCK 60 /* 60HZ */
#endif
#endif /* KSH_TIME_H */

20
bin/ksh/ksh_times.h Normal file
View File

@@ -0,0 +1,20 @@
/* $NetBSD: ksh_times.h,v 1.2 1997/01/12 19:12:02 tls Exp $ */
#ifndef KSH_TIMES_H
# define KSH_TIMES_H
/* Needed for clock_t on some systems (ie, NeXT in non-posix mode) */
#include "ksh_time.h"
#include <sys/times.h>
#ifdef TIMES_BROKEN
extern clock_t ksh_times ARGS((struct tms *));
#else /* TIMES_BROKEN */
# define ksh_times times
#endif /* TIMES_BROKEN */
#ifdef HAVE_TIMES
extern clock_t times ARGS((struct tms *));
#endif /* HAVE_TIMES */
#endif /* KSH_TIMES_H */

52
bin/ksh/ksh_wait.h Normal file
View File

@@ -0,0 +1,52 @@
/* $NetBSD: ksh_wait.h,v 1.2 1997/01/12 19:12:03 tls Exp $ */
/* Wrapper around the ugly sys/wait includes/ifdefs */
/* $NetBSD: ksh_wait.h,v 1.2 1997/01/12 19:12:03 tls Exp $ */
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#ifndef POSIX_SYS_WAIT
/* Get rid of system macros (which probably use union wait) */
# undef WIFCORED
# undef WIFEXITED
# undef WEXITSTATUS
# undef WIFSIGNALED
# undef WTERMSIG
# undef WIFSTOPPED
# undef WSTOPSIG
#endif /* POSIX_SYS_WAIT */
typedef int WAIT_T;
#ifndef WIFCORED
# define WIFCORED(s) ((s) & 0x80)
#endif
#define WSTATUS(s) (s)
#ifndef WIFEXITED
# define WIFEXITED(s) (((s) & 0xff) == 0)
#endif
#ifndef WEXITSTATUS
# define WEXITSTATUS(s) (((s) >> 8) & 0xff)
#endif
#ifndef WIFSIGNALED
# define WIFSIGNALED(s) (((s) & 0xff) != 0 && ((s) & 0xff) != 0x7f)
#endif
#ifndef WTERMSIG
# define WTERMSIG(s) ((s) & 0x7f)
#endif
#ifndef WIFSTOPPED
# define WIFSTOPPED(s) (((s) & 0xff) == 0x7f)
#endif
#ifndef WSTOPSIG
# define WSTOPSIG(s) (((s) >> 8) & 0xff)
#endif
#if !defined(HAVE_WAITPID) && defined(HAVE_WAIT3)
/* always used with p == -1 */
# define ksh_waitpid(p, s, o) wait3((s), (o), (struct rusage *) 0)
#else /* !HAVE_WAITPID && HAVE_WAIT3 */
# define ksh_waitpid(p, s, o) waitpid((p), (s), (o))
#endif /* !HAVE_WAITPID && HAVE_WAIT3 */

1398
bin/ksh/lex.c Normal file

File diff suppressed because it is too large Load Diff

133
bin/ksh/lex.h Normal file
View File

@@ -0,0 +1,133 @@
/* $NetBSD: lex.h,v 1.7 2005/09/11 22:16:00 christos Exp $ */
/*
* Source input, lexer and parser
*/
/* $Id: lex.h,v 1.7 2005/09/11 22:16:00 christos Exp $ */
#define IDENT 64
typedef struct source Source;
struct source {
const char *str; /* input pointer */
int type; /* input type */
const char *start; /* start of current buffer */
union {
char **strv; /* string [] */
struct shf *shf; /* shell file */
struct tbl *tblp; /* alias (SALIAS) */
char *freeme; /* also for SREREAD */
} u;
char ugbuf[2]; /* buffer for ungetsc() (SREREAD) and
* alias (SALIAS) */
int line; /* line number */
int errline; /* line the error occurred on (0 if not set) */
const char *file; /* input file name */
int flags; /* SF_* */
Area *areap;
XString xs; /* input buffer */
Source *next; /* stacked source */
};
/* Source.type values */
#define SEOF 0 /* input EOF */
#define SFILE 1 /* file input */
#define SSTDIN 2 /* read stdin */
#define SSTRING 3 /* string */
#define SWSTR 4 /* string without \n */
#define SWORDS 5 /* string[] */
#define SWORDSEP 6 /* string[] separator */
#define SALIAS 7 /* alias expansion */
#define SREREAD 8 /* read ahead to be re-scanned */
/* Source.flags values */
#define SF_ECHO BIT(0) /* echo input to shlout */
#define SF_ALIAS BIT(1) /* faking space at end of alias */
#define SF_ALIASEND BIT(2) /* faking space at end of alias */
#define SF_TTY BIT(3) /* type == SSTDIN & it is a tty */
/*
* states while lexing word
*/
#define SBASE 0 /* outside any lexical constructs */
#define SWORD 1 /* implicit quoting for substitute() */
#ifdef KSH
#define SLETPAREN 2 /* inside (( )), implicit quoting */
#endif /* KSH */
#define SSQUOTE 3 /* inside '' */
#define SDQUOTE 4 /* inside "" */
#define SBRACE 5 /* inside ${} */
#define SCSPAREN 6 /* inside $() */
#define SBQUOTE 7 /* inside `` */
#define SASPAREN 8 /* inside $(( )) */
#define SHEREDELIM 9 /* parsing <<,<<- delimiter */
#define SHEREDQUOTE 10 /* parsing " in <<,<<- delimiter */
#define SPATTERN 11 /* parsing *(...|...) pattern (*+?@!) */
#define STBRACE 12 /* parsing ${..[#%]..} */
typedef union {
int i;
char *cp;
char **wp;
struct op *o;
struct ioword *iop;
} YYSTYPE;
/* If something is added here, add it to tokentab[] in syn.c as well */
#define LWORD 256
#define LOGAND 257 /* && */
#define LOGOR 258 /* || */
#define BREAK 259 /* ;; */
#define IF 260
#define THEN 261
#define ELSE 262
#define ELIF 263
#define FI 264
#define CASE 265
#define ESAC 266
#define FOR 267
#define SELECT 268
#define WHILE 269
#define UNTIL 270
#define DO 271
#define DONE 272
#define IN 273
#define FUNCTION 274
#define TIME 275
#define REDIR 276
#ifdef KSH
#define MDPAREN 277 /* (( )) */
#endif /* KSH */
#define BANG 278 /* ! */
#define DBRACKET 279 /* [[ .. ]] */
#define COPROC 280 /* |& */
#define YYERRCODE 300
/* flags to yylex */
#define CONTIN BIT(0) /* skip new lines to complete command */
#define ONEWORD BIT(1) /* single word for substitute() */
#define ALIAS BIT(2) /* recognize alias */
#define KEYWORD BIT(3) /* recognize keywords */
#define LETEXPR BIT(4) /* get expression inside (( )) */
#define VARASN BIT(5) /* check for var=word */
#define ARRAYVAR BIT(6) /* parse x[1 & 2] as one word */
#define ESACONLY BIT(7) /* only accept esac keyword */
#define CMDWORD BIT(8) /* parsing simple command (alias related) */
#define HEREDELIM BIT(9) /* parsing <<,<<- delimiter */
#define HEREDOC BIT(10) /* parsing heredoc */
#define HERES 10 /* max << in line */
EXTERN Source *source; /* yyparse/yylex source */
EXTERN YYSTYPE yylval; /* result from yylex */
EXTERN struct ioword *heres [HERES], **herep;
EXTERN char ident [IDENT+1];
#ifdef HISTORY
# define HISTORYSIZE 128 /* size of saved history */
EXTERN char **histlist; /* saved commands */
EXTERN char **histptr; /* last history item */
EXTERN int histsize; /* history size */
#endif /* HISTORY */

202
bin/ksh/mail.c Normal file
View File

@@ -0,0 +1,202 @@
/* $NetBSD: mail.c,v 1.5 2006/01/15 18:16:30 jschauma Exp $ */
/*
* Mailbox checking code by Robert J. Gibson, adapted for PD ksh by
* John R. MacMillan
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: mail.c,v 1.5 2006/01/15 18:16:30 jschauma Exp $");
#endif
#include "config.h"
#ifdef KSH
#include "sh.h"
#include "ksh_stat.h"
#include "ksh_time.h"
#define MBMESSAGE "You have mail in $_"
typedef struct mbox {
struct mbox *mb_next; /* next mbox in list */
char *mb_path; /* path to mail file */
char *mb_msg; /* to announce arrival of new mail */
time_t mb_mtime; /* mtime of mail file */
} mbox_t;
/*
* $MAILPATH is a linked list of mboxes. $MAIL is a treated as a
* special case of $MAILPATH, where the list has only one node. The
* same list is used for both since they are exclusive.
*/
static mbox_t *mplist;
static mbox_t mbox;
static time_t mlastchkd; /* when mail was last checked */
static time_t mailcheck_interval;
static void munset ARGS((mbox_t *mlist)); /* free mlist and mval */
static mbox_t * mballoc ARGS((char *p, char *m)); /* allocate a new mbox */
static void mprintit ARGS((mbox_t *mbp));
void
mcheck()
{
register mbox_t *mbp;
time_t now;
struct tbl *vp;
struct stat stbuf;
now = time((time_t *) 0);
if (mlastchkd == 0)
mlastchkd = now;
if (now - mlastchkd >= mailcheck_interval) {
mlastchkd = now;
if (mplist)
mbp = mplist;
else if ((vp = global("MAIL")) && (vp->flag & ISSET))
mbp = &mbox;
else
mbp = NULL;
while (mbp) {
if (mbp->mb_path && stat(mbp->mb_path, &stbuf) == 0
&& S_ISREG(stbuf.st_mode))
{
if (stbuf.st_size
&& mbp->mb_mtime != stbuf.st_mtime
&& stbuf.st_atime <= stbuf.st_mtime)
mprintit(mbp);
mbp->mb_mtime = stbuf.st_mtime;
} else {
/*
* Some mail readers remove the mail
* file if all mail is read. If file
* does not exist, assume this is the
* case and set mtime to zero.
*/
mbp->mb_mtime = 0;
}
mbp = mbp->mb_next;
}
}
}
void
mcset(interval)
long interval;
{
mailcheck_interval = interval;
}
void
mbset(p)
register char *p;
{
struct stat stbuf;
if (mbox.mb_msg)
afree((void *)mbox.mb_msg, APERM);
if (mbox.mb_path)
afree((void *)mbox.mb_path, APERM);
/* Save a copy to protect from export (which munges the string) */
mbox.mb_path = str_save(p, APERM);
mbox.mb_msg = NULL;
if (p && stat(p, &stbuf) == 0 && S_ISREG(stbuf.st_mode))
mbox.mb_mtime = stbuf.st_mtime;
else
mbox.mb_mtime = 0;
}
void
mpset(mptoparse)
register char *mptoparse;
{
register mbox_t *mbp;
register char *mpath, *mmsg, *mval;
char *p;
munset( mplist );
mplist = NULL;
mval = str_save(mptoparse, APERM);
while (mval) {
mpath = mval;
if ((mval = strchr(mval, PATHSEP)) != NULL) {
*mval = '\0', mval++;
}
/* POSIX/bourne-shell say file%message */
for (p = mpath; (mmsg = strchr(p, '%')); ) {
/* a literal percent? (POSIXism) */
if (mmsg[-1] == '\\') {
/* use memmove() to avoid overlap problems */
memmove(mmsg - 1, mmsg, strlen(mmsg) + 1);
p = mmsg + 1;
continue;
}
break;
}
/* at&t ksh says file?message */
if (!mmsg && !Flag(FPOSIX))
mmsg = strchr(mpath, '?');
if (mmsg) {
*mmsg = '\0';
mmsg++;
}
mbp = mballoc(mpath, mmsg);
mbp->mb_next = mplist;
mplist = mbp;
}
}
static void
munset(mlist)
register mbox_t *mlist;
{
register mbox_t *mbp;
while (mlist != NULL) {
mbp = mlist;
mlist = mbp->mb_next;
if (!mlist)
afree((void *)mbp->mb_path, APERM);
afree((void *)mbp, APERM);
}
}
static mbox_t *
mballoc(p, m)
char *p;
char *m;
{
struct stat stbuf;
register mbox_t *mbp;
mbp = (mbox_t *)alloc(sizeof(mbox_t), APERM);
mbp->mb_next = NULL;
mbp->mb_path = p;
mbp->mb_msg = m;
if (stat(mbp->mb_path, &stbuf) == 0 && S_ISREG(stbuf.st_mode))
mbp->mb_mtime = stbuf.st_mtime;
else
mbp->mb_mtime = 0;
return(mbp);
}
static void
mprintit( mbp )
mbox_t *mbp;
{
struct tbl *vp;
/* Ignore setstr errors here (arbitrary) */
setstr((vp = local("_", FALSE)), mbp->mb_path, KSH_RETURN_ERROR);
shellf("%s\n", substitute(mbp->mb_msg ? mbp->mb_msg : MBMESSAGE, 0));
unset(vp, 0);
}
#endif /* KSH */

869
bin/ksh/main.c Normal file
View File

@@ -0,0 +1,869 @@
/* $NetBSD: main.c,v 1.15 2011/10/16 17:12:11 joerg Exp $ */
/*
* startup, main loop, environments and error handling
*/
#include <sys/cdefs.h>
#include <locale.h>
#ifndef lint
__RCSID("$NetBSD: main.c,v 1.15 2011/10/16 17:12:11 joerg Exp $");
#endif
#define EXTERN /* define EXTERNs in sh.h */
#include "sh.h"
#include "ksh_stat.h"
#include "ksh_time.h"
extern char **environ;
/*
* global data
*/
static void reclaim ARGS((void));
static void remove_temps ARGS((struct temp *tp));
static int is_restricted ARGS((char *name));
/*
* shell initialization
*/
static const char initifs[] = "IFS= \t\n";
static const char initsubs[] = "${PS2=> } ${PS3=#? } ${PS4=+ }";
static const char version_param[] =
#ifdef KSH
"KSH_VERSION"
#else /* KSH */
"SH_VERSION"
#endif /* KSH */
;
static const char *const initcoms [] = {
"typeset", "-x", "SHELL", "PATH", "HOME", NULL,
"typeset", "-r", version_param, NULL,
"typeset", "-i", "PPID", NULL,
"typeset", "-i", "OPTIND=1", NULL,
#ifdef KSH
"eval", "typeset -i RANDOM MAILCHECK=\"${MAILCHECK-600}\" SECONDS=\"${SECONDS-0}\" TMOUT=\"${TMOUT-0}\"", NULL,
#endif /* KSH */
"alias",
/* Standard ksh aliases */
"hash=alias -t", /* not "alias -t --": hash -r needs to work */
"type=whence -v",
#ifdef JOBS
"stop=kill -STOP",
"suspend=kill -STOP $$",
#endif
#ifdef KSH
"autoload=typeset -fu",
"functions=typeset -f",
# ifdef HISTORY
"history=fc -l",
# endif /* HISTORY */
"integer=typeset -i",
"nohup=nohup ",
"local=typeset",
"r=fc -e -",
#endif /* KSH */
#ifdef KSH
/* Aliases that are builtin commands in at&t */
"login=exec login",
#ifndef __NetBSD__
"newgrp=exec newgrp",
#endif /* __NetBSD__ */
#endif /* KSH */
NULL,
/* this is what at&t ksh seems to track, with the addition of emacs */
"alias", "-tU",
"cat", "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls",
"mail", "make", "mv", "pr", "rm", "sed", "sh", "vi", "who",
NULL,
#ifdef EXTRA_INITCOMS
EXTRA_INITCOMS, NULL,
#endif /* EXTRA_INITCOMS */
NULL
};
int
main(int argc, char *argv[])
{
register int i;
int argi;
Source *s;
struct block *l;
int restricted, errexit;
char **wp;
struct env env;
pid_t ppid;
#ifdef MEM_DEBUG
chmem_set_defaults("ct", 1);
/* chmem_push("+c", 1); */
#endif /* MEM_DEBUG */
#ifdef OS2
setmode (0, O_BINARY);
setmode (1, O_TEXT);
#endif
/* make sure argv[] is sane */
if (!*argv) {
static const char *empty_argv[] = {
"pdksh", (char *) 0
};
argv = (char **)__UNCONST(empty_argv);
argc = 1;
}
kshname = *argv;
ainit(&aperm); /* initialize permanent Area */
/* set up base environment */
memset(&env, 0, sizeof(env));
env.type = E_NONE;
ainit(&env.area);
e = &env;
newblock(); /* set up global l->vars and l->funs */
/* Do this first so output routines (eg, errorf, shellf) can work */
initio();
initvar();
initctypes();
inittraps();
#ifdef KSH
coproc_init();
#endif /* KSH */
/* set up variable and command dictionaries */
tinit(&taliases, APERM, 0);
tinit(&aliases, APERM, 0);
tinit(&homedirs, APERM, 0);
/* define shell keywords */
initkeywords();
/* define built-in commands */
tinit(&builtins, APERM, 64); /* must be 2^n (currently 40 builtins) */
for (i = 0; shbuiltins[i].name != NULL; i++)
builtin(shbuiltins[i].name, shbuiltins[i].func);
for (i = 0; kshbuiltins[i].name != NULL; i++)
builtin(kshbuiltins[i].name, kshbuiltins[i].func);
init_histvec();
def_path = DEFAULT__PATH;
#if defined(HAVE_CONFSTR) && defined(_CS_PATH)
{
size_t len = confstr(_CS_PATH, (char *) 0, 0);
char *new;
if (len > 0) {
confstr(_CS_PATH, new = alloc(len + 1, APERM), len + 1);
def_path = new;
}
}
#endif /* HAVE_CONFSTR && _CS_PATH */
/* Set PATH to def_path (will set the path global variable).
* (import of environment below will probably change this setting).
*/
{
struct tbl *vp = global("PATH");
/* setstr can't fail here */
setstr(vp, def_path, KSH_RETURN_ERROR);
}
/* Turn on nohup by default for now - will change to off
* by default once people are aware of its existence
* (at&t ksh does not have a nohup option - it always sends
* the hup).
*/
Flag(FNOHUP) = 1;
/* Turn on brace expansion by default. At&t ksh's that have
* alternation always have it on. BUT, posix doesn't have
* brace expansion, so set this before setting up FPOSIX
* (change_flag() clears FBRACEEXPAND when FPOSIX is set).
*/
#ifdef BRACE_EXPAND
Flag(FBRACEEXPAND) = 1;
#endif /* BRACE_EXPAND */
/* set posix flag just before environment so that it will have
* exactly the same effect as the POSIXLY_CORRECT environment
* variable. If this needs to be done sooner to ensure correct posix
* operation, an initial scan of the environment will also have
* done sooner.
*/
#ifdef POSIXLY_CORRECT
change_flag(FPOSIX, OF_SPECIAL, 1);
#endif /* POSIXLY_CORRECT */
/* Set edit mode to emacs by default, may be overridden
* by the environment or the user. Also, we want tab completion
* on in vi by default. */
#if defined(EDIT) && defined(EMACS)
change_flag(FEMACS, OF_SPECIAL, 1);
#endif /* EDIT && EMACS */
#if defined(EDIT) && defined(VI)
Flag(FVITABCOMPLETE) = 1;
#endif /* EDIT && VI */
/* import environment */
if (environ != NULL)
for (wp = environ; *wp != NULL; wp++)
typeset(*wp, IMPORT|EXPORT, 0, 0, 0);
kshpid = procpid = getpid();
typeset(initifs, 0, 0, 0, 0); /* for security */
/* assign default shell variable values */
substitute(initsubs, 0);
/* Figure out the current working directory and set $PWD */
{
struct stat s_pwd, s_dot;
struct tbl *pwd_v = global("PWD");
char *pwd = str_val(pwd_v);
char *pwdx = pwd;
/* Try to use existing $PWD if it is valid */
if (!ISABSPATH(pwd)
|| stat(pwd, &s_pwd) < 0 || stat(".", &s_dot) < 0
|| s_pwd.st_dev != s_dot.st_dev
|| s_pwd.st_ino != s_dot.st_ino)
pwdx = (char *) 0;
set_current_wd(pwdx);
if (current_wd[0])
simplify_path(current_wd);
/* Only set pwd if we know where we are or if it had a
* bogus value
*/
if (current_wd[0] || pwd != null)
/* setstr can't fail here */
setstr(pwd_v, current_wd, KSH_RETURN_ERROR);
}
ppid = getppid();
setint(global("PPID"), (long) ppid);
#ifdef KSH
setint(global("RANDOM"), (long) (time((time_t *)0) * kshpid * ppid));
#endif /* KSH */
/* setstr can't fail here */
setstr(global(version_param), ksh_version, KSH_RETURN_ERROR);
/* execute initialization statements */
for (wp = (char**)__UNCONST(initcoms); *wp != NULL; wp++) {
shcomexec(wp);
for (; *wp != NULL; wp++)
;
}
ksheuid = geteuid();
safe_prompt = ksheuid ? "$ " : "# ";
{
struct tbl *vp = global("PS1");
/* Set PS1 if it isn't set, or we are root and prompt doesn't
* contain a #.
*/
if (!(vp->flag & ISSET)
|| (!ksheuid && !strchr(str_val(vp), '#')))
/* setstr can't fail here */
setstr(vp, safe_prompt, KSH_RETURN_ERROR);
}
/* Set this before parsing arguments */
Flag(FPRIVILEGED) = getuid() != ksheuid || getgid() != getegid();
/* this to note if monitor is set on command line (see below) */
Flag(FMONITOR) = 127;
argi = parse_args(argv, OF_CMDLINE, (int *) 0);
if (argi < 0) {
exit(1);
/* NOTREACHED */
}
if (Flag(FCOMMAND)) {
s = pushs(SSTRING, ATEMP);
if (!(s->start = s->str = argv[argi++]))
errorf("-c requires an argument");
if (argv[argi])
kshname = argv[argi++];
} else if (argi < argc && !Flag(FSTDIN)) {
s = pushs(SFILE, ATEMP);
#ifdef OS2
/* a bug in os2 extproc shell processing doesn't
* pass full pathnames so we have to search for it.
* This changes the behavior of 'ksh arg' to search
* the users search path but it can't be helped.
*/
s->file = search(argv[argi++], path, R_OK, (int *) 0);
if (!s->file || !*s->file)
s->file = argv[argi - 1];
#else
s->file = argv[argi++];
#endif /* OS2 */
s->u.shf = shf_open(s->file, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC);
if (s->u.shf == NULL) {
exstat = 127; /* POSIX */
errorf("%s: %s", s->file, strerror(errno));
}
kshname = s->file;
} else {
Flag(FSTDIN) = 1;
s = pushs(SSTDIN, ATEMP);
s->file = "<stdin>";
s->u.shf = shf_fdopen(0, SHF_RD | can_seek(0),
(struct shf *) 0);
if (isatty(0) && isatty(2)) {
Flag(FTALKING) = Flag(FTALKING_I) = 1;
/* The following only if isatty(0) */
s->flags |= SF_TTY;
s->u.shf->flags |= SHF_INTERRUPT;
s->file = (char *) 0;
}
}
/* This bizarreness is mandated by POSIX */
{
struct stat s_stdin;
if (fstat(0, &s_stdin) >= 0 && S_ISCHR(s_stdin.st_mode) &&
Flag(FTALKING))
reset_nonblock(0);
}
/* initialize job control */
i = Flag(FMONITOR) != 127;
Flag(FMONITOR) = 0;
j_init(i);
#ifdef EDIT
/* Do this after j_init(), as tty_fd is not initialized 'til then */
if (Flag(FTALKING))
x_init();
#endif
l = e->loc;
l->argv = &argv[argi - 1];
l->argc = argc - argi;
l->argv[0] = (char *)__UNCONST(kshname);
getopts_reset(1);
/* Disable during .profile/ENV reading */
restricted = Flag(FRESTRICTED);
Flag(FRESTRICTED) = 0;
errexit = Flag(FERREXIT);
Flag(FERREXIT) = 0;
/* Do this before profile/$ENV so that if it causes problems in them,
* user will know why things broke.
*/
if (!current_wd[0] && Flag(FTALKING))
warningf(FALSE, "Cannot determine current working directory");
if (Flag(FLOGIN)) {
#ifdef OS2
char *profile;
/* Try to find a profile - first see if $INIT has a value,
* then try /etc/profile.ksh, then c:/usr/etc/profile.ksh.
*/
if (!Flag(FPRIVILEGED)
&& strcmp(profile = substitute("$INIT/profile.ksh", 0),
"/profile.ksh"))
include(profile, 0, (char **) 0, 1);
else if (include("/etc/profile.ksh", 0, (char **) 0, 1) < 0)
include("c:/usr/etc/profile.ksh", 0, (char **) 0, 1);
if (!Flag(FPRIVILEGED))
include(substitute("$HOME/profile.ksh", 0), 0,
(char **) 0, 1);
#else /* OS2 */
include(KSH_SYSTEM_PROFILE, 0, (char **) 0, 1);
if (!Flag(FPRIVILEGED))
include(substitute("$HOME/.profile", 0), 0,
(char **) 0, 1);
#endif /* OS2 */
}
if (Flag(FPRIVILEGED))
include("/etc/suid_profile", 0, (char **) 0, 1);
else {
char *env_file;
#ifndef KSH
if (!Flag(FPOSIX))
env_file = null;
else
#endif /* !KSH */
/* include $ENV */
env_file = str_val(global("ENV"));
#ifdef DEFAULT_ENV
/* If env isn't set, include default environment */
if (env_file == null)
env_file = __UNCONST(DEFAULT_ENV);
#endif /* DEFAULT_ENV */
env_file = substitute(env_file, DOTILDE);
if (*env_file != '\0')
include(env_file, 0, (char **) 0, 1);
#ifdef OS2
else if (Flag(FTALKING))
include(substitute("$HOME/kshrc.ksh", 0), 0,
(char **) 0, 1);
#endif /* OS2 */
}
if (is_restricted(argv[0]) || is_restricted(str_val(global("SHELL"))))
restricted = 1;
if (restricted) {
static const char *const restr_com[] = {
"typeset", "-r", "PATH",
"ENV", "SHELL",
(char *) 0
};
shcomexec((char **)__UNCONST(restr_com));
/* After typeset command... */
Flag(FRESTRICTED) = 1;
}
if (errexit)
Flag(FERREXIT) = 1;
if (Flag(FTALKING)) {
hist_init(s);
#ifdef KSH
alarm_init();
#endif /* KSH */
} else
Flag(FTRACKALL) = 1; /* set after ENV */
setlocale(LC_CTYPE, "");
shell(s, TRUE); /* doesn't return */
return 0;
}
int
include(name, argc, argv, intr_ok)
const char *name;
int argc;
char **argv;
int intr_ok;
{
register Source *volatile s = NULL;
struct shf *shf;
char **volatile old_argv;
volatile int old_argc;
int i;
shf = shf_open(name, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC);
if (shf == NULL)
return -1;
if (argv) {
old_argv = e->loc->argv;
old_argc = e->loc->argc;
} else {
old_argv = (char **) 0;
old_argc = 0;
}
newenv(E_INCL);
i = ksh_sigsetjmp(e->jbuf, 0);
if (i) {
if (s) /* Do this before quitenv(), which frees the memory */
shf_close(s->u.shf);
quitenv();
if (old_argv) {
e->loc->argv = old_argv;
e->loc->argc = old_argc;
}
switch (i) {
case LRETURN:
case LERROR:
return exstat & 0xff; /* see below */
case LINTR:
/* intr_ok is set if we are including .profile or $ENV.
* If user ^C's out, we don't want to kill the shell...
*/
if (intr_ok && (exstat - 128) != SIGTERM)
return 1;
/* fall through... */
case LEXIT:
case LLEAVE:
case LSHELL:
unwind(i);
/*NOREACHED*/
default:
internal_errorf(1, "include: %d", i);
/*NOREACHED*/
}
}
if (argv) {
e->loc->argv = argv;
e->loc->argc = argc;
}
s = pushs(SFILE, ATEMP);
s->u.shf = shf;
s->file = str_save(name, ATEMP);
i = shell(s, FALSE);
shf_close(s->u.shf);
quitenv();
if (old_argv) {
e->loc->argv = old_argv;
e->loc->argc = old_argc;
}
return i & 0xff; /* & 0xff to ensure value not -1 */
}
int
command(comm)
const char *comm;
{
register Source *s;
int r;
s = pushs(SSTRING, ATEMP);
s->start = s->str = comm;
r = shell(s, FALSE);
afree(s, ATEMP);
return r;
}
/*
* run the commands from the input source, returning status.
*/
int
shell(s, toplevel)
Source *volatile s; /* input source */
int volatile toplevel;
{
struct op *t;
volatile int wastty = s->flags & SF_TTY;
volatile int attempts = 13;
volatile int interactive = Flag(FTALKING) && toplevel;
Source *volatile old_source = source;
int i;
newenv(E_PARSE);
if (interactive)
really_exit = 0;
i = ksh_sigsetjmp(e->jbuf, 0);
if (i) {
switch (i) {
case LINTR: /* we get here if SIGINT not caught or ignored */
case LERROR:
case LSHELL:
if (interactive) {
if (i == LINTR)
shellf("%s", newline);
/* Reset any eof that was read as part of a
* multiline command.
*/
if (Flag(FIGNOREEOF) && s->type == SEOF
&& wastty)
s->type = SSTDIN;
/* Used by exit command to get back to
* top level shell. Kind of strange since
* interactive is set if we are reading from
* a tty, but to have stopped jobs, one only
* needs FMONITOR set (not FTALKING/SF_TTY)...
*/
/* toss any input we have so far */
s->start = s->str = null;
break;
}
/* fall through... */
case LEXIT:
case LLEAVE:
case LRETURN:
source = old_source;
quitenv();
unwind(i); /* keep on going */
/*NOREACHED*/
default:
source = old_source;
quitenv();
internal_errorf(1, "shell: %d", i);
/*NOREACHED*/
}
}
while (1) {
if (trap)
runtraps(0);
if (s->next == NULL) {
if (Flag(FVERBOSE))
s->flags |= SF_ECHO;
else
s->flags &= ~SF_ECHO;
}
if (interactive) {
j_notify();
#ifdef KSH
mcheck();
#endif /* KSH */
set_prompt(PS1, s);
}
t = compile(s);
if (t != NULL && t->type == TEOF) {
if (wastty && Flag(FIGNOREEOF) && --attempts > 0) {
shellf("Use `exit' to leave ksh\n");
s->type = SSTDIN;
} else if (wastty && !really_exit
&& j_stopped_running())
{
really_exit = 1;
s->type = SSTDIN;
} else {
/* this for POSIX, which says EXIT traps
* shall be taken in the environment
* immediately after the last command
* executed.
*/
if (toplevel)
unwind(LEXIT);
break;
}
}
if (t && (!Flag(FNOEXEC) || (s->flags & SF_TTY)))
exstat = execute(t, 0);
if (t != NULL && t->type != TEOF && interactive && really_exit)
really_exit = 0;
reclaim();
}
quitenv();
source = old_source;
return exstat;
}
/* return to closest error handler or shell(), exit if none found */
void
unwind(i)
int i;
{
/* ordering for EXIT vs ERR is a bit odd (this is what at&t ksh does) */
if (i == LEXIT || (Flag(FERREXIT) && (i == LERROR || i == LINTR)
&& sigtraps[SIGEXIT_].trap))
{
runtrap(&sigtraps[SIGEXIT_]);
i = LLEAVE;
} else if (Flag(FERREXIT) && (i == LERROR || i == LINTR)) {
runtrap(&sigtraps[SIGERR_]);
i = LLEAVE;
}
while (1) {
switch (e->type) {
case E_PARSE:
case E_FUNC:
case E_INCL:
case E_LOOP:
case E_ERRH:
ksh_siglongjmp(e->jbuf, i);
/*NOTREACHED*/
case E_NONE:
if (i == LINTR)
e->flags |= EF_FAKE_SIGDIE;
/* Fall through... */
default:
quitenv();
}
}
}
void
newenv(type)
int type;
{
register struct env *ep;
ep = (struct env *) alloc(sizeof(*ep), ATEMP);
ep->type = type;
ep->flags = 0;
ainit(&ep->area);
ep->loc = e->loc;
ep->savefd = NULL;
ep->oenv = e;
ep->temps = NULL;
e = ep;
}
void
quitenv()
{
register struct env *ep = e;
register int fd;
if (ep->oenv && ep->oenv->loc != ep->loc)
popblock();
if (ep->savefd != NULL) {
for (fd = 0; fd < NUFILE; fd++)
/* if ep->savefd[fd] < 0, means fd was closed */
if (ep->savefd[fd])
restfd(fd, ep->savefd[fd]);
if (ep->savefd[2]) /* Clear any write errors */
shf_reopen(2, SHF_WR, shl_out);
}
reclaim();
/* Bottom of the stack.
* Either main shell is exiting or cleanup_parents_env() was called.
*/
if (ep->oenv == NULL) {
if (ep->type == E_NONE) { /* Main shell exiting? */
if (Flag(FTALKING))
hist_finish();
j_exit();
if (ep->flags & EF_FAKE_SIGDIE) {
int sig = exstat - 128;
/* ham up our death a bit (at&t ksh
* only seems to do this for SIGTERM)
* Don't do it for SIGQUIT, since we'd
* dump a core..
*/
if (sig == SIGINT || sig == SIGTERM) {
setsig(&sigtraps[sig], SIG_DFL,
SS_RESTORE_CURR|SS_FORCE);
kill(0, sig);
}
}
#ifdef MEM_DEBUG
chmem_allfree();
#endif /* MEM_DEBUG */
}
exit(exstat);
}
e = e->oenv;
afree(ep, ATEMP);
}
/* Called after a fork to cleanup stuff left over from parents environment */
void
cleanup_parents_env()
{
struct env *ep;
int fd;
/* Don't clean up temporary files - parent will probably need them.
* Also, can't easily reclaim memory since variables, etc. could be
* anywhere.
*/
/* close all file descriptors hiding in savefd */
for (ep = e; ep; ep = ep->oenv) {
if (ep->savefd) {
for (fd = 0; fd < NUFILE; fd++)
if (ep->savefd[fd] > 0)
close(ep->savefd[fd]);
afree(ep->savefd, &ep->area);
ep->savefd = (short *) 0;
}
}
e->oenv = (struct env *) 0;
}
/* Called just before an execve cleanup stuff temporary files */
void
cleanup_proc_env()
{
struct env *ep;
for (ep = e; ep; ep = ep->oenv)
remove_temps(ep->temps);
}
/* remove temp files and free ATEMP Area */
static void
reclaim()
{
remove_temps(e->temps);
e->temps = NULL;
afreeall(&e->area);
}
static void
remove_temps(tp)
struct temp *tp;
{
#ifdef OS2
static struct temp *delayed_remove;
struct temp *t, **tprev;
if (delayed_remove) {
for (tprev = &delayed_remove, t = delayed_remove; t; t = *tprev)
/* No need to check t->pid here... */
if (unlink(t->name) >= 0 || errno == ENOENT) {
*tprev = t->next;
afree(t, APERM);
} else
tprev = &t->next;
}
#endif /* OS2 */
for (; tp != NULL; tp = tp->next)
if (tp->pid == procpid) {
#ifdef OS2
/* OS/2 (and dos) do not allow files that are currently
* open to be removed, so we cache it away for future
* removal.
* XXX should only do this if errno
* is Efile-still-open-can't-remove
* (but I don't know what that is...)
*/
if (unlink(tp->name) < 0 && errno != ENOENT) {
t = (struct temp *) alloc(
sizeof(struct temp) + strlen(tp->name) + 1,
APERM);
memset(t, 0, sizeof(struct temp));
t->name = (char *) &t[1];
strlcpy(t->name, tp->name, strlen(tp->name) + 1);
t->next = delayed_remove;
delayed_remove = t;
}
#else /* OS2 */
unlink(tp->name);
#endif /* OS2 */
}
}
/* Returns true if name refers to a restricted shell */
static int
is_restricted(name)
char *name;
{
char *p;
if ((p = ksh_strrchr_dirsep(name)))
name = p;
/* accepts rsh, rksh, rpdksh, pdrksh, etc. */
return (p = strchr(name, 'r')) && strstr(p, "sh");
}
void
aerror(ap, msg)
Area *ap;
const char *msg;
{
internal_errorf(1, "alloc: %s", msg);
errorf("%s", null); /* this is never executed - keeps gcc quiet */
/*NOTREACHED*/
}

1364
bin/ksh/misc.c Normal file

File diff suppressed because it is too large Load Diff

46
bin/ksh/mkman Executable file
View File

@@ -0,0 +1,46 @@
#!/bin/sh
: ${AWK:=awk}
verbose=no
if [ X"$1" = X-v ] ; then
verbose=yes
shift
fi
if [ $# != 2 ] ; then
echo "usage: $0 [-v] which-shell ksh.Man-file" 1>&2
exit 1;
fi
shell=$1
man=$2
case $shell in
sh) which=0;;
ksh) which=1;;
*)
echo "$0: bad shell option (must be sh or ksh)" 1>&2
exit 1
;;
esac
if [ ! -r "$man" ] ; then
echo "$0: can't read $man file" 1>&2
exit 1;
fi
#
# Now generate the appropriate man page...
#
[ $verbose = yes ] && echo "$0: Generating $which man page (0=sh,1=ksh)..." 1>&2
${AWK} 'BEGIN { ksh = '$which'; pr = 1 }
/^\.sh\(/ { pr = ksh - 1; next }
/^\.sh\)/ { pr = 1; next }
/^\.ksh\(/ { pr = ksh; next }
/^\.ksh\)/ { pr = 1; next }
{ if (pr) print $0 } ' < $man
[ $verbose = yes ] && echo "$0: All done" 1>&2
exit 0

318
bin/ksh/path.c Normal file
View File

@@ -0,0 +1,318 @@
/* $NetBSD: path.c,v 1.8 2009/04/25 05:11:37 lukem Exp $ */
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: path.c,v 1.8 2009/04/25 05:11:37 lukem Exp $");
#endif
#include "sh.h"
#include "ksh_stat.h"
/*
* Contains a routine to search a : separated list of
* paths (a la CDPATH) and make appropriate file names.
* Also contains a routine to simplify .'s and ..'s out of
* a path name.
*
* Larry Bouzane (larry@cs.mun.ca)
*/
#ifdef S_ISLNK
static char *do_phys_path ARGS((XString *, char *, const char *));
#endif /* S_ISLNK */
/*
* Makes a filename into result using the following algorithm.
* - make result NULL
* - if file starts with '/', append file to result & set cdpathp to NULL
* - if file starts with ./ or ../ append cwd and file to result
* and set cdpathp to NULL
* - if the first element of cdpathp doesnt start with a '/' xx or '.' xx
* then cwd is appended to result.
* - the first element of cdpathp is appended to result
* - file is appended to result
* - cdpathp is set to the start of the next element in cdpathp (or NULL
* if there are no more elements.
* The return value indicates whether a non-null element from cdpathp
* was appended to result.
*/
int
make_path(cwd, file, cdpathp, xsp, phys_pathp)
const char *cwd;
const char *file;
char **cdpathp; /* & of : separated list */
XString *xsp;
int *phys_pathp;
{
int rval = 0;
int use_cdpath = 1;
char *plist;
int len;
int plen = 0;
char *xp = Xstring(*xsp, xp);
if (!file)
file = null;
if (!ISRELPATH(file)) {
*phys_pathp = 0;
use_cdpath = 0;
} else {
if (file[0] == '.') {
char c = file[1];
if (c == '.')
c = file[2];
if (ISDIRSEP(c) || c == '\0')
use_cdpath = 0;
}
plist = *cdpathp;
if (!plist)
use_cdpath = 0;
else if (use_cdpath) {
char *pend;
for (pend = plist; *pend && *pend != PATHSEP; pend++)
;
plen = pend - plist;
*cdpathp = *pend ? ++pend : (char *) 0;
}
if ((use_cdpath == 0 || !plen || ISRELPATH(plist))
&& (cwd && *cwd))
{
len = strlen(cwd);
XcheckN(*xsp, xp, len);
memcpy(xp, cwd, len);
xp += len;
if (!ISDIRSEP(cwd[len - 1]))
Xput(*xsp, xp, DIRSEP);
}
*phys_pathp = Xlength(*xsp, xp);
if (use_cdpath && plen) {
XcheckN(*xsp, xp, plen);
memcpy(xp, plist, plen);
xp += plen;
if (!ISDIRSEP(plist[plen - 1]))
Xput(*xsp, xp, DIRSEP);
rval = 1;
}
}
len = strlen(file) + 1;
XcheckN(*xsp, xp, len);
memcpy(xp, file, len);
if (!use_cdpath)
*cdpathp = (char *) 0;
return rval;
}
/*
* Simplify pathnames containing "." and ".." entries.
* ie, simplify_path("/a/b/c/./../d/..") returns "/a/b"
*/
void
simplify_path(pathx)
char *pathx;
{
char *cur;
char *t;
int isrooted;
char *very_start = pathx;
char *start;
if (!*pathx)
return;
if ((isrooted = ISROOTEDPATH(pathx)))
very_start++;
#if defined (OS2) || defined (__CYGWIN__)
if (pathx[0] && pathx[1] == ':') /* skip a: */
very_start += 2;
#endif /* OS2 || __CYGWIN__ */
/* Before After
* /foo/ /foo
* /foo/../../bar /bar
* /foo/./blah/.. /foo
* . .
* .. ..
* ./foo foo
* foo/../../../bar ../../bar
* OS2 and CYGWIN:
* a:/foo/../.. a:/
* a:. a:
* a:.. a:..
* a:foo/../../blah a:../blah
*/
#ifdef __CYGWIN__
/* preserve leading double-slash on pathnames (for UNC paths) */
if (pathx[0] && ISDIRSEP(pathx[0]) && pathx[1] && ISDIRSEP(pathx[1]))
very_start++;
#endif /* __CYGWIN__ */
for (cur = t = start = very_start; ; ) {
/* treat multiple '/'s as one '/' */
while (ISDIRSEP(*t))
t++;
if (*t == '\0') {
if (cur == pathx)
/* convert empty path to dot */
*cur++ = '.';
*cur = '\0';
break;
}
if (t[0] == '.') {
if (!t[1] || ISDIRSEP(t[1])) {
t += 1;
continue;
} else if (t[1] == '.' && (!t[2] || ISDIRSEP(t[2]))) {
if (!isrooted && cur == start) {
if (cur != very_start)
*cur++ = DIRSEP;
*cur++ = '.';
*cur++ = '.';
start = cur;
} else if (cur != start)
while (--cur > start && !ISDIRSEP(*cur))
;
t += 2;
continue;
}
}
if (cur != very_start)
*cur++ = DIRSEP;
/* find/copy next component of pathname */
while (*t && !ISDIRSEP(*t))
*cur++ = *t++;
}
}
void
set_current_wd(pathx)
char *pathx;
{
int len;
char *p = pathx;
if (!p && !(p = ksh_get_wd((char *) 0, 0)))
p = null;
len = strlen(p) + 1;
if (len > current_wd_size)
current_wd = aresize(current_wd, current_wd_size = len, APERM);
memcpy(current_wd, p, len);
if (p != pathx && p != null)
afree(p, ATEMP);
}
#ifdef S_ISLNK
char *
get_phys_path(pathx)
const char *pathx;
{
XString xs;
char *xp;
Xinit(xs, xp, strlen(pathx) + 1, ATEMP);
xp = do_phys_path(&xs, xp, pathx);
if (!xp)
return (char *) 0;
if (Xlength(xs, xp) == 0)
Xput(xs, xp, DIRSEP);
Xput(xs, xp, '\0');
return Xclose(xs, xp);
}
static char *
do_phys_path(xsp, xp, pathx)
XString *xsp;
char *xp;
const char *pathx;
{
const char *p, *q;
int len, llen;
int savepos;
char lbuf[PATH];
Xcheck(*xsp, xp);
for (p = pathx; p; p = q) {
while (ISDIRSEP(*p))
p++;
if (!*p)
break;
len = (q = ksh_strchr_dirsep(p)) ? q - p : (int)strlen(p);
if (len == 1 && p[0] == '.')
continue;
if (len == 2 && p[0] == '.' && p[1] == '.') {
while (xp > Xstring(*xsp, xp)) {
xp--;
if (ISDIRSEP(*xp))
break;
}
continue;
}
savepos = Xsavepos(*xsp, xp);
Xput(*xsp, xp, DIRSEP);
XcheckN(*xsp, xp, len + 1);
memcpy(xp, p, len);
xp += len;
*xp = '\0';
llen = readlink(Xstring(*xsp, xp), lbuf, sizeof(lbuf) - 1);
if (llen < 0) {
/* EINVAL means it wasn't a symlink... */
if (errno != EINVAL)
return (char *) 0;
continue;
}
lbuf[llen] = '\0';
/* If absolute path, start from scratch.. */
xp = ISABSPATH(lbuf) ? Xstring(*xsp, xp)
: Xrestpos(*xsp, xp, savepos);
if (!(xp = do_phys_path(xsp, xp, lbuf)))
return (char *) 0;
}
return xp;
}
#endif /* S_ISLNK */
#ifdef TEST
main(argc, argv)
{
int rv;
char *cp, cdpath[256], pwd[256], file[256], result[256];
printf("enter CDPATH: "); gets(cdpath);
printf("enter PWD: "); gets(pwd);
while (1) {
if (printf("Enter file: "), gets(file) == 0)
return 0;
cp = cdpath;
do {
rv = make_path(pwd, file, &cp, result, sizeof(result));
printf("make_path returns (%d), \"%s\" ", rv, result);
simplify_path(result);
printf("(simpifies to \"%s\")\n", result);
} while (cp);
}
}
#endif /* TEST */

298
bin/ksh/proto.h Normal file
View File

@@ -0,0 +1,298 @@
/* $NetBSD: proto.h,v 1.7 2005/06/26 19:09:00 christos Exp $ */
/*
* prototypes for PD-KSH
* originally generated using "cproto.c 3.5 92/04/11 19:28:01 cthuang "
* $Id: proto.h,v 1.7 2005/06/26 19:09:00 christos Exp $
*/
/* alloc.c */
Area * ainit ARGS((Area *));
void afreeall ARGS((Area *));
void * alloc ARGS((size_t, Area *));
void * aresize ARGS((void *, size_t, Area *));
void afree ARGS((void *, Area *));
/* c_ksh.c */
int c_hash ARGS((char **));
int c_cd ARGS((char **));
int c_pwd ARGS((char **));
int c_print ARGS((char **));
int c_whence ARGS((char **));
int c_command ARGS((char **));
int c_typeset ARGS((char **));
int c_alias ARGS((char **));
int c_unalias ARGS((char **));
int c_let ARGS((char **));
int c_jobs ARGS((char **));
int c_fgbg ARGS((char **));
int c_kill ARGS((char **));
void getopts_reset ARGS((int));
int c_getopts ARGS((char **));
int c_bind ARGS((char **));
/* c_sh.c */
int c_label ARGS((char **));
int c_shift ARGS((char **));
int c_umask ARGS((char **));
int c_dot ARGS((char **));
int c_wait ARGS((char **));
int c_read ARGS((char **));
int c_eval ARGS((char **));
int c_trap ARGS((char **));
int c_brkcont ARGS((char **));
int c_exitreturn ARGS((char **));
int c_set ARGS((char **));
int c_unset ARGS((char **));
int c_ulimit ARGS((char **));
int c_times ARGS((char **));
int timex ARGS((struct op *, int));
void timex_hook ARGS((struct op *, char ** volatile *));
int c_exec ARGS((char **));
int c_builtin ARGS((char **));
/* c_test.c */
int c_test ARGS((char **));
/* edit.c: most prototypes in edit.h */
void x_init ARGS((void));
int x_read ARGS((char *, size_t));
void set_editmode ARGS((const char *));
/* emacs.c: most prototypes in edit.h */
int x_bind ARGS((const char *, const char *, int, int));
/* eval.c */
char * substitute ARGS((const char *, int));
char ** eval ARGS((char **, int));
char * evalstr ARGS((char *, int));
char * evalonestr ARGS((char *, int));
char *debunk ARGS((char *, const char *, size_t));
void expand ARGS((char *, XPtrV *, int));
int glob_str ARGS((char *, XPtrV *, int));
/* exec.c */
int fd_clexec ARGS((int));
int execute ARGS((struct op * volatile, volatile int));
int shcomexec ARGS((char **));
struct tbl * findfunc ARGS((const char *, unsigned int, int));
int define ARGS((const char *, struct op *));
void builtin ARGS((const char *, int (*)(char **)));
struct tbl * findcom ARGS((const char *, int));
void flushcom ARGS((int all));
char * search ARGS((const char *, const char *, int, int *));
int search_access ARGS((const char *, int, int *));
int pr_menu ARGS((char *const *));
int pr_list ARGS((char *const *));
/* expr.c */
int evaluate ARGS((const char *, long *, int));
int v_evaluate ARGS((struct tbl *, const char *, volatile int));
/* history.c */
void init_histvec ARGS((void));
void hist_init ARGS((Source *));
void hist_finish ARGS((void));
void histsave ARGS((int, const char *, int));
#ifdef HISTORY
int c_fc ARGS((char **));
void sethistsize ARGS((int));
void sethistfile ARGS((const char *));
# ifdef EASY_HISTORY
void histappend ARGS((const char *, int));
# endif
char ** histpos ARGS((void));
int histN ARGS((void));
int histnum ARGS((int));
int findhist ARGS((int, int, const char *, int));
#endif /* HISTORY */
/* io.c */
void errorf ARGS((const char *, ...))
GCC_FUNC_ATTR2(noreturn, format(printf, 1, 2));
void warningf ARGS((int, const char *, ...))
GCC_FUNC_ATTR(format(printf, 2, 3));
void bi_errorf ARGS((const char *, ...))
GCC_FUNC_ATTR(format(printf, 1, 2));
void internal_errorf ARGS((int, const char *, ...))
GCC_FUNC_ATTR(format(printf, 2, 3));
void error_prefix ARGS((int));
void shellf ARGS((const char *, ...))
GCC_FUNC_ATTR(format(printf, 1, 2));
void shprintf ARGS((const char *, ...))
GCC_FUNC_ATTR(format(printf, 1, 2));
#ifdef KSH_DEBUG
void kshdebug_init_ ARGS((void));
void kshdebug_printf_ ARGS((const char *, ...))
GCC_FUNC_ATTR(format(printf, 1, 2));
void kshdebug_dump_ ARGS((const char *, const void *, int));
#endif /* KSH_DEBUG */
int can_seek ARGS((int));
void initio ARGS((void));
int ksh_dup2 ARGS((int, int, int));
int savefd ARGS((int, int));
void restfd ARGS((int, int));
void openpipe ARGS((int *));
void closepipe ARGS((int *));
int check_fd ARGS((char *, int, const char **));
#ifdef KSH
void coproc_init ARGS((void));
void coproc_read_close ARGS((int));
void coproc_readw_close ARGS((int));
void coproc_write_close ARGS((int));
int coproc_getfd ARGS((int, const char **));
void coproc_cleanup ARGS((int));
#endif /* KSH */
struct temp *maketemp ARGS((Area *, Temp_type, struct temp **));
/* jobs.c */
void j_init ARGS((int));
void j_exit ARGS((void));
void j_change ARGS((void));
int exchild ARGS((struct op *, int, int));
void startlast ARGS((void));
int waitlast ARGS((void));
int waitfor ARGS((const char *, int *));
int j_kill ARGS((const char *, int));
int j_resume ARGS((const char *, int));
int j_jobs ARGS((const char *, int, int));
void j_notify ARGS((void));
pid_t j_async ARGS((void));
int j_stopped_running ARGS((void));
/* lex.c */
int yylex ARGS((int));
void yyerror ARGS((const char *, ...))
GCC_FUNC_ATTR2(noreturn, format(printf, 1, 2));
Source * pushs ARGS((int, Area *));
void set_prompt ARGS((int, Source *));
void pprompt ARGS((const char *, int));
/* mail.c */
#ifdef KSH
void mcheck ARGS((void));
void mcset ARGS((long));
void mbset ARGS((char *));
void mpset ARGS((char *));
#endif /* KSH */
/* main.c */
int include ARGS((const char *, int, char **, int));
int command ARGS((const char *));
int shell ARGS((Source *volatile, int volatile));
void unwind ARGS((int)) GCC_FUNC_ATTR(noreturn);
void newenv ARGS((int));
void quitenv ARGS((void));
void cleanup_parents_env ARGS((void));
void cleanup_proc_env ARGS((void));
void aerror ARGS((Area *, const char *))
GCC_FUNC_ATTR(noreturn);
/* misc.c */
void setctypes ARGS((const char *, int));
void initctypes ARGS((void));
char * ulton ARGS((unsigned long, int));
char * str_save ARGS((const char *, Area *));
char * str_nsave ARGS((const char *, int, Area *));
int option ARGS((const char *));
char * getoptions ARGS((void));
void change_flag ARGS((enum sh_flag, int, int));
int parse_args ARGS((char **v, int what, int *));
int getn ARGS((const char *, int *));
int bi_getn ARGS((const char *, int *));
int gmatch ARGS((const char *, const char *, int));
int has_globbing ARGS((const char *, const char *));
const unsigned char *pat_scan ARGS((const unsigned char *,
const unsigned char *, int));
void qsortp ARGS((void **, size_t, int (*)(void *, void *)));
int xstrcmp ARGS((void *, void *));
void ksh_getopt_reset ARGS((Getopt *, int));
int ksh_getopt ARGS((char **, Getopt *, const char *));
void print_value_quoted ARGS((const char *));
void print_columns ARGS((struct shf *, int,
char *(*)(void *, int, char *, int),
void *, int, int));
int strip_nuls ARGS((char *, int));
char *str_zcpy ARGS((char *, const char *, int));
int blocking_read ARGS((int, char *, int));
int reset_nonblock ARGS((int));
char *ksh_get_wd ARGS((char *, int));
/* path.c */
int make_path ARGS((const char *, const char *,
char **, XString *, int *));
void simplify_path ARGS((char *));
char *get_phys_path ARGS((const char *));
void set_current_wd ARGS((char *));
/* syn.c */
void initkeywords ARGS((void));
struct op * compile ARGS((Source *));
/* table.c */
unsigned int hash ARGS((const char *));
void tinit ARGS((struct table *, Area *, int));
struct tbl * tsearch ARGS((struct table *, const char *, unsigned int));
struct tbl * tenter ARGS((struct table *, const char *, unsigned int));
void tdelete ARGS((struct tbl *));
void twalk ARGS((struct tstate *, struct table *));
struct tbl * tnext ARGS((struct tstate *));
struct tbl ** tsort ARGS((struct table *));
/* trace.c */
/* trap.c */
void inittraps ARGS((void));
#ifdef KSH
void alarm_init ARGS((void));
#endif /* KSH */
Trap * gettrap ARGS((const char *, int));
RETSIGTYPE trapsig ARGS((int));
void intrcheck ARGS((void));
int fatal_trap_check ARGS((void));
int trap_pending ARGS((void));
void runtraps ARGS((int));
void runtrap ARGS((Trap *));
void cleartraps ARGS((void));
void restoresigs ARGS((void));
void settrap ARGS((Trap *, char *));
int block_pipe ARGS((void));
void restore_pipe ARGS((int));
int setsig ARGS((Trap *, handler_t, int));
void setexecsig ARGS((Trap *, int));
/* tree.c */
int fptreef ARGS((struct shf *, int, const char *, ...));
char * snptreef ARGS((char *, int, const char *, ...));
struct op * tcopy ARGS((struct op *, Area *));
char * wdcopy ARGS((const char *, Area *));
char * wdscan ARGS((const char *, int));
char * wdstrip ARGS((const char *));
void tfree ARGS((struct op *, Area *));
/* var.c */
void newblock ARGS((void));
void popblock ARGS((void));
void initvar ARGS((void));
struct tbl * global ARGS((const char *));
struct tbl * local ARGS((const char *, bool_t));
char * str_val ARGS((struct tbl *));
long intval ARGS((struct tbl *));
int setstr ARGS((struct tbl *, const char *, int));
struct tbl *setint_v ARGS((struct tbl *, struct tbl *));
void setint ARGS((struct tbl *, long));
int getint ARGS((struct tbl *, long *));
struct tbl * typeset ARGS((const char *, Tflag, Tflag, int, int));
void unset ARGS((struct tbl *, int));
char * skip_varname ARGS((const char *, int));
char *skip_wdvarname ARGS((const char *, int));
int is_wdvarname ARGS((const char *, int));
int is_wdvarassign ARGS((const char *));
char ** makenv ARGS((void));
void change_random ARGS((void));
int array_ref_len ARGS((const char *));
char * arrayname ARGS((const char *));
void set_array ARGS((const char *, int, char **));
/* version.c */
/* vi.c: see edit.h */
/* Hack to avoid billions of compile warnings on SunOS 4.1.x */
#if defined(MUN) && defined(sun) && !defined(__svr4__)
extern void bcopy ARGS((const void *, void *, size_t));
extern intclose ARGS((FILE *));
extern intprintf ARGS((FILE *, const char *, ...));
extern intread ARGS((void *, int, int, FILE *));
extern int ioctl ARGS((int, int, void *));
extern int killpg ARGS((int, int));
extern int nice ARGS((int));
extern int readlink ARGS((const char *, char *, int));
extern int setpgrp ARGS((int, int));
extern int strcasecmp ARGS((const char *, const char *));
extern int tolower ARGS((int));
extern int toupper ARGS((int));
/* Include files aren't included yet */
extern int getrlimit ARGS(( /* int, struct rlimit * */ ));
extern int getrusage ARGS(( /* int, struct rusage * */ ));
extern int gettimeofday ARGS(( /* struct timeval *, struct timezone * */ ));
extern int setrlimit ARGS(( /* int, struct rlimit * */ ));
extern int lstat ARGS(( /* const char *, struct stat * */ ));
#endif

735
bin/ksh/sh.h Normal file
View File

@@ -0,0 +1,735 @@
/* $NetBSD: sh.h,v 1.7 2005/06/26 19:09:00 christos Exp $ */
/*
* Public Domain Bourne/Korn shell
*/
/* $Id: sh.h,v 1.7 2005/06/26 19:09:00 christos Exp $ */
#include "config.h" /* system and option configuration info */
#ifdef HAVE_PROTOTYPES
# define ARGS(args) args /* prototype declaration */
#else
# define ARGS(args) () /* K&R declaration */
#endif
/* Start of common headers */
#include <stdio.h>
#include <sys/types.h>
#include <setjmp.h>
#ifdef HAVE_STDDEF_H
# include <stddef.h>
#endif
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#else
/* just a useful subset of what stdlib.h would have */
extern char * getenv ARGS((const char *));
extern void * malloc ARGS((size_t));
extern void * realloc ARGS((void *, size_t));
extern int free ARGS((void *));
extern int exit ARGS((int));
extern int rand ARGS((void));
extern void srand ARGS((unsigned int));
extern int atoi ARGS((const char *));
#endif /* HAVE_STDLIB_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#else
/* just a useful subset of what unistd.h would have */
extern int access ARGS((const char *, int));
extern int open ARGS((const char *, int, ...));
extern int creat ARGS((const char *, mode_t));
extern int read ARGS((int, char *, unsigned));
extern int write ARGS((int, const char *, unsigned));
extern off_t lseek ARGS((int, off_t, int));
extern int close ARGS((int));
extern int pipe ARGS((int []));
extern int dup2 ARGS((int, int));
extern int unlink ARGS((const char *));
extern int fork ARGS((void));
extern int execve ARGS((const char *, char * const[], char * const[]));
extern int chdir ARGS((const char *));
extern int kill ARGS((pid_t, int));
extern char *getcwd(); /* no ARGS here - differs on different machines */
extern int geteuid ARGS((void));
extern int readlink ARGS((const char *, char *, int));
extern int getegid ARGS((void));
extern int getpid ARGS((void));
extern int getppid ARGS((void));
extern unsigned int sleep ARGS((unsigned int));
extern int isatty ARGS((int));
# ifdef POSIX_PGRP
extern int getpgrp ARGS((void));
extern int setpgid ARGS((pid_t, pid_t));
# endif /* POSIX_PGRP */
# ifdef BSD_PGRP
extern int getpgrp ARGS((pid_t));
extern int setpgrp ARGS((pid_t, pid_t));
# endif /* BSD_PGRP */
# ifdef SYSV_PGRP
extern int getpgrp ARGS((void));
extern int setpgrp ARGS((void));
# endif /* SYSV_PGRP */
#endif /* HAVE_UNISTD_H */
#ifdef HAVE_STRING_H
# include <string.h>
#else
# include <strings.h>
# define strchr index
# define strrchr rindex
#endif /* HAVE_STRING_H */
#ifndef HAVE_STRSTR
char *strstr ARGS((const char *s, const char *p));
#endif /* HAVE_STRSTR */
#ifndef HAVE_STRCASECMP
int strcasecmp ARGS((const char *s1, const char *s2));
int strncasecmp ARGS((const char *s1, const char *s2, int n));
#endif /* HAVE_STRCASECMP */
#ifdef HAVE_MEMORY_H
# include <memory.h>
#endif
#ifndef HAVE_MEMSET
# define memcpy(d, s, n) bcopy(s, d, n)
# define memcmp(s1, s2, n) bcmp(s1, s2, n)
void *memset ARGS((void *d, int c, size_t n));
#endif /* HAVE_MEMSET */
#ifndef HAVE_MEMMOVE
# ifdef HAVE_BCOPY
# define memmove(d, s, n) bcopy(s, d, n)
# else
void *memmove ARGS((void *d, const void *s, size_t n));
# endif
#endif /* HAVE_MEMMOVE */
#ifdef HAVE_PROTOTYPES
# include <stdarg.h>
# define SH_VA_START(va, argn) va_start(va, argn)
#else
# include <varargs.h>
# define SH_VA_START(va, argn) va_start(va)
#endif /* HAVE_PROTOTYPES */
#include <errno.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#else
# include <sys/file.h>
#endif /* HAVE_FCNTL_H */
#ifndef O_ACCMODE
# define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
#endif /* !O_ACCMODE */
#ifndef F_OK /* access() arguments */
# define F_OK 0
# define X_OK 1
# define W_OK 2
# define R_OK 4
#endif /* !F_OK */
#ifndef SEEK_SET
# ifdef L_SET
# define SEEK_SET L_SET
# define SEEK_CUR L_INCR
# define SEEK_END L_XTND
# else /* L_SET */
# define SEEK_SET 0
# define SEEK_CUR 1
# define SEEK_END 2
# endif /* L_SET */
#endif /* !SEEK_SET */
/* Some machines (eg, FreeBSD 1.1.5) define CLK_TCK in limits.h
* (ksh_limval.h assumes limits has been included, if available)
*/
#ifdef HAVE_LIMITS_H
# include <limits.h>
#endif /* HAVE_LIMITS_H */
#include <signal.h>
#ifdef NSIG
# define SIGNALS NSIG
#else
# ifdef _MINIX
# define SIGNALS (_NSIG+1) /* _NSIG is # of signals used, excluding 0. */
# else
# ifdef _SIGMAX /* QNX */
# define SIGNALS _SIGMAX
# else /* _SIGMAX */
# define SIGNALS 32
# endif /* _SIGMAX */
# endif /* _MINIX */
#endif /* NSIG */
#ifndef SIGCHLD
# define SIGCHLD SIGCLD
#endif
/* struct sigaction.sa_flags is set to KSH_SA_FLAGS. Used to ensure
* system calls are interrupted
*/
#ifdef SA_INTERRUPT
# define KSH_SA_FLAGS SA_INTERRUPT
#else /* SA_INTERRUPT */
# define KSH_SA_FLAGS 0
#endif /* SA_INTERRUPT */
typedef RETSIGTYPE (*handler_t) ARGS((int)); /* signal handler */
#ifdef USE_FAKE_SIGACT
# include "sigact.h" /* use sjg's fake sigaction() */
#endif
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif /* HAVE_PATHS_H */
#ifdef _PATH_DEFPATH
# define DEFAULT__PATH _PATH_DEFPATH
#else /* _PATH_DEFPATH */
# define DEFAULT__PATH DEFAULT_PATH
#endif /* _PATH_DEFPATH */
#ifndef offsetof
# define offsetof(type,id) ((size_t)&((type*)NULL)->id)
#endif
#ifndef HAVE_KILLPG
# define killpg(p, s) kill(-(p), (s))
#endif /* !HAVE_KILLPG */
/* Special cases for execve(2) */
#ifdef OS2
extern int ksh_execve(char *cmd, char **args, char **env, int flags);
#else /* OS2 */
# if defined(OS_ISC) && defined(_POSIX_SOURCE)
/* Kludge for ISC 3.2 (and other versions?) so programs will run correctly. */
# define ksh_execve(p, av, ev, flags) \
do { \
__setostype(0); \
execve(p, av, ev); \
__setostype(1); \
} while (0)
# else /* OS_ISC && _POSIX */
# define ksh_execve(p, av, ev, flags) execve(p, av, ev)
# endif /* OS_ISC && _POSIX */
#endif /* OS2 */
/* this is a hang-over from older versions of the os2 port */
#define ksh_dupbase(fd, base) fcntl(fd, F_DUPFD, base)
#ifdef HAVE_SIGSETJMP
# define ksh_sigsetjmp(env,sm) sigsetjmp((env), (sm))
# define ksh_siglongjmp(env,v) siglongjmp((env), (v))
# define ksh_jmp_buf sigjmp_buf
#else /* HAVE_SIGSETJMP */
# ifdef HAVE__SETJMP
# define ksh_sigsetjmp(env,sm) _setjmp(env)
# define ksh_siglongjmp(env,v) _longjmp((env), (v))
# else /* HAVE__SETJMP */
# define ksh_sigsetjmp(env,sm) setjmp(env)
# define ksh_siglongjmp(env,v) longjmp((env), (v))
# endif /* HAVE__SETJMP */
# define ksh_jmp_buf jmp_buf
#endif /* HAVE_SIGSETJMP */
#ifndef HAVE_DUP2
extern int dup2 ARGS((int, int));
#endif /* !HAVE_DUP2 */
/* Find a integer type that is at least 32 bits (or die) - SIZEOF_* defined
* by autoconf (assumes an 8 bit byte, but I'm not concerned).
* NOTE: INT32 may end up being more than 32 bits.
*/
#if SIZEOF_INT >= 4
# define INT32 int
#else /* SIZEOF_INT */
# if SIZEOF_LONG >= 4
# define INT32 long
# else /* SIZEOF_LONG */
#error cannot find 32 bit type...
# endif /* SIZEOF_LONG */
#endif /* SIZEOF_INT */
/* end of common headers */
/* Stop gcc and lint from complaining about possibly uninitialized variables */
#if defined(__GNUC__) || defined(lint)
# define UNINITIALIZED(var) var = 0
#else
# define UNINITIALIZED(var) var
#endif /* GNUC || lint */
/* some useful #defines */
#ifdef EXTERN
# define I__(i) = i
#else
# define I__(i)
# define EXTERN extern
# define EXTERN_DEFINED
#endif
#ifdef OS2
# define inDOS() (!(_emx_env & 0x200))
#endif
#ifndef EXECSHELL
/* shell to exec scripts (see also $SHELL initialization in main.c) */
# ifdef OS2
# define EXECSHELL (inDOS() ? "c:\\command.com" : "c:\\os2\\cmd.exe")
# define EXECSHELL_STR (inDOS() ? "COMSPEC" : "OS2_SHELL")
# else /* OS2 */
# define EXECSHELL "/bin/sh"
# define EXECSHELL_STR "EXECSHELL"
# endif /* OS2 */
#endif
/* ISABSPATH() means path is fully and completely specified,
* ISROOTEDPATH() means a .. as the first component is a no-op,
* ISRELPATH() means $PWD can be tacked on to get an absolute path.
*
* OS Path ISABSPATH ISROOTEDPATH ISRELPATH
* unix /foo yes yes no
* unix foo no no yes
* unix ../foo no no yes
* os2+cyg a:/foo yes yes no
* os2+cyg a:foo no no no
* os2+cyg /foo no yes no
* os2+cyg foo no no yes
* os2+cyg ../foo no no yes
* cyg //foo yes yes no
*/
#ifdef OS2
# define PATHSEP ';'
# define DIRSEP '/' /* even though \ is native */
# define DIRSEPSTR "\\"
# define ISDIRSEP(c) ((c) == '\\' || (c) == '/')
# define ISABSPATH(s) (((s)[0] && (s)[1] == ':' && ISDIRSEP((s)[2])))
# define ISROOTEDPATH(s) (ISDIRSEP((s)[0]) || ISABSPATH(s))
# define ISRELPATH(s) (!(s)[0] || ((s)[1] != ':' && !ISDIRSEP((s)[0])))
# define FILECHCONV(c) (isascii(c) && isupper(c) ? tolower(c) : c)
# define FILECMP(s1, s2) stricmp(s1, s2)
# define FILENCMP(s1, s2, n) strnicmp(s1, s2, n)
extern char *ksh_strchr_dirsep(const char *path);
extern char *ksh_strrchr_dirsep(const char *path);
# define chdir _chdir2
# define getcwd _getcwd2
#else
# define PATHSEP ':'
# define DIRSEP '/'
# define DIRSEPSTR "/"
# define ISDIRSEP(c) ((c) == '/')
#ifdef __CYGWIN__
# define ISABSPATH(s) \
(((s)[0] && (s)[1] == ':' && ISDIRSEP((s)[2])) || ISDIRSEP((s)[0]))
# define ISRELPATH(s) (!(s)[0] || ((s)[1] != ':' && !ISDIRSEP((s)[0])))
#else /* __CYGWIN__ */
# define ISABSPATH(s) ISDIRSEP((s)[0])
# define ISRELPATH(s) (!ISABSPATH(s))
#endif /* __CYGWIN__ */
# define ISROOTEDPATH(s) ISABSPATH(s)
# define FILECHCONV(c) c
# define FILECMP(s1, s2) strcmp(s1, s2)
# define FILENCMP(s1, s2, n) strncmp(s1, s2, n)
# define ksh_strchr_dirsep(p) strchr(p, DIRSEP)
# define ksh_strrchr_dirsep(p) strrchr(p, DIRSEP)
#endif
typedef int bool_t;
#define FALSE 0
#define TRUE 1
#define NELEM(a) (sizeof(a) / sizeof((a)[0]))
#define sizeofN(type, n) (sizeof(type) * (n))
#define BIT(i) (1<<(i)) /* define bit in flag */
/* Table flag type - needs > 16 and < 32 bits */
typedef INT32 Tflag;
#define NUFILE 32 /* Number of user-accessible files */
#define FDBASE 10 /* First file usable by Shell */
/* you're not going to run setuid shell scripts, are you? */
#define eaccess(path, mode) access(path, mode)
/* Make MAGIC a char that might be printed to make bugs more obvious, but
* not a char that is used often. Also, can't use the high bit as it causes
* portability problems (calling strchr(x, 0x80|'x') is error prone).
*/
#define MAGIC (7) /* prefix for *?[!{,} during expand */
#define ISMAGIC(c) ((unsigned char)(c) == MAGIC)
#define NOT '!' /* might use ^ (ie, [!...] vs [^..]) */
#define LINE 1024 /* input line size */
#define PATH 1024 /* pathname size (todo: PATH_MAX/pathconf()) */
#define ARRAYMAX 1023 /* max array index */
EXTERN const char *kshname; /* $0 */
EXTERN pid_t kshpid; /* $$, shell pid */
EXTERN pid_t procpid; /* pid of executing process */
EXTERN uid_t ksheuid; /* effective uid of shell */
EXTERN int exstat; /* exit status */
EXTERN int subst_exstat; /* exit status of last $(..)/`..` */
EXTERN const char *safe_prompt; /* safe prompt if PS1 substitution fails */
/*
* Area-based allocation built on malloc/free
*/
typedef struct Area {
struct link *freelist; /* free list */
} Area;
EXTERN Area aperm; /* permanent object space */
#define APERM &aperm
#define ATEMP &e->area
#ifdef MEM_DEBUG
# include "chmem.h" /* a debugging front end for malloc et. al. */
#endif /* MEM_DEBUG */
#ifdef KSH_DEBUG
# define kshdebug_init() kshdebug_init_()
# define kshdebug_printf(a) kshdebug_printf_ a
# define kshdebug_dump(a) kshdebug_dump_ a
#else /* KSH_DEBUG */
# define kshdebug_init()
# define kshdebug_printf(a)
# define kshdebug_dump(a)
#endif /* KSH_DEBUG */
/*
* parsing & execution environment
*/
EXTERN struct env {
short type; /* environment type - see below */
short flags; /* EF_* */
Area area; /* temporary allocation area */
struct block *loc; /* local variables and functions */
short *savefd; /* original redirected fd's */
struct env *oenv; /* link to previous environment */
ksh_jmp_buf jbuf; /* long jump back to env creator */
struct temp *temps; /* temp files */
} *e;
/* struct env.type values */
#define E_NONE 0 /* dummy environment */
#define E_PARSE 1 /* parsing command # */
#define E_FUNC 2 /* executing function # */
#define E_INCL 3 /* including a file via . # */
#define E_EXEC 4 /* executing command tree */
#define E_LOOP 5 /* executing for/while # */
#define E_ERRH 6 /* general error handler # */
/* # indicates env has valid jbuf (see unwind()) */
/* struct env.flag values */
#define EF_FUNC_PARSE BIT(0) /* function being parsed */
#define EF_BRKCONT_PASS BIT(1) /* set if E_LOOP must pass break/continue on */
#define EF_FAKE_SIGDIE BIT(2) /* hack to get info from unwind to quitenv */
/* Do breaks/continues stop at env type e? */
#define STOP_BRKCONT(t) ((t) == E_NONE || (t) == E_PARSE \
|| (t) == E_FUNC || (t) == E_INCL)
/* Do returns stop at env type e? */
#define STOP_RETURN(t) ((t) == E_FUNC || (t) == E_INCL)
/* values for ksh_siglongjmp(e->jbuf, 0) */
#define LRETURN 1 /* return statement */
#define LEXIT 2 /* exit statement */
#define LERROR 3 /* errorf() called */
#define LLEAVE 4 /* untrappable exit/error */
#define LINTR 5 /* ^C noticed */
#define LBREAK 6 /* break statement */
#define LCONTIN 7 /* continue statement */
#define LSHELL 8 /* return to interactive shell() */
#define LAEXPR 9 /* error in arithmetic expression */
/* option processing */
#define OF_CMDLINE 0x01 /* command line */
#define OF_SET 0x02 /* set builtin */
#define OF_SPECIAL 0x04 /* a special variable changing */
#define OF_INTERNAL 0x08 /* set internally by shell */
#define OF_ANY (OF_CMDLINE | OF_SET | OF_SPECIAL | OF_INTERNAL)
struct option {
const char *name; /* long name of option */
char c; /* character flag (if any) */
short flags; /* OF_* */
};
extern const struct option goptions[];
/*
* flags (the order of these enums MUST match the order in misc.c(options[]))
*/
enum sh_flag {
FEXPORT = 0, /* -a: export all */
#ifdef BRACE_EXPAND
FBRACEEXPAND, /* enable {} globbing */
#endif
FBGNICE, /* bgnice */
FCOMMAND, /* -c: (invocation) execute specified command */
#ifdef EMACS
FEMACS, /* emacs command editing */
FEMACSUSEMETA, /* use 8th bit as meta */
#endif
FERREXIT, /* -e: quit on error */
#ifdef EMACS
FGMACS, /* gmacs command editing */
#endif
FIGNOREEOF, /* eof does not exit */
FTALKING, /* -i: interactive */
FKEYWORD, /* -k: name=value anywhere */
FLOGIN, /* -l: a login shell */
FMARKDIRS, /* mark dirs with / in file name completion */
FMONITOR, /* -m: job control monitoring */
FNOCLOBBER, /* -C: don't overwrite existing files */
FNOEXEC, /* -n: don't execute any commands */
FNOGLOB, /* -f: don't do file globbing */
FNOHUP, /* -H: don't kill running jobs when login shell exits */
FNOLOG, /* don't save functions in history (ignored) */
#ifdef JOBS
FNOTIFY, /* -b: asynchronous job completion notification */
#endif
FNOUNSET, /* -u: using an unset var is an error */
FPHYSICAL, /* -o physical: don't do logical cd's/pwd's */
FPOSIX, /* -o posix: be posixly correct */
FPRIVILEGED, /* -p: use suid_profile */
FRESTRICTED, /* -r: restricted shell */
FSTDIN, /* -s: (invocation) parse stdin */
FTRACKALL, /* -h: create tracked aliases for all commands */
FVERBOSE, /* -v: echo input */
#ifdef VI
FVI, /* vi command editing */
FVIRAW, /* always read in raw mode (ignored) */
FVISHOW8, /* display chars with 8th bit set as is (versus M-) */
FVITABCOMPLETE, /* enable tab as file name completion char */
FVIESCCOMPLETE, /* enable ESC as file name completion in command mode */
#endif
FXTRACE, /* -x: execution trace */
FTALKING_I, /* (internal): initial shell was interactive */
FNFLAGS /* (place holder: how many flags are there) */
};
#define Flag(f) (shell_flags[(int) (f)])
EXTERN char shell_flags [FNFLAGS];
EXTERN char null [] I__(""); /* null value for variable */
EXTERN char space [] I__(" ");
EXTERN char newline [] I__("\n");
EXTERN char slash [] I__("/");
enum temp_type {
TT_HEREDOC_EXP, /* expanded heredoc */
TT_HIST_EDIT /* temp file used for history editing (fc -e) */
};
typedef enum temp_type Temp_type;
/* temp/heredoc files. The file is removed when the struct is freed. */
struct temp {
struct temp *next;
struct shf *shf;
int pid; /* pid of process parsed here-doc */
Temp_type type;
char *name;
};
/*
* stdio and our IO routines
*/
#define shl_spare (&shf_iob[0]) /* for c_read()/c_print() */
#define shl_stdout (&shf_iob[1])
#define shl_out (&shf_iob[2])
EXTERN int shl_stdout_ok;
/*
* trap handlers
*/
typedef struct trap {
int signal; /* signal number */
const char *name; /* short name */
const char *mess; /* descriptive name */
char *trap; /* trap command */
int volatile set; /* trap pending */
int flags; /* TF_* */
handler_t cursig; /* current handler (valid if TF_ORIG_* set) */
handler_t shtrap; /* shell signal handler */
} Trap;
/* values for Trap.flags */
#define TF_SHELL_USES BIT(0) /* shell uses signal, user can't change */
#define TF_USER_SET BIT(1) /* user has (tried to) set trap */
#define TF_ORIG_IGN BIT(2) /* original action was SIG_IGN */
#define TF_ORIG_DFL BIT(3) /* original action was SIG_DFL */
#define TF_EXEC_IGN BIT(4) /* restore SIG_IGN just before exec */
#define TF_EXEC_DFL BIT(5) /* restore SIG_DFL just before exec */
#define TF_DFL_INTR BIT(6) /* when received, default action is LINTR */
#define TF_TTY_INTR BIT(7) /* tty generated signal (see j_waitj) */
#define TF_CHANGED BIT(8) /* used by runtrap() to detect trap changes */
#define TF_FATAL BIT(9) /* causes termination if not trapped */
/* values for setsig()/setexecsig() flags argument */
#define SS_RESTORE_MASK 0x3 /* how to restore a signal before an exec() */
#define SS_RESTORE_CURR 0 /* leave current handler in place */
#define SS_RESTORE_ORIG 1 /* restore original handler */
#define SS_RESTORE_DFL 2 /* restore to SIG_DFL */
#define SS_RESTORE_IGN 3 /* restore to SIG_IGN */
#define SS_FORCE BIT(3) /* set signal even if original signal ignored */
#define SS_USER BIT(4) /* user is doing the set (ie, trap command) */
#define SS_SHTRAP BIT(5) /* trap for internal use (CHLD,ALRM,WINCH) */
#define SIGEXIT_ 0 /* for trap EXIT */
#define SIGERR_ SIGNALS /* for trap ERR */
EXTERN int volatile trap; /* traps pending? */
EXTERN int volatile intrsig; /* pending trap interrupts executing command */
EXTERN int volatile fatal_trap;/* received a fatal signal */
#ifndef FROM_TRAP_C
/* Kludge to avoid bogus re-declaration of sigtraps[] error on AIX 3.2.5 */
extern Trap sigtraps[SIGNALS+1];
#endif /* !FROM_TRAP_C */
#ifdef KSH
/*
* TMOUT support
*/
/* values for ksh_tmout_state */
enum tmout_enum {
TMOUT_EXECUTING = 0, /* executing commands */
TMOUT_READING, /* waiting for input */
TMOUT_LEAVING /* have timed out */
};
EXTERN unsigned int ksh_tmout;
EXTERN enum tmout_enum ksh_tmout_state I__(TMOUT_EXECUTING);
#endif /* KSH */
/* For "You have stopped jobs" message */
EXTERN int really_exit;
/*
* fast character classes
*/
#define C_ALPHA BIT(0) /* a-z_A-Z */
#define C_DIGIT BIT(1) /* 0-9 */
#define C_LEX1 BIT(2) /* \0 \t\n|&;<>() */
#define C_VAR1 BIT(3) /* *@#!$-? */
#define C_IFSWS BIT(4) /* \t \n (IFS white space) */
#define C_SUBOP1 BIT(5) /* "=-+?" */
#define C_SUBOP2 BIT(6) /* "#%" */
#define C_IFS BIT(7) /* $IFS */
#define C_QUOTE BIT(8) /* \n\t"#$&'()*;<>?[\`| (needing quoting) */
extern short ctypes [];
#define ctype(c, t) !!(ctypes[(unsigned char)(c)]&(t))
#define letter(c) ctype(c, C_ALPHA)
#define digit(c) ctype(c, C_DIGIT)
#define letnum(c) ctype(c, C_ALPHA|C_DIGIT)
EXTERN int ifs0 I__(' '); /* for "$*" */
/* Argument parsing for built-in commands and getopts command */
/* Values for Getopt.flags */
#define GF_ERROR BIT(0) /* call errorf() if there is an error */
#define GF_PLUSOPT BIT(1) /* allow +c as an option */
#define GF_NONAME BIT(2) /* don't print argv[0] in errors */
/* Values for Getopt.info */
#define GI_MINUS BIT(0) /* an option started with -... */
#define GI_PLUS BIT(1) /* an option started with +... */
#define GI_MINUSMINUS BIT(2) /* arguments were ended with -- */
typedef struct {
int optind;
int uoptind;/* what user sees in $OPTIND */
char *optarg;
int flags; /* see GF_* */
int info; /* see GI_* */
unsigned int p; /* 0 or index into argv[optind - 1] */
char buf[2]; /* for bad option OPTARG value */
} Getopt;
EXTERN Getopt builtin_opt; /* for shell builtin commands */
EXTERN Getopt user_opt; /* parsing state for getopts builtin command */
#ifdef KSH
/* This for co-processes */
typedef INT32 Coproc_id; /* something that won't (realisticly) wrap */
struct coproc {
int read; /* pipe from co-process's stdout */
int readw; /* other side of read (saved temporarily) */
int write; /* pipe to co-process's stdin */
Coproc_id id; /* id of current output pipe */
int njobs; /* number of live jobs using output pipe */
void *job; /* 0 or job of co-process using input pipe */
};
EXTERN struct coproc coproc;
#endif /* KSH */
/* Used in jobs.c and by coprocess stuff in exec.c */
#ifdef JOB_SIGS
EXTERN sigset_t sm_default, sm_sigchld;
#endif /* JOB_SIGS */
extern char ksh_version[];
/* name of called builtin function (used by error functions) */
EXTERN char *builtin_argv0;
EXTERN Tflag builtin_flag; /* flags of called builtin (SPEC_BI, etc.) */
/* current working directory, and size of memory allocated for same */
EXTERN char *current_wd;
EXTERN int current_wd_size;
#ifdef EDIT
/* Minimum required space to work with on a line - if the prompt leaves less
* space than this on a line, the prompt is truncated.
*/
# define MIN_EDIT_SPACE 7
/* Minimum allowed value for x_cols: 2 for prompt, 3 for " < " at end of line
*/
# define MIN_COLS (2 + MIN_EDIT_SPACE + 3)
EXTERN int x_cols I__(80); /* tty columns */
#else
# define x_cols 80 /* for pr_menu(exec.c) */
#endif
/* These to avoid bracket matching problems */
#define OPAREN '('
#define CPAREN ')'
#define OBRACK '['
#define CBRACK ']'
#define OBRACE '{'
#define CBRACE '}'
/* Determine the location of the system (common) profile */
#ifndef KSH_SYSTEM_PROFILE
# ifdef __NeXT
# define KSH_SYSTEM_PROFILE "/etc/profile.std"
# else /* __NeXT */
# define KSH_SYSTEM_PROFILE "/etc/profile"
# endif /* __NeXT */
#endif /* KSH_SYSTEM_PROFILE */
/* Used by v_evaluate() and setstr() to control action when error occurs */
#define KSH_UNWIND_ERROR 0 /* unwind the stack (longjmp) */
#define KSH_RETURN_ERROR 1 /* return 1/0 for success/failure */
#include "shf.h"
#include "table.h"
#include "tree.h"
#include "expand.h"
#include "lex.h"
#include "proto.h"
/* be sure not to interfere with anyone else's idea about EXTERN */
#ifdef EXTERN_DEFINED
# undef EXTERN_DEFINED
# undef EXTERN
#endif
#undef I__

1302
bin/ksh/shf.c Normal file

File diff suppressed because it is too large Load Diff

87
bin/ksh/shf.h Normal file
View File

@@ -0,0 +1,87 @@
/* $NetBSD: shf.h,v 1.3 1999/10/20 15:10:00 hubertf Exp $ */
#ifndef SHF_H
# define SHF_H
/*
* Shell file I/O routines
*/
/* $Id: shf.h,v 1.3 1999/10/20 15:10:00 hubertf Exp $ */
#define SHF_BSIZE 512
#define shf_fileno(shf) ((shf)->fd)
#define shf_setfileno(shf,nfd) ((shf)->fd = (nfd))
#define shf_getc(shf) ((shf)->rnleft > 0 ? (shf)->rnleft--, *(shf)->rp++ : \
shf_getchar(shf))
#define shf_putc(c, shf) ((shf)->wnleft == 0 ? shf_putchar((c), (shf)) \
: ((shf)->wnleft--, *(shf)->wp++ = (c)))
#define shf_eof(shf) ((shf)->flags & SHF_EOF)
#define shf_error(shf) ((shf)->flags & SHF_ERROR)
#define shf_errno(shf) ((shf)->errno_)
#define shf_clearerr(shf) ((shf)->flags &= ~(SHF_EOF | SHF_ERROR))
/* Flags passed to shf_*open() */
#define SHF_RD 0x0001
#define SHF_WR 0x0002
#define SHF_RDWR (SHF_RD|SHF_WR)
#define SHF_ACCMODE 0x0003 /* mask */
#define SHF_GETFL 0x0004 /* use fcntl() to figure RD/WR flags */
#define SHF_UNBUF 0x0008 /* unbuffered I/O */
#define SHF_CLEXEC 0x0010 /* set close on exec flag */
#define SHF_MAPHI 0x0020 /* make fd > FDBASE (and close orig)
* (shf_open() only) */
#define SHF_DYNAMIC 0x0040 /* string: increase buffer as needed */
#define SHF_INTERRUPT 0x0080 /* EINTR in read/write causes error */
/* Flags used internally */
#define SHF_STRING 0x0100 /* a string, not a file */
#define SHF_ALLOCS 0x0200 /* shf and shf->buf were alloc()ed */
#define SHF_ALLOCB 0x0400 /* shf->buf was alloc()ed */
#define SHF_ERROR 0x0800 /* read()/write() error */
#define SHF_EOF 0x1000 /* read eof (sticky) */
#define SHF_READING 0x2000 /* currently reading: rnleft,rp valid */
#define SHF_WRITING 0x4000 /* currently writing: wnleft,wp valid */
struct shf {
int flags; /* see SHF_* */
unsigned char *rp; /* read: current position in buffer */
int rbsize; /* size of buffer (1 if SHF_UNBUF) */
int rnleft; /* read: how much data left in buffer */
unsigned char *wp; /* write: current position in buffer */
int wbsize; /* size of buffer (0 if SHF_UNBUF) */
int wnleft; /* write: how much space left in buffer */
unsigned char *buf; /* buffer */
int fd; /* file descriptor */
int errno_; /* saved value of errno after error */
int bsize; /* actual size of buf */
Area *areap; /* area shf/buf were allocated in */
};
extern struct shf shf_iob[];
struct shf *shf_open ARGS((const char *name, int oflags, int mode,
int sflags));
struct shf *shf_fdopen ARGS((int fd, int sflags, struct shf *shf));
struct shf *shf_reopen ARGS((int fd, int sflags, struct shf *shf));
struct shf *shf_sopen ARGS((char *buf, int bsize, int sflags,
struct shf *shf));
int shf_close ARGS((struct shf *shf));
int shf_fdclose ARGS((struct shf *shf));
char *shf_sclose ARGS((struct shf *shf));
int shf_finish ARGS((struct shf *shf));
int shf_flush ARGS((struct shf *shf));
int shf_seek ARGS((struct shf *shf, off_t where, int from));
int shf_read ARGS((char *buf, int bsize, struct shf *shf));
char *shf_getse ARGS((char *buf, int bsize, struct shf *shf));
int shf_getchar ARGS((struct shf *shf));
int shf_ungetc ARGS((int c, struct shf *shf));
int shf_putchar ARGS((int c, struct shf *shf));
int shf_puts ARGS((const char *s, struct shf *shf));
int shf_write ARGS((const char *buf, int nbytes, struct shf *shf));
int shf_fprintf ARGS((struct shf *shf, const char *fmt, ...));
int shf_snprintf ARGS((char *buf, int bsize, const char *fmt, ...));
char *shf_smprintf ARGS((const char *fmt, ...));
int shf_vfprintf ARGS((struct shf *, const char *fmt, va_list args));
#endif /* SHF_H */

486
bin/ksh/sigact.c Normal file
View File

@@ -0,0 +1,486 @@
/* $NetBSD: sigact.c,v 1.4 2003/06/23 11:39:03 agc Exp $ */
/* NAME:
* sigact.c - fake sigaction(2)
*
* SYNOPSIS:
* #include "sigact.h"
*
* int sigaction(int sig, struct sigaction *act,
* struct sigaction *oact);
* int sigaddset(sigset_t *mask, int sig);
* int sigdelset(sigset_t *mask, int sig);
* int sigemptyset(sigset_t *mask);
* int sigfillset(sigset_t *mask);
* int sigismember(sigset_t *mask, int sig);
* int sigpending(sigset_t *set);
* int sigprocmask(int how, sigset_t *set, sigset_t *oset);
* int sigsuspend(sigset_t *mask);
*
* RETSIGTYPE (*Signal(int sig, RETSIGTYPE (*disp)(int)))(int);
*
* DESCRIPTION:
* This is a fake sigaction implementation. It uses
* sigsetmask(2) et al or sigset(2) and friends if
* available, otherwise it just uses signal(2). If it
* thinks sigaction(2) really exists it compiles to "almost"
* nothing.
*
* In any case it provides a Signal() function that is
* implemented in terms of sigaction().
* If not using signal(2) as part of the underlying
* implementation (USE_SIGNAL or USE_SIGMASK), and
* NO_SIGNAL is not defined, it also provides a signal()
* function that calls Signal().
*
* The need for all this mucking about is the problems
* caused by mixing various signal handling mechanisms in
* the one process. This module allows for a consistent
* POSIX compliant interface to whatever is actually
* available.
*
* sigaction() allows the caller to examine and/or set the
* action to be associated with a given signal. "act" and
* "oact" are pointers to 'sigaction structs':
*.nf
*
* struct sigaction
* {
* RETSIGTYPE (*sa_handler)();
* sigset_t sa_mask;
* int sa_flags;
* };
*.fi
*
* RETSIGTYPE is normally 'void' in the POSIX implementation
* and for most current systems. On some older UNIX
* systems, signal handlers do not return 'void', so
* this implementation keeps 'sa_handler' inline with the
* hosts normal signal handling conventions.
* 'sa_mask' controls which signals will be blocked while
* the selected signal handler is active. It is not used
* in this implementation.
* 'sa_flags' controls various semantics such as whether
* system calls should be automagically restarted
* (SA_RESTART) etc. It is not used in this
* implementation.
* Either "act" or "oact" may be NULL in which case the
* appropriate operation is skipped.
*
* sigaddset() adds "sig" to the sigset_t pointed to by "mask".
*
* sigdelset() removes "sig" from the sigset_t pointed to
* by "mask".
*
* sigemptyset() makes the sigset_t pointed to by "mask" empty.
*
* sigfillset() makes the sigset_t pointed to by "mask"
* full ie. match all signals.
*
* sigismember() returns true if "sig" is found in "*mask".
*
* sigpending() is supposed to return "set" loaded with the
* set of signals that are blocked and pending for the
* calling process. It does nothing in this impementation.
*
* sigprocmask() is used to examine and/or change the
* signal mask for the calling process. Either "set" or
* "oset" may be NULL in which case the appropriate
* operation is skipped. "how" may be one of SIG_BLOCK,
* SIG_UNBLOCK or SIG_SETMASK. If this package is built
* with USE_SIGNAL, then this routine achieves nothing.
*
* sigsuspend() sets the signal mask to "*mask" and waits
* for a signal to be delivered after which the previous
* mask is restored.
*
*
* RETURN VALUE:
* 0==success, -1==failure
*
* BUGS:
* Since we fake most of this, don't expect fancy usage to
* work.
*
* AUTHOR:
* Simon J. Gerraty <sjg@zen.void.oz.au>
*/
/* COPYRIGHT:
* @(#)Copyright (c) 1992 Simon J. Gerraty
*
* This is free software. It comes with NO WARRANTY.
* Permission to use, modify and distribute this source code
* is granted subject to the following conditions.
* 1/ that that the above copyright notice and this notice
* are preserved in all copies and that due credit be given
* to the author.
* 2/ that any changes to this code are clearly commented
* as such so that the author does get blamed for bugs
* other than his own.
*
* Please send copies of changes and bug-fixes to:
* sjg@zen.void.oz.au
*
*/
/* Changes to sigact.c for pdksh, Michael Rendell <michael@cs.mun.ca>:
* - sigsuspend(): pass *mask to bsd4.2 sigpause instead of mask.
* - changed SIG_HDLR to RETSIGTYPE for use with GNU autoconf
* - added and used RETSIGVAL
* - include sh.h instead of signal.h (to get *_SIGNALS macros)
* - changed if !SA_NOCLDSTOP ... to USE_FAKE_SIGACT to avoid confusion
* - set the USE_* defines using the *_SIGNALS defines from autoconf
* - sigaction(): if using BSD signals, use sigvec() (used to use
* signal()) and set the SV_INTERRUPT flag (POSIX says syscalls
* are interrupted and pdksh needs this behaviour).
* - define IS_KSH before including anything; ifdef out routines
* not used in ksh if IS_KSH is defined (same in sigact.h).
* - use ARGS() instead of __P()
* - sigaction(),sigsuspend(),Signal(),signal(): use handler_t typedef
* instead of explicit type.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: sigact.c,v 1.4 2003/06/23 11:39:03 agc Exp $");
#endif
/*
#include <signal.h>
*/
#define IS_KSH
#include "sh.h"
/*
#ifndef __P
# define __P(p) p
#endif
*/
/*
* some systems have a faulty sigaction() implementation!
* Allow us to bypass it.
* Or they may have installed sigact.h as signal.h which is why
* we have SA_NOCLDSTOP defined.
*/
#ifdef USE_FAKE_SIGACT /* let autoconf decide.. */
/* #if !defined(SA_NOCLDSTOP) || defined(_SIGACT_H) || defined(USE_SIGNAL) || defined(USE_SIGSET) || defined(USE_SIGMASK) */
/* Let autoconf decide which to use */
#ifdef BSD42_SIGNALS
# define USE_SIGMASK
#else
# ifdef BSD41_SIGNALS
# define USE_SIGSET
# else
# define USE_SIGNAL
# endif
#endif /* BSD42_SIGNALS */
/*
* if we haven't been told,
* try and guess what we should implement with.
*/
#if !defined(USE_SIGSET) && !defined(USE_SIGMASK) && !defined(USE_SIGNAL)
# if defined(sigmask) || defined(BSD) || defined(_BSD) && !defined(BSD41)
# define USE_SIGMASK
# else
# ifndef NO_SIGSET
# define USE_SIGSET
# else
# define USE_SIGNAL
# endif
# endif
#endif
/*
* if we still don't know, we're in trouble
*/
#if !defined(USE_SIGSET) && !defined(USE_SIGMASK) && !defined(USE_SIGNAL)
error must know what to implement with
#endif
#include "sigact.h"
/*
* in case signal() has been mapped to our Signal().
*/
#undef signal
int
sigaction(sig, act, oact)
int sig;
struct sigaction *act, *oact;
{
handler_t oldh;
if (act)
{
#ifdef USE_SIGSET
oldh = sigset(sig, act->sa_handler);
#else
# ifdef USE_SIGMASK
struct sigvec nsv,osv;
nsv.sv_handler = act->sa_handler;
nsv.sv_mask = 0; /* punt */
nsv.sv_flags = SV_INTERRUPT; /* punt */
sigvec(sig, &nsv, &osv);
oldh = osv.sv_handler;
# else /* USE_SIGMASK */
oldh = signal(sig, act->sa_handler);
# endif /* USE_SIGMASK */
#endif
}
else
{
if (oact)
{
#ifdef USE_SIGSET
oldh = sigset(sig, SIG_IGN);
#else
oldh = signal(sig, SIG_IGN);
#endif
if (oldh != SIG_IGN && oldh != SIG_ERR)
{
#ifdef USE_SIGSET
(void) sigset(sig, oldh);
#else
(void) signal(sig, oldh);
#endif
}
}
}
if (oact)
{
oact->sa_handler = oldh;
}
return 0; /* hey we're faking it */
}
int
sigaddset(mask, sig)
sigset_t *mask;
int sig;
{
*mask |= sigmask(sig);
return 0;
}
#ifndef IS_KSH
int
sigdelset(mask, sig)
sigset_t *mask;
int sig;
{
*mask &= ~(sigmask(sig));
return 0;
}
#endif /* IS_KSH */
int
sigemptyset(mask)
sigset_t *mask;
{
*mask = 0;
return 0;
}
#ifndef IS_KSH
int
sigfillset(mask)
sigset_t *mask;
{
*mask = ~0;
return 0;
}
#endif /* IS_KSH */
#ifndef IS_KSH
int
sigismember(mask, sig)
sigset_t *mask;
int sig;
{
return ((*mask) & sigmask(sig));
}
#endif /* IS_KSH */
#ifndef IS_KSH
int
sigpending(set)
sigset_t *set;
{
return 0; /* faking it! */
}
#endif /* IS_KSH */
int
sigprocmask(how, set, oset)
int how;
sigset_t *set, *oset;
{
#ifdef USE_SIGSET
register int i;
#endif
static sigset_t sm;
static int once = 0;
if (!once)
{
/*
* initally we clear sm,
* there after, it represents the last
* thing we did.
*/
once++;
#ifdef USE_SIGMASK
sm = sigblock(0);
#else
sm = 0;
#endif
}
if (oset)
*oset = sm;
if (set)
{
switch (how)
{
case SIG_BLOCK:
sm |= *set;
break;
case SIG_UNBLOCK:
sm &= ~(*set);
break;
case SIG_SETMASK:
sm = *set;
break;
}
#ifdef USE_SIGMASK
(void) sigsetmask(sm);
#else
# ifdef USE_SIGSET
for (i = 1; i < NSIG; i++)
{
if (how == SIG_UNBLOCK)
{
if (*set & sigmask(i))
sigrelse(i);
}
else
if (sm & sigmask(i))
{
sighold(i);
}
}
# endif
#endif
}
return 0;
}
int
sigsuspend(mask)
sigset_t *mask;
{
#ifdef USE_SIGMASK
sigpause(*mask);
#else
register int i;
# ifdef USE_SIGSET
for (i = 1; i < NSIG; i++)
{
if (*mask & sigmask(i))
{
/* not the same sigpause() as above! */
sigpause(i);
break;
}
}
# else /* signal(2) only */
handler_t oldh;
/*
* make sure that signals in mask will not
* be ignored.
*/
for (i = 1; i < NSIG; i++)
{
if (*mask & sigmask(i))
{
if ((oldh = signal(i, SIG_DFL)) != SIG_ERR &&
oldh != SIG_IGN &&
oldh != SIG_DFL)
(void) signal(i, oldh); /* restore handler */
}
}
pause(); /* wait for a signal */
# endif
#endif
return 0;
}
#endif /* USE_FAKE_SIGACT (was ! SA_NOCLDSTOP) */
#if !defined(RETSIGTYPE)
# define RETSIGTYPE void
# define RETSIGVAL
#endif
#if !defined(SIG_ERR)
# define SIG_ERR (RETSIGTYPE (*)())-1
#endif
/*
* an implementation of signal() using sigaction().
*/
#ifndef IS_KSH
handler_t Signal(sig, handler)
int sig;
handler_t handler;
{
struct sigaction act, oact;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (sigaction(sig, &act, &oact) < 0)
return (SIG_ERR);
return (oact.sa_handler);
}
#endif /* IS_KSH */
#ifndef IS_KSH
#if !defined(USE_SIGNAL) && !defined(USE_SIGMASK) && !defined(NO_SIGNAL)
/*
* ensure we avoid signal mayhem
*/
handler_t signal(sig, handler)
int sig;
handler_t handler;
{
return (Signal(sig, handler));
}
#endif
#endif /* IS_KSH */
/* This lot (for GNU-Emacs) goes at the end of the file. */
/*
* Local Variables:
* version-control:t
* comment-column:40
* End:
*/

125
bin/ksh/sigact.h Normal file
View File

@@ -0,0 +1,125 @@
/* $NetBSD: sigact.h,v 1.3 2002/05/25 23:29:17 wiz Exp $ */
/* NAME:
* sigact.h - sigaction et al
*
* SYNOPSIS:
* #include "sigact.h"
*
* DESCRIPTION:
* This header is the interface to a fake sigaction(2)
* implementation. It provides a POSIX compliant interface
* to whatever signal handling mechanisms are available.
* It also provides a Signal() function that is implemented
* in terms of sigaction().
* If not using signal(2) as part of the underlying
* implementation (USE_SIGNAL or USE_SIGMASK), and
* NO_SIGNAL is not defined, it also provides a signal()
* function that calls Signal().
*
* SEE ALSO:
* sigact.c
*/
/*
* RCSid:
* $NetBSD: sigact.h,v 1.3 2002/05/25 23:29:17 wiz Exp $
*/
/* Changes to sigact.h for pdksh, Michael Rendell <michael@cs.mun.ca>:
* - changed SIG_HDLR to RETSIGTYPE for use with GNU autoconf
* - added RETSIGVAL
* - ifdef'd out ARGS(), volatile and const initializations
* - ifdef'd out sigset_t definition - let autoconf handle it
* - ifdef out routines not used in ksh if IS_KSH is defined
* (same in sigact.c).
*/
#ifndef _SIGACT_H
#define _SIGACT_H
/*
* most modern systems use void for signal handlers but
* not all.
*/
#ifndef RETSIGTYPE
# define RETSIGTYPE void
# define RETSIGVAL
#endif
#if 0 /* ARGS(), volatile and const are already set up in config*.h -mhr */
#undef ARGS
#define ARGS(p) p
#endif
#ifndef IS_KSH
handler_t Signal ARGS((int sig, handler_t disp));
#endif /* IS_KSH */
/*
* if you want to install this header as signal.h,
* modify this to pick up the original signal.h
*/
#ifndef SIGKILL
# include <signal.h>
#endif
#ifndef SIG_ERR
# define SIG_ERR ((handler_t) -1)
#endif
#ifndef BADSIG
# define BADSIG SIG_ERR
#endif
#ifndef SA_NOCLDSTOP
/* we assume we need the fake sigaction */
/* sa_flags */
#define SA_NOCLDSTOP 1 /* don't send SIGCHLD on child stop */
#define SA_RESTART 2 /* re-start I/O */
/* sigprocmask flags */
#define SIG_BLOCK 1
#define SIG_UNBLOCK 2
#define SIG_SETMASK 4
#if 0 /* autoconf will define sigset_t if it isn't available */
/*
* this is a bit untidy
*/
#if !defined(__sys_stdtypes_h)
typedef unsigned int sigset_t;
#endif
#endif /* 0 */
/*
* POSIX sa_handler should return void, but since we are
* implementing in terms of something else, it may
* be appropriate to use the normal RETSIGTYPE return type
*/
struct sigaction
{
handler_t sa_handler;
sigset_t sa_mask;
int sa_flags;
};
int sigaction ARGS(( int sig, struct sigaction *act, struct sigaction *oact ));
int sigaddset ARGS(( sigset_t *mask, int sig ));
#ifndef IS_KSH
int sigdelset ARGS(( sigset_t *mask, int sig ));
#endif /* IS_KSH */
int sigemptyset ARGS(( sigset_t *mask ));
#ifndef IS_KSH
int sigfillset ARGS(( sigset_t *mask ));
int sigismember ARGS(( sigset_t *mask, int sig ));
int sigpending ARGS(( sigset_t *set ));
#endif /* IS_KSH */
int sigprocmask ARGS(( int how, sigset_t *set, sigset_t *oset ));
int sigsuspend ARGS(( sigset_t *mask ));
#ifndef sigmask
# define sigmask(s) (1<<((s)-1)) /* convert SIGnum to mask */
#endif
#if !defined(NSIG) && defined(_NSIG)
# define NSIG _NSIG
#endif
#endif /* ! SA_NOCLDSTOP */
#endif /* _SIGACT_H */

56
bin/ksh/siglist.in Normal file
View File

@@ -0,0 +1,56 @@
# $NetBSD: siglist.in,v 1.2 1997/01/12 19:12:17 tls Exp $
#
# List of signals used to initialize ksh's signal table (see trap.c
# and siglist.sh).
#
# Note that if a system has multiple defines for the same signal
# (eg, SIGABRT vs SIGIOT, SIGCHLD vs SIGCLD), only the first one
# will be seen, so the order in this list is important.
#
HUP Hangup
INT Interrupt
QUIT Quit
ILL Illegal instruction
TRAP Trace trap
# before IOT (ABRT is posix and ABRT is sometimes the same as IOT)
ABRT Abort
IOT IOT instruction
EMT EMT trap
FPE Floating point exception
KILL Killed
# before BUS (linux doesn't really have a BUS, but defines it to UNUSED)
UNUSED Unused
BUS Bus error
SEGV Memory fault
SYS Bad system call
PIPE Broken pipe
ALRM Alarm clock
TERM Terminated
STKFLT Stack fault
IO I/O possible
XCPU CPU time limit exceeded
XFSZ File size limit exceeded
VTALRM Virtual timer expired
PROF Profiling timer expired
WINCH Window size change
LOST File lock lost
USR1 User defined signal 1
USR2 User defined signal 2
PWR Power-fail/Restart
POLL Pollable event occurred
STOP Stopped (signal)
TSTP Stopped
CONT Continued
# before CLD (CHLD is posix and CHLD is sometimes the same as CLD)
CHLD Child exited
CLD Child exited
TTIN Stopped (tty input)
TTOU Stopped (tty output)
INFO Information request
URG Urgent I/O condition
# Solaris (svr4?) signals
WAITING No runnable LWPs
LWP Inter-LWP signal
FREEZE Checkpoint freeze
THAW Checkpoint thaw
CANCEL Thread cancellation

44
bin/ksh/siglist.sh Executable file
View File

@@ -0,0 +1,44 @@
#!/bin/sh
# $NetBSD: siglist.sh,v 1.9 2011/01/23 17:11:55 hauke Exp $
#
# Script to generate a sorted, complete list of signals, suitable
# for inclusion in trap.c as array initializer.
#
set -e
: ${AWK:=awk}
: ${SED:=sed}
in=tmpi$$.c
out=tmpo$$.c
ecode=1
trapsigs='0 1 2 13 15'
trap 'rm -f $in $out; trap 0; exit $ecode' $trapsigs
CPP="${1-cc -E}"
# The trap here to make up for a bug in bash (1.14.3(1)) that calls the trap
(trap $trapsigs;
echo '#include "sh.h"';
echo ' { QwErTy SIGNALS , "DUMMY" , "hook for number of signals" },';
${SED} -e '/^[ ]*#/d' -e 's/^[ ]*\([^ ][^ ]*\)[ ][ ]*\(.*[^ ]\)[ ]*$/#ifdef SIG\1\
{ QwErTy .signal = SIG\1 , .name = "\1", .mess = "\2" },\
#endif/') > $in
$CPP $in > $out
${SED} -n 's/{ QwErTy/{/p' < $out | ${AWK} '{print NR, $0}' | sort -k 5n -k 1n |
${SED} 's/^[0-9]* //' |
${AWK} 'BEGIN { last=0; nsigs=0; }
{
if ($4 ~ /^[0-9][0-9]*$/ && $5 == ",") {
n = $4;
if (n > 0 && n != last) {
while (++last < n) {
printf "\t{ .signal = %d , .name = NULL, .mess = `Signal %d` } ,\n", last, last;
}
print;
}
}
}' |
tr '`' '"' | grep -v '"DUMMY"'
ecode=0

958
bin/ksh/syn.c Normal file
View File

@@ -0,0 +1,958 @@
/* $NetBSD: syn.c,v 1.9 2006/10/16 00:07:32 christos Exp $ */
/*
* shell parser (C version)
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: syn.c,v 1.9 2006/10/16 00:07:32 christos Exp $");
#endif
#include "sh.h"
#include "c_test.h"
#include <assert.h>
struct nesting_state {
int start_token; /* token than began nesting (eg, FOR) */
int start_line; /* line nesting began on */
};
static void yyparse ARGS((void));
static struct op *pipeline ARGS((int cf));
static struct op *andor ARGS((void));
static struct op *c_list ARGS((int multi));
static struct ioword *synio ARGS((int cf));
static void musthave ARGS((int c, int cf));
static struct op *nested ARGS((int type, int smark, int emark));
static struct op *get_command ARGS((int cf));
static struct op *dogroup ARGS((void));
static struct op *thenpart ARGS((void));
static struct op *elsepart ARGS((void));
static struct op *caselist ARGS((void));
static struct op *casepart ARGS((int endtok));
static struct op *function_body ARGS((char *name, int ksh_func));
static char ** wordlist ARGS((void));
static struct op *block ARGS((int type, struct op *t1, struct op *t2,
char **wp));
static struct op *newtp ARGS((int type));
static void syntaxerr ARGS((const char *what))
GCC_FUNC_ATTR(noreturn);
static void nesting_push ARGS((struct nesting_state *save, int tok));
static void nesting_pop ARGS((struct nesting_state *saved));
static int assign_command ARGS((char *s));
static int inalias ARGS((struct source *s));
#ifdef KSH
static int dbtestp_isa ARGS((Test_env *te, Test_meta meta));
static const char *dbtestp_getopnd ARGS((Test_env *te, Test_op op,
int do_eval));
static int dbtestp_eval ARGS((Test_env *te, Test_op op, const char *opnd1,
const char *opnd2, int do_eval));
static void dbtestp_error ARGS((Test_env *te, int offset, const char *msg));
#endif /* KSH */
static struct op *outtree; /* yyparse output */
static struct nesting_state nesting; /* \n changed to ; */
static int reject; /* token(cf) gets symbol again */
static int symbol; /* yylex value */
#define REJECT (reject = 1)
#define ACCEPT (reject = 0)
#define token(cf) \
((reject) ? (ACCEPT, symbol) : (symbol = yylex(cf)))
#define tpeek(cf) \
((reject) ? (symbol) : (REJECT, symbol = yylex(cf)))
static void
yyparse()
{
int c;
ACCEPT;
outtree = c_list(source->type == SSTRING);
c = tpeek(0);
if (c == 0 && !outtree)
outtree = newtp(TEOF);
else if (c != '\n' && c != 0)
syntaxerr((char *) 0);
}
static struct op *
pipeline(cf)
int cf;
{
register struct op *t, *p, *tl = NULL;
t = get_command(cf);
if (t != NULL) {
while (token(0) == '|') {
if ((p = get_command(CONTIN)) == NULL)
syntaxerr((char *) 0);
if (tl == NULL)
t = tl = block(TPIPE, t, p, NOWORDS);
else
tl = tl->right = block(TPIPE, tl->right, p, NOWORDS);
}
REJECT;
}
return (t);
}
static struct op *
andor()
{
register struct op *t, *p;
register int c;
t = pipeline(0);
if (t != NULL) {
while ((c = token(0)) == LOGAND || c == LOGOR) {
if ((p = pipeline(CONTIN)) == NULL)
syntaxerr((char *) 0);
t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS);
}
REJECT;
}
return (t);
}
static struct op *
c_list(multi)
int multi;
{
register struct op *t = NULL, *p, *tl = NULL;
register int c;
int have_sep;
while (1) {
p = andor();
/* Token has always been read/rejected at this point, so
* we don't worry about what flags to pass token()
*/
c = token(0);
have_sep = 1;
if (c == '\n' && (multi || inalias(source))) {
if (!p) /* ignore blank lines */
continue;
} else if (!p)
break;
else if (c == '&' || c == COPROC)
p = block(c == '&' ? TASYNC : TCOPROC,
p, NOBLOCK, NOWORDS);
else if (c != ';')
have_sep = 0;
if (!t)
t = p;
else if (!tl)
t = tl = block(TLIST, t, p, NOWORDS);
else
tl = tl->right = block(TLIST, tl->right, p, NOWORDS);
if (!have_sep)
break;
}
REJECT;
return t;
}
static struct ioword *
synio(cf)
int cf;
{
register struct ioword *iop;
int ishere;
if (tpeek(cf) != REDIR)
return NULL;
ACCEPT;
iop = yylval.iop;
ishere = (iop->flag&IOTYPE) == IOHERE;
musthave(LWORD, ishere ? HEREDELIM : 0);
if (ishere) {
iop->delim = yylval.cp;
if (*ident != 0) /* unquoted */
iop->flag |= IOEVAL;
if (herep >= &heres[HERES])
yyerror("too many <<'s\n");
*herep++ = iop;
} else
iop->name = yylval.cp;
return iop;
}
static void
musthave(c, cf)
int c, cf;
{
if ((token(cf)) != c)
syntaxerr((char *) 0);
}
static struct op *
nested(type, smark, emark)
int type, smark, emark;
{
register struct op *t;
struct nesting_state old_nesting;
nesting_push(&old_nesting, smark);
t = c_list(TRUE);
musthave(emark, KEYWORD|ALIAS);
nesting_pop(&old_nesting);
return (block(type, t, NOBLOCK, NOWORDS));
}
static struct op *
get_command(cf)
int cf;
{
register struct op *t;
register int c, iopn = 0, syniocf;
struct ioword *iop, **iops;
XPtrV args, vars;
struct nesting_state old_nesting;
iops = (struct ioword **) alloc(sizeofN(struct ioword *, NUFILE+1),
ATEMP);
XPinit(args, 16);
XPinit(vars, 16);
syniocf = KEYWORD|ALIAS;
switch (c = token(cf|KEYWORD|ALIAS|VARASN)) {
default:
REJECT;
afree((void*) iops, ATEMP);
XPfree(args);
XPfree(vars);
return NULL; /* empty line */
case LWORD:
case REDIR:
REJECT;
syniocf &= ~(KEYWORD|ALIAS);
t = newtp(TCOM);
t->lineno = source->line;
while (1) {
cf = (t->u.evalflags ? ARRAYVAR : 0)
| (XPsize(args) == 0 ? ALIAS|VARASN : CMDWORD);
switch (tpeek(cf)) {
case REDIR:
if (iopn >= NUFILE)
yyerror("too many redirections\n");
iops[iopn++] = synio(cf);
break;
case LWORD:
ACCEPT;
/* the iopn == 0 and XPsize(vars) == 0 are
* dubious but at&t ksh acts this way
*/
if (iopn == 0 && XPsize(vars) == 0
&& XPsize(args) == 0
&& assign_command(ident))
t->u.evalflags = DOVACHECK;
if ((XPsize(args) == 0 || Flag(FKEYWORD))
&& is_wdvarassign(yylval.cp))
XPput(vars, yylval.cp);
else
XPput(args, yylval.cp);
break;
case '(':
/* Check for "> foo (echo hi)", which at&t ksh
* allows (not POSIX, but not disallowed)
*/
afree(t, ATEMP);
if (XPsize(args) == 0 && XPsize(vars) == 0) {
ACCEPT;
goto Subshell;
}
/* Must be a function */
if (iopn != 0 || XPsize(args) != 1
|| XPsize(vars) != 0)
syntaxerr((char *) 0);
ACCEPT;
/*(*/
musthave(')', 0);
t = function_body(XPptrv(args)[0], FALSE);
goto Leave;
default:
goto Leave;
}
}
Leave:
break;
Subshell:
case '(':
t = nested(TPAREN, '(', ')');
break;
case '{': /*}*/
t = nested(TBRACE, '{', '}');
break;
#ifdef KSH
case MDPAREN:
{
static const char let_cmd[] = { CHAR, 'l', CHAR, 'e',
CHAR, 't', EOS };
/* Leave KEYWORD in syniocf (allow if (( 1 )) then ...) */
t = newtp(TCOM);
t->lineno = source->line;
ACCEPT;
XPput(args, wdcopy(let_cmd, ATEMP));
musthave(LWORD,LETEXPR);
XPput(args, yylval.cp);
break;
}
#endif /* KSH */
#ifdef KSH
case DBRACKET: /* [[ .. ]] */
/* Leave KEYWORD in syniocf (allow if [[ -n 1 ]] then ...) */
t = newtp(TDBRACKET);
ACCEPT;
{
Test_env te;
te.flags = TEF_DBRACKET;
te.pos.av = &args;
te.isa = dbtestp_isa;
te.getopnd = dbtestp_getopnd;
te.eval = dbtestp_eval;
te.error = dbtestp_error;
test_parse(&te);
}
break;
#endif /* KSH */
case FOR:
case SELECT:
t = newtp((c == FOR) ? TFOR : TSELECT);
musthave(LWORD, ARRAYVAR);
if (!is_wdvarname(yylval.cp, TRUE))
yyerror("%s: bad identifier\n",
c == FOR ? "for" : "select");
t->str = str_save(ident, ATEMP);
nesting_push(&old_nesting, c);
t->vars = wordlist();
t->left = dogroup();
nesting_pop(&old_nesting);
break;
case WHILE:
case UNTIL:
nesting_push(&old_nesting, c);
t = newtp((c == WHILE) ? TWHILE : TUNTIL);
t->left = c_list(TRUE);
t->right = dogroup();
nesting_pop(&old_nesting);
break;
case CASE:
t = newtp(TCASE);
musthave(LWORD, 0);
t->str = yylval.cp;
nesting_push(&old_nesting, c);
t->left = caselist();
nesting_pop(&old_nesting);
break;
case IF:
nesting_push(&old_nesting, c);
t = newtp(TIF);
t->left = c_list(TRUE);
t->right = thenpart();
musthave(FI, KEYWORD|ALIAS);
nesting_pop(&old_nesting);
break;
case BANG:
syniocf &= ~(KEYWORD|ALIAS);
t = pipeline(0);
if (t == (struct op *) 0)
syntaxerr((char *) 0);
t = block(TBANG, NOBLOCK, t, NOWORDS);
break;
case TIME:
syniocf &= ~(KEYWORD|ALIAS);
t = pipeline(0);
t = block(TTIME, t, NOBLOCK, NOWORDS);
break;
case FUNCTION:
musthave(LWORD, 0);
t = function_body(yylval.cp, TRUE);
break;
}
while ((iop = synio(syniocf)) != NULL) {
if (iopn >= NUFILE)
yyerror("too many redirections\n");
iops[iopn++] = iop;
}
if (iopn == 0) {
afree((void*) iops, ATEMP);
t->ioact = NULL;
} else {
iops[iopn++] = NULL;
iops = (struct ioword **) aresize((void*) iops,
sizeofN(struct ioword *, iopn), ATEMP);
t->ioact = iops;
}
if (t->type == TCOM || t->type == TDBRACKET) {
XPput(args, NULL);
t->args = (char **) XPclose(args);
XPput(vars, NULL);
t->vars = (char **) XPclose(vars);
} else {
XPfree(args);
XPfree(vars);
}
return t;
}
static struct op *
dogroup()
{
register int c;
register struct op *list;
c = token(CONTIN|KEYWORD|ALIAS);
/* A {...} can be used instead of do...done for for/select loops
* but not for while/until loops - we don't need to check if it
* is a while loop because it would have been parsed as part of
* the conditional command list...
*/
if (c == DO)
c = DONE;
else if (c == '{')
c = '}';
else
syntaxerr((char *) 0);
list = c_list(TRUE);
musthave(c, KEYWORD|ALIAS);
return list;
}
static struct op *
thenpart()
{
register struct op *t;
musthave(THEN, KEYWORD|ALIAS);
t = newtp(0);
t->left = c_list(TRUE);
if (t->left == NULL)
syntaxerr((char *) 0);
t->right = elsepart();
return (t);
}
static struct op *
elsepart()
{
register struct op *t;
switch (token(KEYWORD|ALIAS|VARASN)) {
case ELSE:
if ((t = c_list(TRUE)) == NULL)
syntaxerr((char *) 0);
return (t);
case ELIF:
t = newtp(TELIF);
t->left = c_list(TRUE);
t->right = thenpart();
return (t);
default:
REJECT;
}
return NULL;
}
static struct op *
caselist()
{
register struct op *t, *tl;
int c;
c = token(CONTIN|KEYWORD|ALIAS);
/* A {...} can be used instead of in...esac for case statements */
if (c == IN)
c = ESAC;
else if (c == '{')
c = '}';
else
syntaxerr((char *) 0);
t = tl = NULL;
while ((tpeek(CONTIN|KEYWORD|ESACONLY)) != c) { /* no ALIAS here */
struct op *tc = casepart(c);
if (tl == NULL)
t = tl = tc, tl->right = NULL;
else
tl->right = tc, tl = tc;
}
musthave(c, KEYWORD|ALIAS);
return (t);
}
static struct op *
casepart(endtok)
int endtok;
{
register struct op *t;
register int c;
XPtrV ptns;
XPinit(ptns, 16);
t = newtp(TPAT);
c = token(CONTIN|KEYWORD); /* no ALIAS here */
if (c != '(')
REJECT;
do {
musthave(LWORD, 0);
XPput(ptns, yylval.cp);
} while ((c = token(0)) == '|');
REJECT;
XPput(ptns, NULL);
t->vars = (char **) XPclose(ptns);
musthave(')', 0);
t->left = c_list(TRUE);
/* Note: Posix requires the ;; */
if ((tpeek(CONTIN|KEYWORD|ALIAS)) != endtok)
musthave(BREAK, CONTIN|KEYWORD|ALIAS);
return (t);
}
static struct op *
function_body(name, ksh_func)
char *name;
int ksh_func; /* function foo { ... } vs foo() { .. } */
{
char *sname, *p;
struct op *t;
int old_func_parse;
sname = wdstrip(name);
/* Check for valid characters in name. posix and ksh93 say only
* allow [a-zA-Z_0-9] but this allows more as old pdksh's have
* allowed more (the following were never allowed:
* nul space nl tab $ ' " \ ` ( ) & | ; = < >
* C_QUOTE covers all but = and adds # [ ? *)
*/
for (p = sname; *p; p++)
if (ctype(*p, C_QUOTE) || *p == '=')
yyerror("%s: invalid function name\n", sname);
t = newtp(TFUNCT);
t->str = sname;
t->u.ksh_func = ksh_func;
t->lineno = source->line;
/* Note that POSIX allows only compound statements after foo(), sh and
* at&t ksh allow any command, go with the later since it shouldn't
* break anything. However, for function foo, at&t ksh only accepts
* an open-brace.
*/
if (ksh_func) {
musthave('{', CONTIN|KEYWORD|ALIAS); /* } */
REJECT;
}
old_func_parse = e->flags & EF_FUNC_PARSE;
e->flags |= EF_FUNC_PARSE;
if ((t->left = get_command(CONTIN)) == (struct op *) 0) {
/*
* Probably something like foo() followed by eof or ;.
* This is accepted by sh and ksh88.
* To make "typeset -f foo" work reliably (so its output can
* be used as input), we pretend there is a colon here.
*/
t->left = newtp(TCOM);
t->left->args = (char **) alloc(sizeof(char *) * 2, ATEMP);
t->left->args[0] = alloc(sizeof(char) * 3, ATEMP);
t->left->args[0][0] = CHAR;
t->left->args[0][1] = ':';
t->left->args[0][2] = EOS;
t->left->args[1] = (char *) 0;
t->left->vars = (char **) alloc(sizeof(char *), ATEMP);
t->left->vars[0] = (char *) 0;
t->left->lineno = 1;
}
if (!old_func_parse)
e->flags &= ~EF_FUNC_PARSE;
return t;
}
static char **
wordlist()
{
register int c;
XPtrV args;
XPinit(args, 16);
/* Posix does not do alias expansion here... */
if ((c = token(CONTIN|KEYWORD|ALIAS)) != IN) {
if (c != ';') /* non-POSIX, but at&t ksh accepts a ; here */
REJECT;
return NULL;
}
while ((c = token(0)) == LWORD)
XPput(args, yylval.cp);
if (c != '\n' && c != ';')
syntaxerr((char *) 0);
if (XPsize(args) == 0) {
XPfree(args);
return NULL;
} else {
XPput(args, NULL);
return (char **) XPclose(args);
}
}
/*
* supporting functions
*/
static struct op *
block(type, t1, t2, wp)
int type;
struct op *t1, *t2;
char **wp;
{
register struct op *t;
t = newtp(type);
t->left = t1;
t->right = t2;
t->vars = wp;
return (t);
}
const struct tokeninfo {
const char *name;
short val;
short reserved;
} tokentab[] = {
/* Reserved words */
{ "if", IF, TRUE },
{ "then", THEN, TRUE },
{ "else", ELSE, TRUE },
{ "elif", ELIF, TRUE },
{ "fi", FI, TRUE },
{ "case", CASE, TRUE },
{ "esac", ESAC, TRUE },
{ "for", FOR, TRUE },
#ifdef KSH
{ "select", SELECT, TRUE },
#endif /* KSH */
{ "while", WHILE, TRUE },
{ "until", UNTIL, TRUE },
{ "do", DO, TRUE },
{ "done", DONE, TRUE },
{ "in", IN, TRUE },
{ "function", FUNCTION, TRUE },
{ "time", TIME, TRUE },
{ "{", '{', TRUE },
{ "}", '}', TRUE },
{ "!", BANG, TRUE },
#ifdef KSH
{ "[[", DBRACKET, TRUE },
#endif /* KSH */
/* Lexical tokens (0[EOF], LWORD and REDIR handled specially) */
{ "&&", LOGAND, FALSE },
{ "||", LOGOR, FALSE },
{ ";;", BREAK, FALSE },
#ifdef KSH
{ "((", MDPAREN, FALSE },
{ "|&", COPROC, FALSE },
#endif /* KSH */
/* and some special cases... */
{ "newline", '\n', FALSE },
{ .name = NULL }
};
void
initkeywords()
{
register struct tokeninfo const *tt;
register struct tbl *p;
tinit(&keywords, APERM, 32); /* must be 2^n (currently 20 keywords) */
for (tt = tokentab; tt->name; tt++) {
if (tt->reserved) {
p = tenter(&keywords, tt->name, hash(tt->name));
p->flag |= DEFINED|ISSET;
p->type = CKEYWD;
p->val.i = tt->val;
}
}
}
static void
syntaxerr(what)
const char *what;
{
char redir[6]; /* 2<<- is the longest redirection, I think */
const char *s;
struct tokeninfo const *tt;
int c;
if (!what)
what = "unexpected";
REJECT;
c = token(0);
Again:
switch (c) {
case 0:
if (nesting.start_token) {
c = nesting.start_token;
source->errline = nesting.start_line;
what = "unmatched";
goto Again;
}
/* don't quote the EOF */
yyerror("syntax error: unexpected EOF\n");
/*NOTREACHED*/
case LWORD:
s = snptreef((char *) 0, 32, "%S", yylval.cp);
break;
case REDIR:
s = snptreef(redir, sizeof(redir), "%R", yylval.iop);
break;
default:
for (tt = tokentab; tt->name; tt++)
if (tt->val == c)
break;
if (tt->name)
s = tt->name;
else {
if (c > 0 && c < 256) {
redir[0] = c;
redir[1] = '\0';
} else
shf_snprintf(redir, sizeof(redir),
"?%d", c);
s = redir;
}
}
yyerror("syntax error: `%s' %s\n", s, what);
}
static void
nesting_push(save, tok)
struct nesting_state *save;
int tok;
{
*save = nesting;
nesting.start_token = tok;
nesting.start_line = source->line;
}
static void
nesting_pop(saved)
struct nesting_state *saved;
{
nesting = *saved;
}
static struct op *
newtp(type)
int type;
{
register struct op *t;
t = (struct op *) alloc(sizeof(*t), ATEMP);
t->type = type;
t->u.evalflags = 0;
t->args = t->vars = NULL;
t->ioact = NULL;
t->left = t->right = NULL;
t->str = NULL;
return (t);
}
struct op *
compile(s)
Source *s;
{
nesting.start_token = 0;
nesting.start_line = 0;
herep = heres;
source = s;
yyparse();
return outtree;
}
/* This kludge exists to take care of sh/at&t ksh oddity in which
* the arguments of alias/export/readonly/typeset have no field
* splitting, file globbing, or (normal) tilde expansion done.
* at&t ksh seems to do something similar to this since
* $ touch a=a; typeset a=[ab]; echo "$a"
* a=[ab]
* $ x=typeset; $x a=[ab]; echo "$a"
* a=a
* $
*/
static int
assign_command(s)
char *s;
{
char c = *s;
if (Flag(FPOSIX) || !*s)
return 0;
return (c == 'a' && strcmp(s, "alias") == 0)
|| (c == 'e' && strcmp(s, "export") == 0)
|| (c == 'r' && strcmp(s, "readonly") == 0)
|| (c == 't' && strcmp(s, "typeset") == 0);
}
/* Check if we are in the middle of reading an alias */
static int
inalias(s)
struct source *s;
{
for (; s && s->type == SALIAS; s = s->next)
if (!(s->flags & SF_ALIASEND))
return 1;
return 0;
}
#ifdef KSH
/* Order important - indexed by Test_meta values
* Note that ||, &&, ( and ) can't appear in as unquoted strings
* in normal shell input, so these can be interpreted unambiguously
* in the evaluation pass.
*/
static const char dbtest_or[] = { CHAR, '|', CHAR, '|', EOS };
static const char dbtest_and[] = { CHAR, '&', CHAR, '&', EOS };
static const char dbtest_not[] = { CHAR, '!', EOS };
static const char dbtest_oparen[] = { CHAR, '(', EOS };
static const char dbtest_cparen[] = { CHAR, ')', EOS };
const char *const dbtest_tokens[] = {
dbtest_or, dbtest_and, dbtest_not,
dbtest_oparen, dbtest_cparen
};
const char db_close[] = { CHAR, ']', CHAR, ']', EOS };
const char db_lthan[] = { CHAR, '<', EOS };
const char db_gthan[] = { CHAR, '>', EOS };
/* Test if the current token is a whatever. Accepts the current token if
* it is. Returns 0 if it is not, non-zero if it is (in the case of
* TM_UNOP and TM_BINOP, the returned value is a Test_op).
*/
static int
dbtestp_isa(te, meta)
Test_env *te;
Test_meta meta;
{
int c = tpeek(ARRAYVAR | (meta == TM_BINOP ? 0 : CONTIN));
int uqword = 0;
char *save = (char *) 0;
int ret = 0;
/* unquoted word? */
uqword = c == LWORD && *ident;
if (meta == TM_OR)
ret = c == LOGOR;
else if (meta == TM_AND)
ret = c == LOGAND;
else if (meta == TM_NOT)
ret = uqword && strcmp(yylval.cp, dbtest_tokens[(int) TM_NOT]) == 0;
else if (meta == TM_OPAREN)
ret = c == '(' /*)*/;
else if (meta == TM_CPAREN)
ret = c == /*(*/ ')';
else if (meta == TM_UNOP || meta == TM_BINOP) {
if (meta == TM_BINOP && c == REDIR
&& (yylval.iop->flag == IOREAD
|| yylval.iop->flag == IOWRITE))
{
ret = 1;
save = wdcopy(yylval.iop->flag == IOREAD ?
db_lthan : db_gthan, ATEMP);
} else if (uqword && (ret = (int) test_isop(te, meta, ident)))
save = yylval.cp;
} else /* meta == TM_END */
ret = uqword && strcmp(yylval.cp, db_close) == 0;
if (ret) {
ACCEPT;
if (meta != TM_END) {
if (!save) {
assert(/* meta >= 0 && */
meta < sizeof(dbtest_tokens) /
sizeof(dbtest_tokens[0]));
save = wdcopy(dbtest_tokens[(int) meta], ATEMP);
}
XPput(*te->pos.av, save);
}
}
return ret;
}
static const char *
dbtestp_getopnd(te, op, do_eval)
Test_env *te;
Test_op op;
int do_eval;
{
int c = tpeek(ARRAYVAR);
if (c != LWORD)
return (const char *) 0;
ACCEPT;
XPput(*te->pos.av, yylval.cp);
return null;
}
static int
dbtestp_eval(te, op, opnd1, opnd2, do_eval)
Test_env *te;
Test_op op;
const char *opnd1;
const char *opnd2;
int do_eval;
{
return 1;
}
static void
dbtestp_error(te, offset, msg)
Test_env *te;
int offset;
const char *msg;
{
te->flags |= TEF_ERROR;
if (offset < 0) {
REJECT;
/* Kludgy to say the least... */
symbol = LWORD;
yylval.cp = *(XPptrv(*te->pos.av) + XPsize(*te->pos.av)
+ offset);
}
syntaxerr(msg);
}
#endif /* KSH */

247
bin/ksh/table.c Normal file
View File

@@ -0,0 +1,247 @@
/* $NetBSD: table.c,v 1.4 2003/06/23 11:39:04 agc Exp $ */
/*
* dynamic hashed associative table for commands and variables
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: table.c,v 1.4 2003/06/23 11:39:04 agc Exp $");
#endif
#include "sh.h"
#define INIT_TBLS 8 /* initial table size (power of 2) */
static void texpand ARGS((struct table *tp, int nsize));
static int tnamecmp ARGS((void *p1, void *p2));
unsigned int
hash(n)
register const char * n;
{
register unsigned int h = 0;
while (*n != '\0')
h = 2*h + *n++;
return h * 32821; /* scatter bits */
}
void
tinit(tp, ap, tsize)
register struct table *tp;
register Area *ap;
int tsize;
{
tp->areap = ap;
tp->tbls = NULL;
tp->size = tp->nfree = 0;
if (tsize)
texpand(tp, tsize);
}
static void
texpand(tp, nsize)
register struct table *tp;
int nsize;
{
register int i;
register struct tbl *tblp, **p;
register struct tbl **ntblp, **otblp = tp->tbls;
int osize = tp->size;
ntblp = (struct tbl**) alloc(sizeofN(struct tbl *, nsize), tp->areap);
for (i = 0; i < nsize; i++)
ntblp[i] = NULL;
tp->size = nsize;
tp->nfree = 8*nsize/10; /* table can get 80% full */
tp->tbls = ntblp;
if (otblp == NULL)
return;
for (i = 0; i < osize; i++) {
if ((tblp = otblp[i]) != NULL) {
if ((tblp->flag&DEFINED)) {
for (p = &ntblp[hash(tblp->name)
& (tp->size-1)];
*p != NULL; p--)
if (p == ntblp) /* wrap */
p += tp->size;
*p = tblp;
tp->nfree--;
} else if (!(tblp->flag & FINUSE)) {
afree((void*)tblp, tp->areap);
}
}
}
afree((void*)otblp, tp->areap);
}
struct tbl *
tsearch(tp, n, h)
register struct table *tp; /* table */
register const char *n; /* name to enter */
unsigned int h; /* hash(n) */
{
register struct tbl **pp, *p;
if (tp->size == 0)
return NULL;
/* search for name in hashed table */
for (pp = &tp->tbls[h & (tp->size-1)]; (p = *pp) != NULL; pp--) {
if (*p->name == *n && strcmp(p->name, n) == 0
&& (p->flag&DEFINED))
return p;
if (pp == tp->tbls) /* wrap */
pp += tp->size;
}
return NULL;
}
struct tbl *
tenter(tp, n, h)
register struct table *tp; /* table */
register const char *n; /* name to enter */
unsigned int h; /* hash(n) */
{
register struct tbl **pp, *p;
register int len;
if (tp->size == 0)
texpand(tp, INIT_TBLS);
Search:
/* search for name in hashed table */
for (pp = &tp->tbls[h & (tp->size-1)]; (p = *pp) != NULL; pp--) {
if (*p->name == *n && strcmp(p->name, n) == 0)
return p; /* found */
if (pp == tp->tbls) /* wrap */
pp += tp->size;
}
if (tp->nfree <= 0) { /* too full */
texpand(tp, 2*tp->size);
goto Search;
}
/* create new tbl entry */
len = strlen(n) + 1;
p = (struct tbl *) alloc(offsetof(struct tbl, name[0]) + len,
tp->areap);
p->flag = 0;
p->type = 0;
p->areap = tp->areap;
p->u2.field = 0;
p->u.array = (struct tbl *)0;
memcpy(p->name, n, len);
/* enter in tp->tbls */
tp->nfree--;
*pp = p;
return p;
}
void
tdelete(p)
register struct tbl *p;
{
p->flag = 0;
}
void
twalk(ts, tp)
struct tstate *ts;
struct table *tp;
{
ts->left = tp->size;
ts->next = tp->tbls;
}
struct tbl *
tnext(ts)
struct tstate *ts;
{
while (--ts->left >= 0) {
struct tbl *p = *ts->next++;
if (p != NULL && (p->flag&DEFINED))
return p;
}
return NULL;
}
static int
tnamecmp(p1, p2)
void *p1, *p2;
{
return strcmp(((struct tbl *)p1)->name, ((struct tbl *)p2)->name);
}
struct tbl **
tsort(tp)
register struct table *tp;
{
register int i;
register struct tbl **p, **sp, **dp;
p = (struct tbl **)alloc(sizeofN(struct tbl *, tp->size+1), ATEMP);
sp = tp->tbls; /* source */
dp = p; /* dest */
for (i = 0; i < tp->size; i++)
if ((*dp = *sp++) != NULL && (((*dp)->flag&DEFINED) ||
((*dp)->flag&ARRAY)))
dp++;
i = dp - p;
qsortp((void**)p, (size_t)i, tnamecmp);
p[i] = NULL;
return p;
}
#ifdef PERF_DEBUG /* performance debugging */
void tprintinfo ARGS((struct table *tp));
void
tprintinfo(tp)
struct table *tp;
{
struct tbl *te;
char *n;
unsigned int h;
int ncmp;
int totncmp = 0, maxncmp = 0;
int nentries = 0;
struct tstate ts;
shellf("table size %d, nfree %d\n", tp->size, tp->nfree);
shellf(" Ncmp name\n");
twalk(&ts, tp);
while ((te = tnext(&ts))) {
register struct tbl **pp, *p;
h = hash(n = te->name);
ncmp = 0;
/* taken from tsearch() and added counter */
for (pp = &tp->tbls[h & (tp->size-1)]; (p = *pp); pp--) {
ncmp++;
if (*p->name == *n && strcmp(p->name, n) == 0
&& (p->flag&DEFINED))
break; /* return p; */
if (pp == tp->tbls) /* wrap */
pp += tp->size;
}
shellf(" %4d %s\n", ncmp, n);
totncmp += ncmp;
nentries++;
if (ncmp > maxncmp)
maxncmp = ncmp;
}
if (nentries)
shellf(" %d entries, worst ncmp %d, avg ncmp %d.%02d\n",
nentries, maxncmp,
totncmp / nentries,
(totncmp % nentries) * 100 / nentries);
}
#endif /* PERF_DEBUG */

181
bin/ksh/table.h Normal file
View File

@@ -0,0 +1,181 @@
/* $NetBSD: table.h,v 1.3 1999/10/20 15:10:00 hubertf Exp $ */
/*
* generic hashed associative table for commands and variables.
*/
struct table {
Area *areap; /* area to allocate entries */
short size, nfree; /* hash size (always 2^^n), free entries */
struct tbl **tbls; /* hashed table items */
};
struct tbl { /* table item */
Tflag flag; /* flags */
int type; /* command type (see below), base (if INTEGER),
* or offset from val.s of value (if EXPORT) */
Area *areap; /* area to allocate from */
union {
char *s; /* string */
long i; /* integer */
int (*f) ARGS((char **)); /* int function */
struct op *t; /* "function" tree */
} val; /* value */
int index; /* index for an array */
union {
int field; /* field with for -L/-R/-Z */
int errno_; /* CEXEC/CTALIAS */
} u2;
union {
struct tbl *array; /* array values */
char *fpath; /* temporary path to undef function */
} u;
char name[4]; /* name -- variable length */
};
/* common flag bits */
#define ALLOC BIT(0) /* val.s has been allocated */
#define DEFINED BIT(1) /* is defined in block */
#define ISSET BIT(2) /* has value, vp->val.[si] */
#define EXPORT BIT(3) /* exported variable/function */
#define TRACE BIT(4) /* var: user flagged, func: execution tracing */
/* (start non-common flags at 8) */
/* flag bits used for variables */
#define SPECIAL BIT(8) /* PATH, IFS, SECONDS, etc */
#define INTEGER BIT(9) /* val.i contains integer value */
#define RDONLY BIT(10) /* read-only variable */
#define LOCAL BIT(11) /* for local typeset() */
#define ARRAY BIT(13) /* array */
#define LJUST BIT(14) /* left justify */
#define RJUST BIT(15) /* right justify */
#define ZEROFIL BIT(16) /* 0 filled if RJUSTIFY, strip 0s if LJUSTIFY */
#define LCASEV BIT(17) /* convert to lower case */
#define UCASEV_AL BIT(18)/* convert to upper case / autoload function */
#define INT_U BIT(19) /* unsigned integer */
#define INT_L BIT(20) /* long integer (no-op) */
#define IMPORT BIT(21) /* flag to typeset(): no arrays, must have = */
#define LOCAL_COPY BIT(22) /* with LOCAL - copy attrs from existing var */
#define EXPRINEVAL BIT(23) /* contents currently being evaluated */
#define EXPRLVALUE BIT(24) /* useable as lvalue (temp flag) */
/* flag bits used for taliases/builtins/aliases/keywords/functions */
#define KEEPASN BIT(8) /* keep command assignments (eg, var=x cmd) */
#define FINUSE BIT(9) /* function being executed */
#define FDELETE BIT(10) /* function deleted while it was executing */
#define FKSH BIT(11) /* function defined with function x (vs x()) */
#define SPEC_BI BIT(12) /* a POSIX special builtin */
#define REG_BI BIT(13) /* a POSIX regular builtin */
/* Attributes that can be set by the user (used to decide if an unset param
* should be repoted by set/typeset). Does not include ARRAY or LOCAL.
*/
#define USERATTRIB (EXPORT|INTEGER|RDONLY|LJUST|RJUST|ZEROFIL\
|LCASEV|UCASEV_AL|INT_U|INT_L)
/* command types */
#define CNONE 0 /* undefined */
#define CSHELL 1 /* built-in */
#define CFUNC 2 /* function */
#define CEXEC 4 /* executable command */
#define CALIAS 5 /* alias */
#define CKEYWD 6 /* keyword */
#define CTALIAS 7 /* tracked alias */
/* Flags for findcom()/comexec() */
#define FC_SPECBI BIT(0) /* special builtin */
#define FC_FUNC BIT(1) /* function builtin */
#define FC_REGBI BIT(2) /* regular builtin */
#define FC_UNREGBI BIT(3) /* un-regular builtin (!special,!regular) */
#define FC_BI (FC_SPECBI|FC_REGBI|FC_UNREGBI)
#define FC_PATH BIT(4) /* do path search */
#define FC_DEFPATH BIT(5) /* use default path in path search */
#define AF_ARGV_ALLOC 0x1 /* argv[] array allocated */
#define AF_ARGS_ALLOCED 0x2 /* argument strings allocated */
#define AI_ARGV(a, i) ((i) == 0 ? (a).argv[0] : (a).argv[(i) - (a).skip])
#define AI_ARGC(a) ((a).argc_ - (a).skip)
/* Argument info. Used for $#, $* for shell, functions, includes, etc. */
struct arg_info {
int flags; /* AF_* */
char **argv;
int argc_;
int skip; /* first arg is argv[0], second is argv[1 + skip] */
};
/*
* activation record for function blocks
*/
struct block {
Area area; /* area to allocate things */
/*struct arg_info argi;*/
char **argv;
int argc;
int flags; /* see BF_* */
struct table vars; /* local variables */
struct table funs; /* local functions */
Getopt getopts_state;
#if 1
char * error; /* error handler */
char * exit; /* exit handler */
#else
Trap error, exit;
#endif
struct block *next; /* enclosing block */
};
/* Values for struct block.flags */
#define BF_DOGETOPTS BIT(0) /* save/restore getopts state */
/*
* Used by twalk() and tnext() routines.
*/
struct tstate {
int left;
struct tbl **next;
};
EXTERN struct table taliases; /* tracked aliases */
EXTERN struct table builtins; /* built-in commands */
EXTERN struct table aliases; /* aliases */
EXTERN struct table keywords; /* keywords */
EXTERN struct table homedirs; /* homedir() cache */
struct builtin {
const char *name;
int (*func) ARGS((char **));
};
/* these really are externs! Look in table.c for them */
extern const struct builtin shbuiltins [], kshbuiltins [];
/* var spec values */
#define V_NONE 0
#define V_PATH 1
#define V_IFS 2
#define V_SECONDS 3
#define V_OPTIND 4
#define V_MAIL 5
#define V_MAILPATH 6
#define V_MAILCHECK 7
#define V_RANDOM 8
#define V_HISTSIZE 9
#define V_HISTFILE 10
#define V_VISUAL 11
#define V_EDITOR 12
#define V_COLUMNS 13
#define V_POSIXLY_CORRECT 14
#define V_TMOUT 15
#define V_TMPDIR 16
#define V_LINENO 17
/* values for set_prompt() */
#define PS1 0 /* command */
#define PS2 1 /* command continuation */
EXTERN char *path; /* copy of either PATH or def_path */
EXTERN const char *def_path; /* path to use if PATH not set */
EXTERN char *tmpdir; /* TMPDIR value */
EXTERN const char *prompt;
EXTERN int cur_prompt; /* PS1 or PS2 */
EXTERN int current_lineno; /* LINENO value */

460
bin/ksh/trap.c Normal file
View File

@@ -0,0 +1,460 @@
/* $NetBSD: trap.c,v 1.8 2006/10/16 00:07:32 christos Exp $ */
/*
* signal handling
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: trap.c,v 1.8 2006/10/16 00:07:32 christos Exp $");
#endif
/* Kludge to avoid bogus re-declaration of sigtraps[] error on AIX 3.2.5 */
#define FROM_TRAP_C
#include "sh.h"
/* Table is indexed by signal number
*
* The script siglist.sh generates siglist.out, which is a sorted, complete
* list of signals
*/
Trap sigtraps[SIGNALS+1] = {
{ .signal = SIGEXIT_, .name = "EXIT", .mess = "Signal 0" },
#include "siglist.out" /* generated by siglist.sh */
{ .signal = SIGERR_, .name = "ERR", .mess = "Error handler" },
};
static struct sigaction Sigact_ign, Sigact_trap;
void
inittraps()
{
#ifdef HAVE_SYS_SIGLIST
# ifndef SYS_SIGLIST_DECLARED
extern char *sys_siglist[];
# endif
int i;
/* Use system description, if available, for unknown signals... */
for (i = 0; i < NSIG; i++)
if (!sigtraps[i].name && sys_siglist[i] && sys_siglist[i][0])
sigtraps[i].mess = sys_siglist[i];
#endif /* HAVE_SYS_SIGLIST */
sigemptyset(&Sigact_ign.sa_mask);
Sigact_ign.sa_flags = KSH_SA_FLAGS;
Sigact_ign.sa_handler = SIG_IGN;
Sigact_trap = Sigact_ign;
Sigact_trap.sa_handler = trapsig;
sigtraps[SIGINT].flags |= TF_DFL_INTR | TF_TTY_INTR;
sigtraps[SIGQUIT].flags |= TF_DFL_INTR | TF_TTY_INTR;
sigtraps[SIGTERM].flags |= TF_DFL_INTR;/* not fatal for interactive */
sigtraps[SIGHUP].flags |= TF_FATAL;
sigtraps[SIGCHLD].flags |= TF_SHELL_USES;
/* these are always caught so we can clean up any temporary files. */
setsig(&sigtraps[SIGINT], trapsig, SS_RESTORE_ORIG);
setsig(&sigtraps[SIGQUIT], trapsig, SS_RESTORE_ORIG);
setsig(&sigtraps[SIGTERM], trapsig, SS_RESTORE_ORIG);
setsig(&sigtraps[SIGHUP], trapsig, SS_RESTORE_ORIG);
}
#ifdef KSH
static RETSIGTYPE alarm_catcher ARGS((int sig));
void
alarm_init()
{
sigtraps[SIGALRM].flags |= TF_SHELL_USES;
setsig(&sigtraps[SIGALRM], alarm_catcher,
SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP);
}
static RETSIGTYPE
alarm_catcher(sig)
int sig;
{
int errno_ = errno;
if (ksh_tmout_state == TMOUT_READING) {
int left = alarm(0);
if (left == 0) {
ksh_tmout_state = TMOUT_LEAVING;
intrsig = 1;
} else
alarm(left);
}
errno = errno_;
return RETSIGVAL;
}
#endif /* KSH */
Trap *
gettrap(name, igncase)
const char *name;
int igncase;
{
int i;
register Trap *p;
if (digit(*name)) {
int n;
if (getn(name, &n) && 0 <= n && n < SIGNALS)
return &sigtraps[n];
return NULL;
}
for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
if (p->name) {
if (igncase) {
if (p->name && (!strcasecmp(p->name, name) ||
(strlen(name) > 3 && !strncasecmp("SIG",
p->name, 3) &&
!strcasecmp(p->name, name + 3))))
return p;
} else {
if (p->name && (!strcmp(p->name, name) ||
(strlen(name) > 3 && !strncmp("SIG",
p->name, 3) && !strcmp(p->name, name + 3))))
return p;
}
}
return NULL;
}
/*
* trap signal handler
*/
RETSIGTYPE
trapsig(i)
int i;
{
Trap *p = &sigtraps[i];
int errno_ = errno;
trap = p->set = 1;
if (p->flags & TF_DFL_INTR)
intrsig = 1;
if ((p->flags & TF_FATAL) && !p->trap) {
fatal_trap = 1;
intrsig = 1;
}
if (p->shtrap)
(*p->shtrap)(i);
#ifdef V7_SIGNALS
if (sigtraps[i].cursig == trapsig) /* this for SIGCHLD,SIGALRM */
sigaction(i, &Sigact_trap, (struct sigaction *) 0);
#endif /* V7_SIGNALS */
errno = errno_;
return RETSIGVAL;
}
/* called when we want to allow the user to ^C out of something - won't
* work if user has trapped SIGINT.
*/
void
intrcheck()
{
if (intrsig)
runtraps(TF_DFL_INTR|TF_FATAL);
}
/* called after EINTR to check if a signal with normally causes process
* termination has been received.
*/
int
fatal_trap_check()
{
int i;
Trap *p;
/* todo: should check if signal is fatal, not the TF_DFL_INTR flag */
for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
if (p->set && (p->flags & (TF_DFL_INTR|TF_FATAL)))
/* return value is used as an exit code */
return 128 + p->signal;
return 0;
}
/* Returns the signal number of any pending traps: ie, a signal which has
* occurred for which a trap has been set or for which the TF_DFL_INTR flag
* is set.
*/
int
trap_pending()
{
int i;
Trap *p;
for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
if (p->set && ((p->trap && p->trap[0])
|| ((p->flags & (TF_DFL_INTR|TF_FATAL))
&& !p->trap)))
return p->signal;
return 0;
}
/*
* run any pending traps. If intr is set, only run traps that
* can interrupt commands.
*/
void
runtraps(flag)
int flag;
{
int i;
register Trap *p;
#ifdef KSH
if (ksh_tmout_state == TMOUT_LEAVING) {
ksh_tmout_state = TMOUT_EXECUTING;
warningf(FALSE, "timed out waiting for input");
unwind(LEXIT);
} else
/* XXX: this means the alarm will have no effect if a trap
* is caught after the alarm() was started...not good.
*/
ksh_tmout_state = TMOUT_EXECUTING;
#endif /* KSH */
if (!flag)
trap = 0;
if (flag & TF_DFL_INTR)
intrsig = 0;
if (flag & TF_FATAL)
fatal_trap = 0;
for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
if (p->set && (!flag
|| ((p->flags & flag) && p->trap == (char *) 0)))
runtrap(p);
}
void
runtrap(p)
Trap *p;
{
int i = p->signal;
char *trapstr = p->trap;
int oexstat;
int UNINITIALIZED(old_changed);
p->set = 0;
if (trapstr == (char *) 0) { /* SIG_DFL */
if (p->flags & TF_FATAL) {
/* eg, SIGHUP */
exstat = 128 + i;
unwind(LLEAVE);
}
if (p->flags & TF_DFL_INTR) {
/* eg, SIGINT, SIGQUIT, SIGTERM, etc. */
exstat = 128 + i;
unwind(LINTR);
}
return;
}
if (trapstr[0] == '\0') /* SIG_IGN */
return;
if (i == SIGEXIT_ || i == SIGERR_) { /* avoid recursion on these */
old_changed = p->flags & TF_CHANGED;
p->flags &= ~TF_CHANGED;
p->trap = (char *) 0;
}
oexstat = exstat;
/* Note: trapstr is fully parsed before anything is executed, thus
* no problem with afree(p->trap) in settrap() while still in use.
*/
command(trapstr);
exstat = oexstat;
if (i == SIGEXIT_ || i == SIGERR_) {
if (p->flags & TF_CHANGED)
/* don't clear TF_CHANGED */
afree(trapstr, APERM);
else
p->trap = trapstr;
p->flags |= old_changed;
}
}
/* clear pending traps and reset user's trap handlers; used after fork(2) */
void
cleartraps()
{
int i;
Trap *p;
trap = 0;
intrsig = 0;
fatal_trap = 0;
for (i = SIGNALS+1, p = sigtraps; --i >= 0; p++) {
p->set = 0;
if ((p->flags & TF_USER_SET) && (p->trap && p->trap[0]))
settrap(p, (char *) 0);
}
}
/* restore signals just before an exec(2) */
void
restoresigs()
{
int i;
Trap *p;
for (i = SIGNALS+1, p = sigtraps; --i >= 0; p++)
if (p->flags & (TF_EXEC_IGN|TF_EXEC_DFL))
setsig(p, (p->flags & TF_EXEC_IGN) ? SIG_IGN : SIG_DFL,
SS_RESTORE_CURR|SS_FORCE);
}
void
settrap(p, s)
Trap *p;
char *s;
{
handler_t f;
if (p->trap)
afree(p->trap, APERM);
p->flags |= TF_CHANGED|TF_USER_SET;
if (s) {
p->trap = str_save(s, APERM);
f = s[0] ? trapsig : SIG_IGN;
} else {
p->trap = NULL;
f = SIG_DFL;
}
if ((p->flags & (TF_DFL_INTR|TF_FATAL)) && f == SIG_DFL)
f = trapsig;
else if (p->flags & TF_SHELL_USES) {
if (!(p->flags & TF_ORIG_IGN) || Flag(FTALKING)) {
/* do what user wants at exec time */
p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL);
if (f == SIG_IGN)
p->flags |= TF_EXEC_IGN;
else
p->flags |= TF_EXEC_DFL;
}
/* assumes handler already set to what shell wants it
* (normally trapsig, but could be j_sigchld() or SIG_IGN)
*/
return;
}
/* todo: should we let user know signal is ignored? how? */
setsig(p, f, SS_RESTORE_CURR|SS_USER);
}
/* Called by c_print() when writing to a co-process to ensure SIGPIPE won't
* kill shell (unless user catches it and exits)
*/
int
block_pipe()
{
int restore_dfl = 0;
Trap *p = &sigtraps[SIGPIPE];
if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) {
setsig(p, SIG_IGN, SS_RESTORE_CURR);
if (p->flags & TF_ORIG_DFL)
restore_dfl = 1;
} else if (p->cursig == SIG_DFL) {
setsig(p, SIG_IGN, SS_RESTORE_CURR);
restore_dfl = 1; /* restore to SIG_DFL */
}
return restore_dfl;
}
/* Called by c_print() to undo whatever block_pipe() did */
void
restore_pipe(restore_dfl)
int restore_dfl;
{
if (restore_dfl)
setsig(&sigtraps[SIGPIPE], SIG_DFL, SS_RESTORE_CURR);
}
/* Set action for a signal. Action may not be set if original
* action was SIG_IGN, depending on the value of flags and
* FTALKING.
*/
int
setsig(p, f, flags)
Trap *p;
handler_t f;
int flags;
{
struct sigaction sigact;
if (p->signal == SIGEXIT_ || p->signal == SIGERR_)
return 1;
/* First time setting this signal? If so, get and note the current
* setting.
*/
if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) {
sigaction(p->signal, &Sigact_ign, &sigact);
p->flags |= sigact.sa_handler == SIG_IGN ?
TF_ORIG_IGN : TF_ORIG_DFL;
p->cursig = SIG_IGN;
}
/* Generally, an ignored signal stays ignored, except if
* - the user of an interactive shell wants to change it
* - the shell wants for force a change
*/
if ((p->flags & TF_ORIG_IGN) && !(flags & SS_FORCE)
&& (!(flags & SS_USER) || !Flag(FTALKING)))
return 0;
setexecsig(p, flags & SS_RESTORE_MASK);
/* This is here 'cause there should be a way of clearing shtraps, but
* don't know if this is a sane way of doing it. At the moment,
* all users of shtrap are lifetime users (SIGCHLD, SIGALRM, SIGWINCH).
*/
if (!(flags & SS_USER))
p->shtrap = (handler_t) 0;
if (flags & SS_SHTRAP) {
p->shtrap = f;
f = trapsig;
}
if (p->cursig != f) {
p->cursig = f;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = KSH_SA_FLAGS;
sigact.sa_handler = f;
sigaction(p->signal, &sigact, (struct sigaction *) 0);
}
return 1;
}
/* control what signal is set to before an exec() */
void
setexecsig(p, restore)
Trap *p;
int restore;
{
/* XXX debugging */
if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL)))
internal_errorf(1, "setexecsig: unset signal %d(%s)",
p->signal, p->name);
/* restore original value for exec'd kids */
p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL);
switch (restore & SS_RESTORE_MASK) {
case SS_RESTORE_CURR: /* leave things as they currently are */
break;
case SS_RESTORE_ORIG:
p->flags |= p->flags & TF_ORIG_IGN ? TF_EXEC_IGN : TF_EXEC_DFL;
break;
case SS_RESTORE_DFL:
p->flags |= TF_EXEC_DFL;
break;
case SS_RESTORE_IGN:
p->flags |= TF_EXEC_IGN;
break;
}
}

766
bin/ksh/tree.c Normal file
View File

@@ -0,0 +1,766 @@
/* $NetBSD: tree.c,v 1.6 2005/06/26 19:09:00 christos Exp $ */
/*
* command tree climbing
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: tree.c,v 1.6 2005/06/26 19:09:00 christos Exp $");
#endif
#include "sh.h"
#define INDENT 4
#define tputc(c, shf) shf_putchar(c, shf);
static void ptree ARGS((struct op *t, int indent, struct shf *f));
static void pioact ARGS((struct shf *f, int indent, struct ioword *iop));
static void tputC ARGS((int c, struct shf *shf));
static void tputS ARGS((char *wp, struct shf *shf));
static void vfptreef ARGS((struct shf *shf, int indent, const char *fmt, va_list va));
static struct ioword **iocopy ARGS((struct ioword **iow, Area *ap));
static void iofree ARGS((struct ioword **iow, Area *ap));
/*
* print a command tree
*/
static void
ptree(t, indent, shf)
register struct op *t;
int indent;
register struct shf *shf;
{
register char **w;
struct ioword **ioact;
struct op *t1;
Chain:
if (t == NULL)
return;
switch (t->type) {
case TCOM:
if (t->vars)
for (w = t->vars; *w != NULL; )
fptreef(shf, indent, "%S ", *w++);
else
fptreef(shf, indent, "#no-vars# ");
if (t->args)
for (w = t->args; *w != NULL; )
fptreef(shf, indent, "%S ", *w++);
else
fptreef(shf, indent, "#no-args# ");
break;
case TEXEC:
#if 0 /* ?not useful - can't be called? */
/* Print original vars */
if (t->left->vars)
for (w = t->left->vars; *w != NULL; )
fptreef(shf, indent, "%S ", *w++);
else
fptreef(shf, indent, "#no-vars# ");
/* Print expanded vars */
if (t->args)
for (w = t->args; *w != NULL; )
fptreef(shf, indent, "%s ", *w++);
else
fptreef(shf, indent, "#no-args# ");
/* Print original io */
t = t->left;
#else
t = t->left;
goto Chain;
#endif
case TPAREN:
fptreef(shf, indent + 2, "( %T) ", t->left);
break;
case TPIPE:
fptreef(shf, indent, "%T| ", t->left);
t = t->right;
goto Chain;
case TLIST:
fptreef(shf, indent, "%T%;", t->left);
t = t->right;
goto Chain;
case TOR:
case TAND:
fptreef(shf, indent, "%T%s %T",
t->left, (t->type==TOR) ? "||" : "&&", t->right);
break;
case TBANG:
fptreef(shf, indent, "! ");
t = t->right;
goto Chain;
case TDBRACKET:
{
int i;
fptreef(shf, indent, "[[");
for (i = 0; t->args[i]; i++)
fptreef(shf, indent, " %S", t->args[i]);
fptreef(shf, indent, " ]] ");
break;
}
#ifdef KSH
case TSELECT:
fptreef(shf, indent, "select %s ", t->str);
/* fall through */
#endif /* KSH */
case TFOR:
if (t->type == TFOR)
fptreef(shf, indent, "for %s ", t->str);
if (t->vars != NULL) {
fptreef(shf, indent, "in ");
for (w = t->vars; *w; )
fptreef(shf, indent, "%S ", *w++);
fptreef(shf, indent, "%;");
}
fptreef(shf, indent + INDENT, "do%N%T", t->left);
fptreef(shf, indent, "%;done ");
break;
case TCASE:
fptreef(shf, indent, "case %S in", t->str);
for (t1 = t->left; t1 != NULL; t1 = t1->right) {
fptreef(shf, indent, "%N(");
for (w = t1->vars; *w != NULL; w++)
fptreef(shf, indent, "%S%c", *w,
(w[1] != NULL) ? '|' : ')');
fptreef(shf, indent + INDENT, "%;%T%N;;", t1->left);
}
fptreef(shf, indent, "%Nesac ");
break;
case TIF:
case TELIF:
/* 3 == strlen("if ") */
fptreef(shf, indent + 3, "if %T", t->left);
for (;;) {
t = t->right;
if (t->left != NULL) {
fptreef(shf, indent, "%;");
fptreef(shf, indent + INDENT, "then%N%T",
t->left);
}
if (t->right == NULL || t->right->type != TELIF)
break;
t = t->right;
fptreef(shf, indent, "%;");
/* 5 == strlen("elif ") */
fptreef(shf, indent + 5, "elif %T", t->left);
}
if (t->right != NULL) {
fptreef(shf, indent, "%;");
fptreef(shf, indent + INDENT, "else%;%T", t->right);
}
fptreef(shf, indent, "%;fi ");
break;
case TWHILE:
case TUNTIL:
/* 6 == strlen("while"/"until") */
fptreef(shf, indent + 6, "%s %T",
(t->type==TWHILE) ? "while" : "until",
t->left);
fptreef(shf, indent, "%;do");
fptreef(shf, indent + INDENT, "%;%T", t->right);
fptreef(shf, indent, "%;done ");
break;
case TBRACE:
fptreef(shf, indent + INDENT, "{%;%T", t->left);
fptreef(shf, indent, "%;} ");
break;
case TCOPROC:
fptreef(shf, indent, "%T|& ", t->left);
break;
case TASYNC:
fptreef(shf, indent, "%T& ", t->left);
break;
case TFUNCT:
fptreef(shf, indent,
t->u.ksh_func ? "function %s %T" : "%s() %T",
t->str, t->left);
break;
case TTIME:
fptreef(shf, indent, "time %T", t->left);
break;
default:
fptreef(shf, indent, "<botch>");
break;
}
if ((ioact = t->ioact) != NULL) {
int need_nl = 0;
while (*ioact != NULL)
pioact(shf, indent, *ioact++);
/* Print here documents after everything else... */
for (ioact = t->ioact; *ioact != NULL; ) {
struct ioword *iop = *ioact++;
/* heredoc is 0 when tracing (set -x) */
if ((iop->flag & IOTYPE) == IOHERE && iop->heredoc) {
tputc('\n', shf);
shf_puts(iop->heredoc, shf);
fptreef(shf, indent, "%s",
evalstr(iop->delim, 0));
need_nl = 1;
}
}
/* Last delimiter must be followed by a newline (this often
* leads to an extra blank line, but its not worth worrying
* about)
*/
if (need_nl)
tputc('\n', shf);
}
}
static void
pioact(shf, indent, iop)
register struct shf *shf;
int indent;
register struct ioword *iop;
{
int flag = iop->flag;
int type = flag & IOTYPE;
int expected;
expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0
: (type == IOCAT || type == IOWRITE) ? 1
: (type == IODUP && (iop->unit == !(flag & IORDUP))) ?
iop->unit
: iop->unit + 1;
if (iop->unit != expected)
tputc('0' + iop->unit, shf);
switch (type) {
case IOREAD:
fptreef(shf, indent, "< ");
break;
case IOHERE:
if (flag&IOSKIP)
fptreef(shf, indent, "<<- ");
else
fptreef(shf, indent, "<< ");
break;
case IOCAT:
fptreef(shf, indent, ">> ");
break;
case IOWRITE:
if (flag&IOCLOB)
fptreef(shf, indent, ">| ");
else
fptreef(shf, indent, "> ");
break;
case IORDWR:
fptreef(shf, indent, "<> ");
break;
case IODUP:
if (flag & IORDUP)
fptreef(shf, indent, "<&");
else
fptreef(shf, indent, ">&");
break;
}
/* name/delim are 0 when printing syntax errors */
if (type == IOHERE) {
if (iop->delim)
fptreef(shf, indent, "%S ", iop->delim);
} else if (iop->name)
fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ",
iop->name);
}
/*
* variants of fputc, fputs for ptreef and snptreef
*/
static void
tputC(c, shf)
register int c;
register struct shf *shf;
{
if ((c&0x60) == 0) { /* C0|C1 */
tputc((c&0x80) ? '$' : '^', shf);
tputc(((c&0x7F)|0x40), shf);
} else if ((c&0x7F) == 0x7F) { /* DEL */
tputc((c&0x80) ? '$' : '^', shf);
tputc('?', shf);
} else
tputc(c, shf);
}
static void
tputS(wp, shf)
register char *wp;
register struct shf *shf;
{
register int c, quoted=0;
/* problems:
* `...` -> $(...)
* 'foo' -> "foo"
* could change encoding to:
* OQUOTE ["'] ... CQUOTE ["']
* COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case)
*/
while (1)
switch ((c = *wp++)) {
case EOS:
return;
case CHAR:
tputC(*wp++, shf);
break;
case QCHAR:
c = *wp++;
if (!quoted || (c == '"' || c == '`' || c == '$'))
tputc('\\', shf);
tputC(c, shf);
break;
case COMSUB:
tputc('$', shf);
tputc('(', shf);
while (*wp != 0)
tputC(*wp++, shf);
tputc(')', shf);
wp++;
break;
case EXPRSUB:
tputc('$', shf);
tputc('(', shf);
tputc('(', shf);
while (*wp != 0)
tputC(*wp++, shf);
tputc(')', shf);
tputc(')', shf);
wp++;
break;
case OQUOTE:
quoted = 1;
tputc('"', shf);
break;
case CQUOTE:
quoted = 0;
tputc('"', shf);
break;
case OSUBST:
tputc('$', shf);
if (*wp++ == '{')
tputc('{', shf);
while ((c = *wp++) != 0)
tputC(c, shf);
break;
case CSUBST:
if (*wp++ == '}')
tputc('}', shf);
break;
#ifdef KSH
case OPAT:
tputc(*wp++, shf);
tputc('(', shf);
break;
case SPAT:
tputc('|', shf);
break;
case CPAT:
tputc(')', shf);
break;
#endif /* KSH */
}
}
/*
* this is the _only_ way to reliably handle
* variable args with an ANSI compiler
*/
/* VARARGS */
int
#ifdef HAVE_PROTOTYPES
fptreef(struct shf *shf, int indent, const char *fmt, ...)
#else
fptreef(shf, indent, fmt, va_alist)
struct shf *shf;
int indent;
const char *fmt;
va_dcl
#endif
{
va_list va;
SH_VA_START(va, fmt);
vfptreef(shf, indent, fmt, va);
va_end(va);
return 0;
}
/* VARARGS */
char *
#ifdef HAVE_PROTOTYPES
snptreef(char *s, int n, const char *fmt, ...)
#else
snptreef(s, n, fmt, va_alist)
char *s;
int n;
const char *fmt;
va_dcl
#endif
{
va_list va;
struct shf shf;
shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf);
SH_VA_START(va, fmt);
vfptreef(&shf, 0, fmt, va);
va_end(va);
return shf_sclose(&shf); /* null terminates */
}
static void
vfptreef(shf, indent, fmt, va)
register struct shf *shf;
int indent;
const char *fmt;
register va_list va;
{
register int c;
while ((c = *fmt++))
if (c == '%') {
register long n;
register char *p;
int neg;
switch ((c = *fmt++)) {
case 'c':
tputc(va_arg(va, int), shf);
break;
case 's':
p = va_arg(va, char *);
while (*p)
tputc(*p++, shf);
break;
case 'S': /* word */
p = va_arg(va, char *);
tputS(p, shf);
break;
case 'd': case 'u': /* decimal */
n = (c == 'd') ? va_arg(va, int)
: va_arg(va, unsigned int);
neg = c=='d' && n<0;
p = ulton((neg) ? -n : n, 10);
if (neg)
*--p = '-';
while (*p)
tputc(*p++, shf);
break;
case 'T': /* format tree */
ptree(va_arg(va, struct op *), indent, shf);
break;
case ';': /* newline or ; */
case 'N': /* newline or space */
if (shf->flags & SHF_STRING) {
if (c == ';')
tputc(';', shf);
tputc(' ', shf);
} else {
int i;
tputc('\n', shf);
for (i = indent; i >= 8; i -= 8)
tputc('\t', shf);
for (; i > 0; --i)
tputc(' ', shf);
}
break;
case 'R':
pioact(shf, indent, va_arg(va, struct ioword *));
break;
default:
tputc(c, shf);
break;
}
} else
tputc(c, shf);
}
/*
* copy tree (for function definition)
*/
struct op *
tcopy(t, ap)
register struct op *t;
Area *ap;
{
register struct op *r;
register char **tw, **rw;
if (t == NULL)
return NULL;
r = (struct op *) alloc(sizeof(struct op), ap);
r->type = t->type;
r->u.evalflags = t->u.evalflags;
r->str = t->type == TCASE ? wdcopy(t->str, ap) : str_save(t->str, ap);
if (t->vars == NULL)
r->vars = NULL;
else {
for (tw = t->vars; *tw++ != NULL; )
;
rw = r->vars = (char **)
alloc((tw - t->vars + 1) * sizeof(*tw), ap);
for (tw = t->vars; *tw != NULL; )
*rw++ = wdcopy(*tw++, ap);
*rw = NULL;
}
if (t->args == NULL)
r->args = NULL;
else {
for (tw = t->args; *tw++ != NULL; )
;
rw = r->args = (char **)
alloc((tw - t->args + 1) * sizeof(*tw), ap);
for (tw = t->args; *tw != NULL; )
*rw++ = wdcopy(*tw++, ap);
*rw = NULL;
}
r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap);
r->left = tcopy(t->left, ap);
r->right = tcopy(t->right, ap);
r->lineno = t->lineno;
return r;
}
char *
wdcopy(wp, ap)
const char *wp;
Area *ap;
{
size_t len = wdscan(wp, EOS) - wp;
return memcpy(alloc(len, ap), wp, len);
}
/* return the position of prefix c in wp plus 1 */
char *
wdscan(wp, c)
register const char *wp;
register int c;
{
register int nest = 0;
while (1)
switch (*wp++) {
case EOS:
return (char *) __UNCONST(wp);
case CHAR:
case QCHAR:
wp++;
break;
case COMSUB:
case EXPRSUB:
while (*wp++ != 0)
;
break;
case OQUOTE:
case CQUOTE:
break;
case OSUBST:
nest++;
while (*wp++ != '\0')
;
break;
case CSUBST:
wp++;
if (c == CSUBST && nest == 0)
return (char *) __UNCONST(wp);
nest--;
break;
#ifdef KSH
case OPAT:
nest++;
wp++;
break;
case SPAT:
case CPAT:
if (c == wp[-1] && nest == 0)
return (char *) __UNCONST(wp);
if (wp[-1] == CPAT)
nest--;
break;
#endif /* KSH */
default:
internal_errorf(0,
"wdscan: unknown char 0x%x (carrying on)",
wp[-1]);
}
}
/* return a copy of wp without any of the mark up characters and
* with quote characters (" ' \) stripped.
* (string is allocated from ATEMP)
*/
char *
wdstrip(wp)
const char *wp;
{
struct shf shf;
int c;
shf_sopen((char *) 0, 32, SHF_WR | SHF_DYNAMIC, &shf);
/* problems:
* `...` -> $(...)
* x${foo:-"hi"} -> x${foo:-hi}
* x${foo:-'hi'} -> x${foo:-hi}
*/
while (1)
switch ((c = *wp++)) {
case EOS:
return shf_sclose(&shf); /* null terminates */
case CHAR:
case QCHAR:
shf_putchar(*wp++, &shf);
break;
case COMSUB:
shf_putchar('$', &shf);
shf_putchar('(', &shf);
while (*wp != 0)
shf_putchar(*wp++, &shf);
shf_putchar(')', &shf);
break;
case EXPRSUB:
shf_putchar('$', &shf);
shf_putchar('(', &shf);
shf_putchar('(', &shf);
while (*wp != 0)
shf_putchar(*wp++, &shf);
shf_putchar(')', &shf);
shf_putchar(')', &shf);
break;
case OQUOTE:
break;
case CQUOTE:
break;
case OSUBST:
shf_putchar('$', &shf);
if (*wp++ == '{')
shf_putchar('{', &shf);
while ((c = *wp++) != 0)
shf_putchar(c, &shf);
break;
case CSUBST:
if (*wp++ == '}')
shf_putchar('}', &shf);
break;
#ifdef KSH
case OPAT:
shf_putchar(*wp++, &shf);
shf_putchar('(', &shf);
break;
case SPAT:
shf_putchar('|', &shf);
break;
case CPAT:
shf_putchar(')', &shf);
break;
#endif /* KSH */
}
}
static struct ioword **
iocopy(iow, ap)
register struct ioword **iow;
Area *ap;
{
register struct ioword **ior;
register int i;
for (ior = iow; *ior++ != NULL; )
;
ior = (struct ioword **) alloc((ior - iow + 1) * sizeof(*ior), ap);
for (i = 0; iow[i] != NULL; i++) {
register struct ioword *p, *q;
p = iow[i];
q = (struct ioword *) alloc(sizeof(*p), ap);
ior[i] = q;
*q = *p;
if (p->name != (char *) 0)
q->name = wdcopy(p->name, ap);
if (p->delim != (char *) 0)
q->delim = wdcopy(p->delim, ap);
if (p->heredoc != (char *) 0)
q->heredoc = str_save(p->heredoc, ap);
}
ior[i] = NULL;
return ior;
}
/*
* free tree (for function definition)
*/
void
tfree(t, ap)
register struct op *t;
Area *ap;
{
register char **w;
if (t == NULL)
return;
if (t->str != NULL)
afree((void*)t->str, ap);
if (t->vars != NULL) {
for (w = t->vars; *w != NULL; w++)
afree((void*)*w, ap);
afree((void*)t->vars, ap);
}
if (t->args != NULL) {
for (w = t->args; *w != NULL; w++)
afree((void*)*w, ap);
afree((void*)t->args, ap);
}
if (t->ioact != NULL)
iofree(t->ioact, ap);
tfree(t->left, ap);
tfree(t->right, ap);
afree((void*)t, ap);
}
static void
iofree(iow, ap)
struct ioword **iow;
Area *ap;
{
register struct ioword **iop;
register struct ioword *p;
for (iop = iow; (p = *iop++) != NULL; ) {
if (p->name != NULL)
afree((void*)p->name, ap);
if (p->delim != NULL)
afree((void*)p->delim, ap);
if (p->heredoc != NULL)
afree((void*)p->heredoc, ap);
afree((void*)p, ap);
}
}

Some files were not shown because too many files have changed in this diff Show More