├── .gitattributes ├── .gitignore ├── AUTHORS ├── CHANGES ├── CHANGES6 ├── INSTALL ├── LICENSE ├── Makefile ├── NOTES ├── PROJECT ├── README ├── defs.h ├── err.c ├── err.h ├── examples ├── FILEPREP ├── LICENSE ├── README ├── dot.osh.login ├── dot.osh.logout ├── dot.oshrc ├── etc.osh.login ├── etc.osh.logout └── etc.osh.oshrc ├── fd2.1 ├── fd2.c ├── glob6.1 ├── glob6.c ├── goto.1 ├── goto.c ├── if.1 ├── if.c ├── mkconfig ├── osh.1 ├── osh.c ├── pexec.c ├── pexec.h ├── sasignal.c ├── sasignal.h ├── sh.h ├── sh6.1 ├── sh6.c ├── util.c └── v.c /.gitattributes: -------------------------------------------------------------------------------- 1 | * ident 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.1.out 2 | *.o 3 | .release 4 | GIT.LOG 5 | config.h 6 | fd2 7 | glob6 8 | goto 9 | if 10 | osh 11 | sh6 12 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | The original Thompson shell was principally written by Ken Thompson 2 | of Bell Labs. However, it should be noted that other individuals 3 | at Bell Labs also had a role in its development: Dennis Ritchie, 4 | M. D. McIlroy, J. F. Ossanna, and quite likely others as well. 5 | 6 | Jeffrey Allen Neitzel is the principal developer and maintainer of 7 | the enhanced, backward-compatible port of the Sixth Edition (V6) 8 | UNIX Thompson shell (and all other software) released as part of 9 | the osh project. 10 | 11 | Notice that I have developed two different implementations of osh(1) 12 | since July 2003. The origin of each one is described below. 13 | 14 | ================================ 15 | [osh-030730 through osh-060124]: 16 | The first implementation was originally authored by Gunnar 17 | Ritter as osh-020214/osh.c and was then adopted by Jeffrey 18 | Allen Neitzel. 19 | 20 | Unfortunately, the design of Gunnar's implementation was 21 | incompatible with the Thompson shell in several respects. 22 | Thus, it required a lot of workarounds in order to fix the 23 | design incompatibilities. 24 | 25 | I modified Gunnar's design to separate command-line parsing 26 | and execution so that the shell could at least be compatible 27 | in the most basic sense. The only catch was that word 28 | splitting was still incompatible. Thus, this partial 29 | solution was always destined for eventual replacement. 30 | === 31 | 32 | =================================== 33 | [osh-20061230 through osh-current]: 34 | The second implementation was originally authored by Ken 35 | Thompson as Sixth Edition UNIX /usr/source/s2/sh.c and was 36 | then ported by Jeffrey Allen Neitzel for personal use in 37 | January 2004. 38 | 39 | I eventually released it as sh6(1) in osh-060124. Then, 40 | after its release, I realized that the design of the original 41 | shell (see: osh-060124/*6.c) offered a far better starting 42 | point for making osh(1) truly backward-compatible with the 43 | Thompson shell. 44 | 45 | Bothered by the fact that osh(1) still had incompatible 46 | word-splitting behavior, I abandoned the design used in the 47 | first implementation, adapted sh6.c and glob6.c, copied 48 | them to osh.c, and began working on it during my free time 49 | in 2006. Finally, I released the new implementation of 50 | osh(1) in osh-20061230. 51 | === 52 | 53 | I wish to thank the original authors very much for their efforts. 54 | Without their previous work, none of this software or documentation 55 | would exist today. 56 | 57 | Jeffrey Allen Neitzel 2010/04/30 58 | 59 | @(#)$Id: 628ef831c68dfdc514f6dc73ab9127f19c71b75a $ 60 | -------------------------------------------------------------------------------- /CHANGES6: -------------------------------------------------------------------------------- 1 | The following list describes the changes made to the original source 2 | code for the Sixth Edition (V6) UNIX Thompson shell and global 3 | command in porting them to run on modern UNIX systems. 4 | 5 | ------------------------------------------------------------------------------- 6 | [osh-current]: Friday, 2010-05-14: 7 | * No changes. 8 | 9 | ------------------------------------------------------------------------------- 10 | [osh-20100430]: 11 | * No user-visible changes. 12 | 13 | ------------------------------------------------------------------------------- 14 | [osh-20100228]: 15 | * No user-visible changes. 16 | 17 | ------------------------------------------------------------------------------- 18 | [osh-20091218]: 19 | * No user-visible changes. 20 | 21 | ------------------------------------------------------------------------------- 22 | [osh-20091127]: 23 | * No user-visible changes. 24 | 25 | ------------------------------------------------------------------------------- 26 | [osh-20091122]: 27 | sh6.c: 28 | * Increased apid[] buffer size to 33 via DOLMAX; this allows $$ 29 | to correctly represent shell's process ID on systems where 30 | process IDs > 99999 are possible. 31 | 32 | glob6.c: 33 | * Changed ERR_ALTOOLONG to ERR_E2BIG. 34 | 35 | *6.1: 36 | * Added COPYRIGHT section headings, and added copyright notices. 37 | 38 | ------------------------------------------------------------------------------- 39 | [osh-20091029]: 40 | sh6.c: 41 | * Wrap WCOREDUMP(s) w/ #ifdef WCOREDUMP ... #endif . 42 | 43 | sh6.1: 44 | * Change example in "I/O redirection" subsection that could 45 | confuse new users. 46 | 47 | ------------------------------------------------------------------------------- 48 | [osh-20090527]: 49 | sh6.c: 50 | * Replaced err(), prn(), prs(), and xputc() w/ err() and fd_print() 51 | from err.c . 52 | 53 | * Added sh_errexit() to handle all error exit scenarios for the shell. 54 | This function is called by err(). 55 | 56 | * Copied prsig() from osh.c; changed pwait() to use it for printing 57 | termination messages. 58 | 59 | glob6.c: 60 | * Replaced gerr() w/ err() and ut_errexit() from err.c . 61 | 62 | ------------------------------------------------------------------------------- 63 | [osh-20081213]: 64 | * No changes. 65 | 66 | ------------------------------------------------------------------------------- 67 | [osh-20081122]: 68 | sh6.c: 69 | * Fixed a bug introduced in osh-20081026 where the shell incorrectly 70 | prints a process ID w/ an empty termination message upon receipt 71 | of the SIGINT signal in certain cases. For example: 72 | 73 | % sleep 10 | sleep 20 | sleep 30 ; wait 74 | ^C 75 | 2845: 76 | 2846: 77 | 78 | This example should only print three newlines to the standard error 79 | on SIGINT, not one newline and two process IDs w/ empty messages. 80 | Now, it behaves as expected. 81 | 82 | ------------------------------------------------------------------------------- 83 | [osh-20081026]: 84 | * Moved common definitions for these programs to "defs.h". 85 | 86 | sh6.c: 87 | * Included "sh.h" for needed declarations. 88 | 89 | * Synced `struct tnode' w/ osh.c by changing the order of the `nav' 90 | and `nflags' members. 91 | 92 | * Changed calls to err() to use the diagnostics defined in "defs.h". 93 | 94 | glob6.c: 95 | * Added a base reallocation multiplier to gavnew(). This doubles the 96 | number of new arguments for which to reallocate memory when the 97 | current allocation will not be large enough for the resulting 98 | argument vector. This reduces the number of realloc()s required 99 | for very large argument vectors while allowing the first malloc() 100 | to be a relatively small allocation for up to 126 matching 101 | file-name arguments. 102 | 103 | * Changed calls to gerr() to use the diagnostics defined in "defs.h". 104 | 105 | ------------------------------------------------------------------------------- 106 | [osh-20080629]: 107 | sh6.c: 108 | * Changed the way that the shell deals w/ the SIGTERM signal so that 109 | it only sets SIGTERM to its default action for child processes if 110 | it was set to its default action when the shell started. 111 | 112 | * Changed the code to use sasignal() instead of signal(3). 113 | 114 | sh6.1.in: 115 | * Updated the documentation as needed to reflect changes to the code. 116 | 117 | ------------------------------------------------------------------------------- 118 | [osh-20080109]: 119 | * No user-visible changes. 120 | 121 | ------------------------------------------------------------------------------- 122 | [osh-20070707]: 123 | * No user-visible changes. 124 | 125 | ------------------------------------------------------------------------------- 126 | [osh-20070324]: 127 | * No changes. 128 | 129 | ------------------------------------------------------------------------------- 130 | [osh-20070321]: 131 | * Imported the project into a local subversion repository. 132 | 133 | * Changed the all of the code to "#include " and to use 134 | the "bool" data-type macro where appropriate. 135 | 136 | * User-visible changes? None. 137 | 138 | ------------------------------------------------------------------------------- 139 | [osh-20070131]: 140 | sh6.c: 141 | * Changed the way SIGINT and SIGQUIT are handled so that the shell's 142 | child processes also ignore these signals when the shell and its 143 | parent process do. See the "Signals" subsection of sh6(1) for a 144 | complete description of the new behavior. Notice that this is the 145 | same behavior found in osh(1). 146 | 147 | glob6.c: 148 | * Changed the glob6 non-zero exit status so that it is always 2 when 149 | any error is encountered. This preserves compatibility w/ the 150 | original, which never caused the shell to terminate a command file 151 | when a globbing error occurred. 152 | 153 | ------------------------------------------------------------------------------- 154 | [osh-20061230]: 155 | sh6.c 1.3 (jneitzel) 2006/09/15: 156 | * The shell now ignores any `#!shell' sequence which occurs as the 157 | first line of a regular file. For example, the first line might 158 | be `#!/usr/local/bin/sh6', `#!/usr/bin/env sh6', or similar. 159 | However, it is important to notice that the original Thompson shell 160 | did not do anything of the sort. This change simply adds a degree 161 | of convenience and flexibility for the user. 162 | 163 | * After the shell is invoked and initializes itself, it closes 164 | unneeded file descriptors. Changed when this is done so that it 165 | does not break x-only scripts if they are supported on a particular 166 | UNIX system. 167 | 168 | * The shell no longer exits w/ an explicit non-zero status if a read(2) 169 | from the input file descriptor fails. It now exits silently w/ the 170 | current value of the global variable status in such a case. 171 | 172 | * The shell now exits silently w/ a zero status if the input file 173 | descriptor refers to a directory. The reason for this change is 174 | because invoking the shell as `sh6 file', `sh6 file', and `>>file' so that 202 | the user can quote it if needed. 203 | 204 | * Parse each command line into a dynamically allocated tree of tnode 205 | structures rather than using a statically allocated intptr_t buffer. 206 | 207 | Remember that malloc(3) did not exist in Sixth Edition UNIX; 208 | alloc(III) did exist, but /bin/sh did not use it. 209 | 210 | glob6.c 1.3 (jneitzel) 2006/09/23: 211 | * Improved the quoting behavior for the sake of convenience, 212 | flexibility, and usability. 213 | 214 | * Improved the behavior of `[...]' range matching (e.g., `[a-z]') so 215 | that it adheres to the documentation (see glob6(1)). This means 216 | that an invalid range such as `[z-a]' matches nothing and that 217 | `[a-m-z]' is equivalent to `[a-mz-]' instead of `[a-z]'. 218 | 219 | * Dynamically allocate memory for the generated argument list rather 220 | than using statically allocated buffers. The total length of the 221 | generated argument list is limited to a maximum of ARG_MAX bytes. 222 | An `Arg list too long' diagnostic is printed if this limit is 223 | exceeded or if pexec() fails and sets errno to E2BIG. Of course, 224 | `Out of memory' is printed if glob6 runs out of memory. 225 | 226 | Remember that malloc(3) did not exist in Sixth Edition UNIX; 227 | alloc(III) did exist, but /etc/glob did not use it. 228 | 229 | ------------------------------------------------------------------------------- 230 | [osh-060124]: 231 | This is the initial public release for the following ports of the 232 | original Sixth Edition UNIX source code. 233 | 234 | sh6.c 1.2 (jneitzel) 2006/01/09: 235 | * Deny set-ID execution. If the effective user (group) ID of the sh6 236 | process is not equal to its real user (group) ID, it shall now print 237 | a diagnostic and exit with a non-zero status. 238 | 239 | * Use geteuid(2) instead of getuid(2) to determine whether to print 240 | the `% ' prompt for a regular user or the `# ' prompt for the 241 | superuser. 242 | 243 | * Cause the shell to ignore SIGINT, SIGQUIT, and SIGTERM when invoked 244 | as an interactive shell. The original Thompson shell did not do 245 | this. In Sixth Edition UNIX, the login(1) utility invoked the shell 246 | in the following way: 247 | 248 | execl("/bin/sh", "-", (char *)0); 249 | 250 | ... 251 | This caused the invoked login shell to ignore SIGINT and SIGQUIT. 252 | However, this was not the case for a non-login interactive shell 253 | invoked by a user. 254 | 255 | * When invoked as `cat file | grep h 277 | 278 | ... 279 | since `cat' will never write to the created file. This fix causes 280 | the shell to silently ignore the ambiguous redirect, adhering to 281 | the behavior originally documented in sh(1) (see sh6(1)). 282 | 283 | * The shell no longer breaks pipelines of the following form: 284 | 285 | % ( ( echo hello ) | ( cat ) | ( grep h ) ) >file & 286 | 287 | ... 288 | This fix further limits when `/dev/null' is opened as input for `&' 289 | commands so that doing so cannot replace the read end of a pipe 290 | previously set up by the shell, adhering to the behavior originally 291 | documented in sh(1) (see sh6(1)). 292 | 293 | * Added explicit error detection in those cases where the original 294 | Thompson shell did not do so. For example, the original Thompson 295 | shell did not check the value returned by dup(2) or pipe(2). 296 | 297 | * Changed all of the close(2)/dup(2) sequences for file descriptors 298 | 0 and 1 to simply call dup2(2) instead. 299 | 300 | * Changed all of the calls to exit(3) which happen in the child process 301 | after a successful call to fork(2) to _exit(2) instead. 302 | 303 | * Added `exit' as a special command which is built into the shell. 304 | Its usage is the same as that of the external `exit' utility found 305 | in Sixth Edition UNIX. 306 | 307 | * Define explicit exit status for special commands, external commands, 308 | and shell errors. 309 | 310 | * Removed the `: too large' diagnostic, and added a `: cannot execute' 311 | diagnostic for external-command execution errors. The `No shell!' 312 | and `: not found' diagnostics, however, are unchanged. 313 | 314 | * Use pexec() (see pexec.h) for external command execution to 315 | give more flexible and predictable command search behavior. 316 | 317 | glob6.c 1.2 (jneitzel) 2006/01/09: 318 | * Deny set-ID execution. If the effective user (group) ID of the 319 | glob6 process is not equal to its real user (group) ID, it shall 320 | now print a diagnostic and exit with a non-zero status. 321 | 322 | * Increased the size of the argument-list buffers to allow generation 323 | of longer argument lists. 324 | 325 | * Added a `Pattern too long' diagnostic for those cases where the 326 | total length of a pattern argument is >= PATH_MAX (or 1024). If 327 | such an error is encountered, glob6 exits with a non-zero status. 328 | 329 | * Handle quoted arguments specially so that path names containing 330 | blanks can be successfully globbed. 331 | 332 | * Use pexec() (see pexec.h) for command execution to give 333 | more flexible and predictable command search behavior. 334 | 335 | ------------------------------------------------------------------------------- 336 | [Unreleased]: 337 | The following ports of the original Sixth Edition UNIX source code 338 | were never released to the public. 339 | 340 | sh6.c 1.1 (jneitzel) 2004/01/26: 341 | * Changed the source file name from `sh.c' to `sh6.c' and the 342 | resulting binary name from `sh' to `sh6' to avoid name conflict 343 | and confusion with the system shell, sh(1), on modern UNIX systems. 344 | 345 | * Transformed the source code from K&R C into ANSI C. 346 | 347 | * This is nothing more than a simple port to modern UNIX systems. 348 | It is now 64-bit clean. At least, this is true for the 64-bit 349 | systems to which the porter has access. 350 | 351 | * Removed support for the shell's accounting of process times (see 352 | times(3)) which allowed the shell to record command execution data 353 | in a log file. 354 | 355 | * Fixed a buffer overflow in the word() function. 356 | 357 | glob6.c 1.1 (jneitzel) 2004/01/26: 358 | * Changed the source file name from `glob.c' to `glob6.c' and 359 | the resulting binary name from `glob' to `glob6', matching 360 | the similar change to the name of the shell (see above). 361 | 362 | * Transformed the source code from K&R C into ANSI C. 363 | 364 | * This is nothing more than a simple port to modern UNIX systems. 365 | 366 | * Fixed possible overflow of the argument-list buffers 367 | in the cat() function. 368 | 369 | ------------------------------------------------------------------------------- 370 | [Original]: 371 | Here is some pertinent information about the original files. 372 | 373 | The following description refers to Sixth Edition (V6) UNIX obtained from: 374 | 375 | http://www.tuhs.org/Archive/PDP-11/Distributions/research/Dennis_v6/ 376 | 377 | ... 378 | A portion of the `http://www.tuhs.org/Archive/PDP-11/Distributions/DETAILS' 379 | file reads as follows: 380 | 381 | Dennis_v6 382 | --------- 383 | 384 | v6root.gz, v6src.gz and v6doc.gz are a set of three RK05 images of Sixth 385 | Edition with root, /usr and documentation, from Dennis Ritchie. The tape 386 | bootstraps are not included. The most recent timestamp on any file is 387 | July 19th 1975. 388 | 389 | v6root.tar.gz, v6src.tar.gz and v6doc.tar.gz are tar archives of the 390 | three RK05 images. 391 | 392 | ... 393 | The following files and the corresponding manual pages were all 394 | obtained from the tar archives described above: 395 | 396 | sh.c: 397 | What: Original source code for the Sixth Edition (V6) UNIX Thompson shell 398 | Date: July 17, 1975 399 | From: Sixth Edition UNIX /usr/source/s2/sh.c 400 | 401 | glob.c: 402 | What: Original source code for the Sixth Edition (V6) UNIX global command 403 | Date: May 14, 1975 404 | From: Sixth Edition UNIX /usr/source/s1/glob.c 405 | 406 | Jeffrey Allen Neitzel 2010/05/14 407 | 408 | @(#)$Id: 8a36afc5169208a221ff186984e19ed27bd86f55 $ 409 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Build and install instructions for osh! 2 | 3 | -------- 4 | SYNOPSIS 5 | env [variable=value ...] make [target ...] 6 | make [variable=value ...] [target ...] 7 | 8 | If the defaults described below match your desires and/or the 9 | requirements of your system, you can build and install the entire 10 | osh package by doing the following. 11 | 12 | % make 13 | # make install 14 | 15 | ... 16 | Otherwise, continue reading for full build and install details. 17 | See the EXAMPLES section at the end of this file for additional 18 | help if needed. 19 | 20 | --------- 21 | VARIABLES 22 | The Makefile defines the following configuration variables (default 23 | value listed). The user can modify the default configuration by 24 | passing the desired variable=value pair(s) on the command line. 25 | 26 | DESTDIR Unset by default. This may be used as a 27 | target directory for building/packaging 28 | binary packages if needed. 29 | 30 | PREFIX Defaults to /usr/local. This is the target 31 | directory where BINDIR, DOCDIR, MANDIR, and 32 | SYSCONFDIR are located by default. 33 | 34 | BINDIR Defaults to $(PREFIX)/bin. This is the target 35 | directory where the binaries are installed. 36 | 37 | DOCDIR Defaults to $(PREFIX)/share/doc/$(OSH_VERSION). 38 | This is the target directory for the [ACILNPR]* 39 | package documentation files. 40 | 41 | EXPDIR Defaults to $(DOCDIR)/examples. This is the 42 | target directory for the examples/* files. 43 | 44 | MANDIR Defaults to $(PREFIX)/share/man/man1. This is 45 | the target directory where the manual pages are 46 | installed. 47 | 48 | SYSCONFDIR Defaults to $(PREFIX)/etc. This is the target 49 | directory where the shell shall search for its 50 | system-wide rc (init and logout) files if such 51 | files are available on the system. See also: 52 | 53 | http://v6shell.org/rc_files 54 | 55 | ... 56 | for example rc files. 57 | 58 | INSTALL Defaults to /usr/bin/install. The install(1) 59 | utility is used to copy the resulting binaries, 60 | manual pages, and other files to final targets. 61 | 62 | Mac OS X only: 63 | The following configuration variable specifies the desired target 64 | architecture(s) for compiling universal binaries and/or 64-bit 65 | binaries and/or 32-bit binaries for Mac OS X running on Intel 66 | and PowerPC Macs. 67 | 68 | MOXARCH Unset by default. Possible value(s) may include 69 | one or more of the following on supported systems: 70 | -arch x86_64, -arch ppc64, -arch i386, -arch ppc. 71 | See also EXAMPLES. 72 | 73 | ------- 74 | TARGETS 75 | The following targets are available. 76 | 77 | all Default target is the same as typing `make'. 78 | Compiles everything and generates manual pages. 79 | 80 | oshall Compiles osh and generates manual pages. 81 | 82 | sh6all Compiles sh6, glob6, if, goto, fd2 and 83 | generates manual pages. 84 | 85 | install Installs all binaries and manual pages. 86 | 87 | install-oshall Installs osh binary and manual pages. 88 | 89 | install-sh6all Installs sh6all binaries and manual pages. 90 | 91 | install-doc Installs package documentation. 92 | 93 | install-exp Installs examples. 94 | 95 | clean-obj Removes all object files. 96 | 97 | clean Removes all binaries, object files, and other 98 | files generated during the build. 99 | 100 | -------- 101 | EXAMPLES 102 | The following compiles osh for /opt/local. 103 | Then, it installs the osh binary into /opt/local/bin, manual pages 104 | into /opt/local/share/man/man1, package documentation and examples 105 | into /opt/local/share/doc/$(OSH_VERSION), and also sets SYSCONFDIR 106 | to /opt/local/etc. 107 | 108 | % make PREFIX=/opt/local oshall 109 | # make PREFIX=/opt/local install-oshall install-doc install-exp 110 | 111 | The following compiles sh6, glob6, if, goto, and fd2 for /usr/pkg. 112 | Then, it installs these binaries into /usr/pkg/bin, manual pages 113 | into /usr/pkg/share/man/man1, and package documentation into 114 | /usr/pkg/share/doc/$(OSH_VERSION). 115 | 116 | % make PREFIX=/usr/pkg sh6all 117 | # make PREFIX=/usr/pkg install-sh6all install-doc 118 | 119 | The following compiles everything, configuring the shell to search 120 | for its system-wide rc files in /etc instead of /usr/local/etc by 121 | default. Then, it installs the entire osh package, including package 122 | documentation and examples, into the default location. 123 | 124 | % make SYSCONFDIR=/etc 125 | # make install install-doc install-exp 126 | 127 | The following compiles each program as a 2-way 32-bit universal 128 | binary for Mac OS X running on Intel and PowerPC Macs. Then, it 129 | installs the entire osh package, including package documentation 130 | and examples, into the default location. 131 | 132 | % make MOXARCH='-arch i386 -arch ppc' 133 | # make install install-doc install-exp 134 | 135 | The following compiles and installs the entire osh package, including 136 | package documentation and examples, into the default location on 137 | OpenSolaris. 138 | 139 | % uname -srvm 140 | SunOS 5.11 snv_111b i86pc 141 | % which cc gmake ginstall 142 | /usr/gnu/bin/cc 143 | /usr/bin/gmake 144 | /usr/bin/ginstall 145 | % gmake 146 | # gmake INSTALL=/usr/bin/ginstall install install-doc install-exp 147 | 148 | Jeffrey Allen Neitzel 2010/04/30 149 | 150 | @(#)$Id: d503a96ad00309d892d17bbceec5de88b0dddce7 $ 151 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ====================================================== 2 | Osh is hereby distributed under the following license: 3 | 4 | /*- 5 | * Copyright (c) 2003-2011 6 | * Jeffrey Allen Neitzel . 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 19 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 27 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | === 30 | 31 | ================================================================== 32 | Additionally, the original license for osh.1, osh.c, sh6.1, sh6.c, 33 | glob6.1, glob6.c, if.1, if.c, goto.1, goto.c, and util.c follows: 34 | 35 | /*- 36 | * Copyright (C) Caldera International Inc. 2001-2002. All rights reserved. 37 | * 38 | * Redistribution and use in source and binary forms, with or without 39 | * modification, are permitted provided that the following conditions 40 | * are met: 41 | * 1. Redistributions of source code and documentation must retain the above 42 | * copyright notice, this list of conditions and the following disclaimer. 43 | * 2. Redistributions in binary form must reproduce the above copyright 44 | * notice, this list of conditions and the following disclaimer in the 45 | * documentation and/or other materials provided with the distribution. 46 | * 3. All advertising materials mentioning features or use of this software 47 | * must display the following acknowledgement: 48 | * This product includes software developed or owned by Caldera 49 | * International, Inc. 50 | * 4. Neither the name of Caldera International, Inc. nor the names of other 51 | * contributors may be used to endorse or promote products derived from 52 | * this software without specific prior written permission. 53 | * 54 | * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 55 | * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 56 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 57 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 58 | * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 59 | * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 60 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 61 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 62 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 63 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 64 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 65 | * POSSIBILITY OF SUCH DAMAGE. 66 | */ 67 | === 68 | 69 | ==================================================================== 70 | Additionally, pexec.c is derived from /usr/src/lib/libc/gen/execvp.c 71 | of the NetBSD project. The original license follows: 72 | 73 | /*- 74 | * $NetBSD: execvp.c,v 1.24 2003/08/07 16:42:47 agc Exp $ 75 | * 76 | * Copyright (c) 1991, 1993 77 | * The Regents of the University of California. All rights reserved. 78 | * 79 | * Redistribution and use in source and binary forms, with or without 80 | * modification, are permitted provided that the following conditions 81 | * are met: 82 | * 1. Redistributions of source code must retain the above copyright 83 | * notice, this list of conditions and the following disclaimer. 84 | * 2. Redistributions in binary form must reproduce the above copyright 85 | * notice, this list of conditions and the following disclaimer in the 86 | * documentation and/or other materials provided with the distribution. 87 | * 3. Neither the name of the University nor the names of its contributors 88 | * may be used to endorse or promote products derived from this software 89 | * without specific prior written permission. 90 | * 91 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 92 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 93 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 94 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 95 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 96 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 97 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 98 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 99 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 100 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 101 | * SUCH DAMAGE. 102 | * 103 | * @(#)exec.c 8.1 (Berkeley) 6/4/93 104 | */ 105 | === 106 | 107 | ================================================================= 108 | Lastly, sasignal.c is derived from /usr/src/lib/libc/gen/signal.c 109 | of the OpenBSD project. The original license follows: 110 | 111 | /*- 112 | * $OpenBSD: signal.c,v 1.7 2005/08/08 08:05:34 espie Exp $ 113 | * 114 | * Copyright (c) 1985, 1989, 1993 115 | * The Regents of the University of California. All rights reserved. 116 | * 117 | * Redistribution and use in source and binary forms, with or without 118 | * modification, are permitted provided that the following conditions 119 | * are met: 120 | * 1. Redistributions of source code must retain the above copyright 121 | * notice, this list of conditions and the following disclaimer. 122 | * 2. Redistributions in binary form must reproduce the above copyright 123 | * notice, this list of conditions and the following disclaimer in the 124 | * documentation and/or other materials provided with the distribution. 125 | * 3. Neither the name of the University nor the names of its contributors 126 | * may be used to endorse or promote products derived from this software 127 | * without specific prior written permission. 128 | * 129 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 130 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 131 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 132 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 133 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 134 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 135 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 136 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 137 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 138 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 139 | * SUCH DAMAGE. 140 | */ 141 | === 142 | 143 | Jeffrey Allen Neitzel 2011/01/28 144 | 145 | @(#)$Id: ceede4125e1403c436bc20b7dfde764d50b0c1f3 $ 146 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for osh 2 | # 3 | # @(#)$Id: 0ff494d7f6a98d6d7cf2193f01c437f656996e4b $ 4 | # 5 | # Begin CONFIGURATION 6 | # 7 | # See the INSTALL file for build and install instructions. 8 | # 9 | 10 | # 11 | # Choose where and how to install the binaries and manual pages. 12 | # 13 | DESTDIR?= 14 | PREFIX?= /usr/local 15 | BINDIR?= $(PREFIX)/bin 16 | DOCDIR?= $(PREFIX)/share/doc/$(OSH_VERSION) 17 | EXPDIR?= $(DOCDIR)/examples 18 | MANDIR?= $(PREFIX)/share/man/man1 19 | SYSCONFDIR?= $(PREFIX)/etc 20 | #BINGRP= -g bin 21 | BINMODE= -m 0555 22 | #MANGRP= -g bin 23 | MANMODE= -m 0444 24 | 25 | # 26 | # Build utilities (SHELL must be POSIX-compliant) 27 | # 28 | INSTALL?= /usr/bin/install 29 | SHELL= /bin/sh 30 | 31 | # 32 | # Preprocessor, compiler, and linker flags 33 | # 34 | # If the compiler gives errors about any of flags specified 35 | # by `OPTIONS' or `WARNINGS' below, comment the appropriate 36 | # line(s) with a `#' character to fix the compiler errors. 37 | # Then, try to build again by doing a `make clean ; make'. 38 | # 39 | #CPPFLAGS= 40 | OPTIONS= -std=c99 -pedantic 41 | #OPTIONS+= -fstack-protector 42 | WARNINGS= -Wall -W 43 | # NOTE: It seems that -Wno-unused-result first appeared in gcc-4.4.0 . 44 | #WARNINGS= -Wno-unused-result 45 | #WARNINGS+= -Wstack-protector 46 | #CFLAGS+= -g 47 | CFLAGS+= -Os $(OPTIONS) $(WARNINGS) 48 | #LDFLAGS+= -static 49 | 50 | # 51 | # End CONFIGURATION 52 | # 53 | # !!! ================= Developer stuff below... ================= !!! 54 | 55 | # 56 | # Adjust CFLAGS and LDFLAGS for MOXARCH if needed. 57 | # 58 | MOXARCH?= 59 | CFLAGS+= $(MOXARCH) 60 | LDFLAGS+= $(MOXARCH) 61 | 62 | # 63 | # The following specifies the osh date and version: 64 | # 65 | # osh-current == unversioned development 66 | # osh-YYYYMMDD-current == development snapshot 67 | # osh-YYYYMMDD-beta[1-9] == beta release 68 | # osh-YYYYMMDD == official release 69 | # osh-YYYYMMDD-p[1-9] == patched release 70 | # 71 | OSH_DATE= July 29, 2011 72 | OSH_VERSION= osh-current 73 | 74 | OSH= osh 75 | SH6= sh6 glob6 76 | UBIN= fd2 goto if 77 | GHEAD= config.h defs.h 78 | ERRSRC= err.h err.c 79 | PEXSRC= pexec.h pexec.c 80 | SIGSRC= sasignal.h sasignal.c 81 | OBJ= err.o fd2.o glob6.o goto.o if.o osh.o pexec.o sasignal.o sh6.o util.o v.o 82 | OSHMAN= osh.1.out 83 | SH6MAN= sh6.1.out glob6.1.out 84 | UMAN= fd2.1.out goto.1.out if.1.out 85 | MANALL= $(OSHMAN) $(SH6MAN) $(UMAN) 86 | SEDSUB= -e 's|@OSH_DATE@|$(OSH_DATE)|' \ 87 | -e 's|@OSH_VERSION@|$(OSH_VERSION)|' \ 88 | -e 's|@SYSCONFDIR@|$(SYSCONFDIR)|' 89 | 90 | DEFS= -DOSH_VERSION='"$(OSH_VERSION)"' -DSYSCONFDIR='"$(SYSCONFDIR)"' 91 | 92 | .SUFFIXES: .1 .1.out .c .o 93 | 94 | .1.1.out: 95 | sed $(SEDSUB) <$< >$@ 96 | 97 | .c.o: 98 | $(CC) -c $(CFLAGS) $(CPPFLAGS) $(DEFS) $< 99 | 100 | # 101 | # Build targets 102 | # 103 | all: oshall sh6all 104 | 105 | oshall: $(OSH) $(OSHMAN) $(UMAN) 106 | 107 | sh6all: $(SH6) $(SH6MAN) utils 108 | 109 | utils: $(UBIN) $(UMAN) 110 | 111 | man: $(MANALL) 112 | 113 | osh: sh.h v.c osh.c util.c $(GHEAD) $(ERRSRC) $(PEXSRC) $(SIGSRC) 114 | @$(MAKE) $@bin 115 | 116 | sh6: sh.h v.c sh6.c $(GHEAD) $(ERRSRC) $(PEXSRC) $(SIGSRC) 117 | @$(MAKE) $@bin 118 | 119 | glob6: v.c glob6.c $(GHEAD) $(ERRSRC) $(PEXSRC) 120 | @$(MAKE) $@bin 121 | 122 | if: v.c if.c $(GHEAD) $(ERRSRC) $(PEXSRC) $(SIGSRC) 123 | @$(MAKE) $@bin 124 | 125 | goto: v.c goto.c $(GHEAD) $(ERRSRC) 126 | @$(MAKE) $@bin 127 | 128 | fd2: v.c fd2.c $(GHEAD) $(ERRSRC) $(PEXSRC) 129 | @$(MAKE) $@bin 130 | 131 | $(OBJ) : $(GHEAD) 132 | fd2.o glob6.o goto.o if.o osh.o pexec.o sh6.o util.o: err.h 133 | fd2.o glob6.o if.o osh.o sh6.o : pexec.h 134 | if.o osh.o sh6.o : sasignal.h 135 | osh.o sh6.o util.o : sh.h 136 | err.o : $(ERRSRC) 137 | pexec.o : $(PEXSRC) 138 | sasignal.o : $(SIGSRC) 139 | 140 | config.h: mkconfig 141 | $(SHELL) ./mkconfig 142 | 143 | oshbin: v.o osh.o err.o util.o pexec.o sasignal.o 144 | $(CC) $(LDFLAGS) -o osh v.o osh.o err.o util.o pexec.o sasignal.o $(LIBS) 145 | 146 | sh6bin: v.o sh6.o err.o pexec.o sasignal.o 147 | $(CC) $(LDFLAGS) -o sh6 v.o sh6.o err.o pexec.o sasignal.o $(LIBS) 148 | 149 | glob6bin: v.o glob6.o err.o pexec.o 150 | $(CC) $(LDFLAGS) -o glob6 v.o glob6.o err.o pexec.o $(LIBS) 151 | 152 | ifbin: v.o if.o err.o pexec.o sasignal.o 153 | $(CC) $(LDFLAGS) -o if v.o if.o err.o pexec.o sasignal.o $(LIBS) 154 | 155 | gotobin: v.o goto.o err.o 156 | $(CC) $(LDFLAGS) -o goto v.o goto.o err.o $(LIBS) 157 | 158 | fd2bin: v.o fd2.o err.o pexec.o 159 | $(CC) $(LDFLAGS) -o fd2 v.o fd2.o err.o pexec.o $(LIBS) 160 | 161 | # 162 | # Install targets 163 | # 164 | DESTBINDIR= $(DESTDIR)$(BINDIR) 165 | DESTDOCDIR= $(DESTDIR)$(DOCDIR) 166 | DESTEXPDIR= $(DESTDIR)$(EXPDIR) 167 | DESTMANDIR= $(DESTDIR)$(MANDIR) 168 | install: install-oshall install-sh6all 169 | 170 | install-oshall: oshall install-osh install-uman 171 | 172 | install-sh6all: sh6all install-sh6 install-utils 173 | 174 | install-utils: install-ubin install-uman 175 | 176 | install-osh: $(OSH) $(OSHMAN) install-dest 177 | $(INSTALL) -c -s $(BINGRP) $(BINMODE) osh $(DESTBINDIR) 178 | $(INSTALL) -c $(MANGRP) $(MANMODE) osh.1.out $(DESTMANDIR)/osh.1 179 | 180 | install-sh6: $(SH6) $(SH6MAN) install-dest 181 | $(INSTALL) -c -s $(BINGRP) $(BINMODE) sh6 $(DESTBINDIR) 182 | $(INSTALL) -c $(MANGRP) $(MANMODE) sh6.1.out $(DESTMANDIR)/sh6.1 183 | $(INSTALL) -c -s $(BINGRP) $(BINMODE) glob6 $(DESTBINDIR) 184 | $(INSTALL) -c $(MANGRP) $(MANMODE) glob6.1.out $(DESTMANDIR)/glob6.1 185 | 186 | install-ubin: $(UBIN) install-dest 187 | $(INSTALL) -c -s $(BINGRP) $(BINMODE) fd2 $(DESTBINDIR) 188 | $(INSTALL) -c -s $(BINGRP) $(BINMODE) goto $(DESTBINDIR) 189 | $(INSTALL) -c -s $(BINGRP) $(BINMODE) if $(DESTBINDIR) 190 | 191 | install-uman: $(UMAN) install-dest 192 | $(INSTALL) -c $(MANGRP) $(MANMODE) fd2.1.out $(DESTMANDIR)/fd2.1 193 | $(INSTALL) -c $(MANGRP) $(MANMODE) goto.1.out $(DESTMANDIR)/goto.1 194 | $(INSTALL) -c $(MANGRP) $(MANMODE) if.1.out $(DESTMANDIR)/if.1 195 | 196 | install-dest: 197 | test -d $(DESTBINDIR) || { umask 0022 && mkdir -p $(DESTBINDIR) ; } 198 | test -d $(DESTMANDIR) || { umask 0022 && mkdir -p $(DESTMANDIR) ; } 199 | 200 | install-doc: 201 | test -d $(DESTDOCDIR) || { umask 0022 && mkdir -p $(DESTDOCDIR) ; } 202 | $(INSTALL) -c $(MANGRP) $(MANMODE) [ACILNPR]* $(DESTDOCDIR) 203 | 204 | install-exp: 205 | test -d $(DESTEXPDIR) || { umask 0022 && mkdir -p $(DESTEXPDIR) ; } 206 | $(INSTALL) -c $(MANGRP) $(MANMODE) examples/* $(DESTEXPDIR) 207 | 208 | # 209 | # Cleanup targets 210 | # 211 | clean-obj: 212 | rm -f $(OBJ) 213 | 214 | clean: clean-obj 215 | rm -f $(OSH) $(SH6) $(UBIN) $(MANALL) config.h 216 | 217 | # 218 | # Release target 219 | # 220 | release: clean 221 | rm -rf .release 222 | oshrelease .release $(OSH_VERSION) 223 | -------------------------------------------------------------------------------- /NOTES: -------------------------------------------------------------------------------- 1 | This file provides an implementation overview of the software 2 | released as part of the osh project, focusing on history and 3 | compatibility since these are the primary project objectives. 4 | 5 | --------------------------------------- 6 | Historical notes for osh(1) and sh6(1): 7 | 8 | The Thompson shell, by Ken Thompson of Bell Labs, was distributed 9 | as the standard command interpreter through Sixth Edition UNIX. 10 | Then, in the Seventh Edition, it was replaced by the Bourne shell. 11 | However, the Thompson shell was still distributed with the system 12 | as osh because of known portability problems with the Bourne shell's 13 | memory management in Seventh Edition UNIX. 14 | 15 | The name of the Thompson shell's binary executable was `sh'. 16 | It was installed as `/bin/sh' through Sixth Edition UNIX and 17 | made use of the following external utilities: 18 | 19 | 1) /bin/exit was used to terminate command files. 20 | 21 | 2) /bin/goto was used to transfer the shell's control 22 | from one point to another within a command file. 23 | 24 | 3) /bin/if was used to evaluate conditional expressions. 25 | This is the predecessor of test(1), which was first 26 | released in Seventh Edition UNIX. 27 | 28 | 4) /etc/glob was used to expand `*', `?', and `[...]' 29 | in command arguments. 30 | 31 | The functionality of each of the above-mentioned utilities is 32 | provided here. However, the `exit' utility is implemented as a 33 | special built-in command for both osh(1) and sh6(1). 34 | 35 | For osh(1), ports of `glob', `goto', and `if' are built into the 36 | shell. For sh6(1), however, each of these utilities remains as an 37 | external utility. 38 | 39 | For sh6(1), the Thompson-shell port's binary executable has been 40 | renamed from `sh' to `sh6' to avoid name conflict and confusion 41 | with the system shell, sh(1), on modern UNIX systems. Similarly, 42 | the `glob' utility has been renamed to `glob6' and is installed 43 | into the same directory as the shell, /usr/local/bin by default, 44 | rather than being installed into the /etc directory. 45 | 46 | Additionally, see the glob6(1), goto(1), and if(1) manual pages for 47 | full details regarding the ports of the above-mentioned utilities. 48 | 49 | ------------------------------- 50 | Compatibility notes for osh(1): 51 | 52 | This is an enhanced, backward-compatible port of the Thompson shell 53 | from Sixth Edition UNIX. However, when it is known to differ in 54 | some way from the original, this fact is indicated with a `(+)' in 55 | the osh(1) manual page. 56 | 57 | Unlike the original, this port of the shell can handle 8-bit character 58 | sets, as well as the UTF-8 encoding. The original, on the other 59 | hand, can only handle 7-bit ASCII. 60 | 61 | Further details regarding some of the known differences: 62 | 63 | 1) This port of the shell uses PATH to search for external commands, 64 | but the original always uses the equivalent of `.:/bin:/usr/bin'. 65 | The sh(1) manual page from Sixth Edition UNIX reads as follows: 66 | 67 | If the first argument is the name of an executable file, 68 | it is invoked; otherwise the string `/bin/' is prepended 69 | to the argument. (In this way most standard commands, 70 | which reside in `/bin', are found.) If no such command is 71 | found, the string `/usr' is further prepended (to give 72 | `/usr/bin/command') and another attempt is made to execute 73 | the resulting file. (Certain lesser-used commands live in 74 | `/usr/bin'.) 75 | 76 | ... 77 | The primary reason this port of the shell uses PATH instead of a 78 | procedure like that described above is for both user convenience 79 | and security. The behavior described above can conceivably be 80 | quite dangerous as an unchangeable default. 81 | 82 | Using PATH allows the user to choose the search behavior. 83 | If search behavior like that of the original is desired, the 84 | user can set PATH to a value of `.:/bin:/usr/bin' in order to 85 | accomplish this. 86 | 87 | 2) This port of the shell integrates the previously external `echo', 88 | `fd2', `glob', `goto', and `if' shell utilities as special built-in 89 | commands in order to improve shell performance and reliability. 90 | This does not change the user-visible behavior of the shell or 91 | utilities. 92 | 93 | 3) This port of the shell prints a progname prefix (e.g., `osh: ') 94 | for all diagnostics. This results in `osh: file: cannot open' 95 | instead of `file: cannot open', `osh: syntax error' instead of 96 | `syntax error', and so forth. 97 | 98 | 4) This port of the shell ignores the first line of a command file 99 | if it begins with `#!' in order to play nicely with kernels which 100 | support the `#!' mechanism. For example, the first line might be 101 | `#!/usr/local/bin/osh' or `#!/usr/bin/env osh'. This is just for 102 | user convenience in the face of conflicting shell languages. 103 | 104 | 5) The original implementation of the shell does shell accounting 105 | in order to record command execution data; this port does not. 106 | 107 | ------------------------------- 108 | Compatibility notes for sh6(1): 109 | 110 | This is a port of the Thompson shell from Sixth Edition UNIX. 111 | However, when it is known to differ in some way from the original, 112 | this fact is indicated with a `(+)' in the sh6(1) manual page. 113 | 114 | Like the original, this port of the shell is not 8-bit clean as it 115 | uses the high-order bit of characters for quoting. Thus, the only 116 | complete character set it can handle is 7-bit ASCII. 117 | 118 | Aside from those differences which are detailed either here or in 119 | the manual page, the CHANGES6 file contains further information 120 | regarding how this port differs from the original. 121 | 122 | Further details regarding the substantial differences: 123 | 124 | 1) This port of the shell uses PATH to search for external commands, 125 | but the original always uses the equivalent of `.:/bin:/usr/bin'. 126 | The sh(1) manual page from Sixth Edition UNIX reads as follows: 127 | 128 | If the first argument is the name of an executable file, 129 | it is invoked; otherwise the string `/bin/' is prepended 130 | to the argument. (In this way most standard commands, 131 | which reside in `/bin', are found.) If no such command is 132 | found, the string `/usr' is further prepended (to give 133 | `/usr/bin/command') and another attempt is made to execute 134 | the resulting file. (Certain lesser-used commands live in 135 | `/usr/bin'.) 136 | 137 | ... 138 | The primary reason this port of the shell uses PATH instead of a 139 | procedure like that described above is for both user convenience 140 | and security. The behavior described above can conceivably be 141 | quite dangerous as an unchangeable default. 142 | 143 | Using PATH allows the user to choose the search behavior. 144 | If search behavior like that of the original is desired, the 145 | user can set PATH to a value of `.:/bin:/usr/bin' in order to 146 | accomplish this. 147 | 148 | 2) This port of the shell ignores the first line of a command file 149 | if it begins with `#!' in order to play nicely with kernels which 150 | support the `#!' mechanism. For example, the first line might be 151 | `#!/usr/local/bin/sh6' or `#!/usr/bin/env sh6'. This is just for 152 | user convenience in the face of conflicting shell languages. 153 | 154 | 3) The original implementation of the shell does shell accounting 155 | in order to record command execution data; this port does not. 156 | 157 | Jeffrey Allen Neitzel 2010/04/30 158 | 159 | @(#)$Id: ffc15d0829e09df70d80afe87e4cb988ad81d4eb $ 160 | -------------------------------------------------------------------------------- /PROJECT: -------------------------------------------------------------------------------- 1 | % cat < $h/.project 2 | 3 | V6 Shell (Osh Project) 4 | 5 | __ ____ ____ _ _ _ 6 | \ \ / / /_ / ___|| |__ ___| | | 7 | \ \ / / '_ \ \___ \| '_ \ / _ \ | | 8 | \ V /| (_) | ___) | | | | __/ | | 9 | \_/ \___/ |____/|_| |_|\___|_|_| 10 | 11 | http://v6shell.org/ - Home Page 12 | http://v6shell.org/git - GitHub Repo 13 | http://v6shell.org/wiki - GitHub Wiki 14 | http://v6shell.org/twitter - on Twitter 15 | 16 | Osh is an enhanced, backward-compatible port of the 17 | Sixth Edition (V6) UNIX Thompson shell (circa 1975). 18 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Welcome to osh! 2 | 3 | The osh package provides two ports of the original /bin/sh from 4 | Sixth Edition (V6) UNIX (circa 1975). 5 | 6 | Osh(1) is an enhanced, backward-compatible port of the Sixth Edition 7 | Thompson shell. Sh6(1) is an unenhanced port of the shell, and 8 | glob6(1) is a port of its global command. Together, sh6 and glob6 9 | provide a user interface which is backward compatible with that 10 | provided by the Sixth Edition Thompson shell and global command, 11 | but without the obvious enhancements found in osh. 12 | 13 | The original Thompson shell was principally written by Ken Thompson 14 | of Bell Labs. 15 | 16 | Notice that this package also includes the following shell utilities: 17 | 18 | if(1) - conditional command (ported from Sixth Edition UNIX) 19 | 20 | goto(1) - transfer command (ported from Sixth Edition UNIX) 21 | 22 | fd2(1) - redirect from/to file descriptor 2 23 | 24 | ------- 25 | See the INSTALL file for build and install instructions. 26 | 27 | ------- 28 | The osh package should build successfully on any POSIX-compliant 29 | UNIX system. It has been reported to build successfully on the 30 | following systems: 31 | 32 | System Releases / Distributions / Additional Info 33 | ---------------------------------------------------------- 34 | DragonFly BSD 2.0.1 35 | FreeBSD 6.1, 7.0 36 | Mac OS X 10.4, 10.5, 10.6, 10.7 37 | NetBSD 2.1, 3.1.1, 4.0, 4.0.1, 5.0, 5.0.1 38 | OpenBSD 4.1, 4.2, 4.3, 4.4, 4.5, 4.6 39 | OpenSolaris 2008.05, 2008.11, 2009.06 (See last example 40 | in EXAMPLES section of INSTALL file.) 41 | GNU/Linux CentOS 5.2, Debian 5.0.3 (lenny), Linpus, 42 | Slackware 13.0, Ubuntu 43 | 44 | If your system is not reported above, simply try to build the osh 45 | package to see if it works or not. In either case, please report 46 | the results to the developer if possible. The resulting "config.h" 47 | file and the compiler name/version is most helpful. 48 | 49 | Please send osh bug reports to . Before 50 | reporting a bug, please try to reproduce it with the latest version 51 | of the code. With bug reports, please try to ensure that enough 52 | information to reproduce the problem is enclosed. Also, if a known 53 | fix for it exists, then please include that as well. 54 | 55 | If you have any comments or questions about this software, I encourage 56 | you to contact me via email. Thanks & Enjoy! 57 | 58 | Jeffrey Allen Neitzel 59 | 60 | http://v6shell.org/ 2011/07/29 61 | 62 | @(#)$Id: 0d48a7a2ee5cc48569b8d86a02090f1397ba82a5 $ 63 | -------------------------------------------------------------------------------- /defs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * osh - an enhanced port of the Sixth Edition (V6) UNIX Thompson shell 3 | */ 4 | /*- 5 | * Copyright (c) 2004-2011 6 | * Jeffrey Allen Neitzel . 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 19 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 27 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | * @(#)$Id: fdbcda17d47b9516324ecb05f2fec52258958226 $ 30 | */ 31 | 32 | #ifndef DEFS_H 33 | #define DEFS_H 34 | 35 | /* 36 | * required header files 37 | */ 38 | #include "config.h" 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | #ifdef PATH_MAX 58 | #define PATHMAX PATH_MAX 59 | #else 60 | #define PATHMAX 1024 61 | #endif 62 | 63 | #ifdef ARG_MAX 64 | #define GAVMAX ARG_MAX 65 | #else 66 | #define GAVMAX 1048576 67 | #endif 68 | #define GAVMULT 2U /* base GAVNEW reallocation multiplier */ 69 | #define GAVNEW 128U /* base # of new arguments per gav allocation */ 70 | 71 | #ifdef _POSIX_OPEN_MAX 72 | #define FDFREEMIN _POSIX_OPEN_MAX 73 | #else 74 | #define FDFREEMIN 20 /* Value is the same as _POSIX_OPEN_MAX. */ 75 | #endif 76 | #define FDFREEMAX 4096 /* Arbitrary maximum value for fd_free(). */ 77 | 78 | #define SOURCEMAX 64 /* Maximum # of nested source invocations */ 79 | 80 | #define LINEMAX 2048 /* 1000 in the original Sixth Edition shell */ 81 | #define WORDMAX 1024 /* 50 ... */ 82 | 83 | #define ASCII 0177 84 | #define QUOTE 0200 85 | 86 | #define SBUFMM(m) ((32 * (m)) + 1)/* small buffer max multiplier */ 87 | #define DOLMAX SBUFMM(1) /* used by osh(1) and sh6(1) shells */ 88 | #define LABELMAX SBUFMM(2) /* used by goto(1) utility */ 89 | 90 | /* 91 | * Following standard conventions, file descriptors 0, 1, and 2 are used 92 | * for standard input, standard output, and standard error respectively. 93 | */ 94 | #define FD0 STDIN_FILENO 95 | #define FD1 STDOUT_FILENO 96 | #define FD2 STDERR_FILENO 97 | 98 | #define F_GZ 1 /* `-s' primary for if(1) utility */ 99 | #define F_OT 2 /* `-ot' ... */ 100 | #define F_NT 3 /* `-nt' ... */ 101 | #define F_EF 4 /* `-ef' ... */ 102 | 103 | #define DOLSUB true 104 | #define FORKED true 105 | #define RETERR true 106 | 107 | #define EQUAL(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) 108 | #define IS_DIGIT(d, c) ((d) >= 0 && (d) <= 9 && "0123456789"[(d) % 10] == (c)) 109 | 110 | /* 111 | * special character literals 112 | */ 113 | #define BANG '!' 114 | #define COLON ':' 115 | #define DOLLAR '$' 116 | #define DOT '.' 117 | #define EOL '\n' 118 | #define EOS '\0' 119 | #define HASH '#' 120 | #define SLASH '/' 121 | #define SPACE ' ' 122 | #define TAB '\t' 123 | #define BQUOT '\\' 124 | #define DQUOT '"' 125 | #define SQUOT '\'' 126 | 127 | #define LPARENTHESIS '(' 128 | #define RPARENTHESIS ')' 129 | #define SEMICOLON ';' 130 | #define AMPERSAND '&' 131 | #define VERTICALBAR '|' 132 | #define CARET '^' 133 | #define LESSTHAN '<' 134 | #define GREATERTHAN '>' 135 | 136 | #define ASTERISK '*' 137 | #define QUESTION '?' 138 | #define LBRACKET '[' 139 | #define RBRACKET ']' 140 | #define HYPHEN '-' 141 | 142 | /* 143 | * special string literals 144 | */ 145 | #define EOC ";&\n" 146 | #define GLOBCHARS "*?[" 147 | #define QUOTPACK "\"'" 148 | #define REDIRERR "(<>" 149 | #define WORDPACK " \t\"'();&|^<>\n" 150 | 151 | /* 152 | * typedefs and related macros 153 | */ 154 | typedef unsigned char UChar; 155 | #define UCHAR(c) ((UChar)(c)) 156 | #define UCPTR(p) ((UChar *)(p)) 157 | 158 | #endif /* !DEFS_H */ 159 | -------------------------------------------------------------------------------- /err.c: -------------------------------------------------------------------------------- 1 | /* 2 | * err.c - shell and utility error-handling routines 3 | */ 4 | /*- 5 | * Copyright (c) 2004-2011 6 | * Jeffrey Allen Neitzel . 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 19 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 27 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | * @(#)$Id: 725f99b08c07ee3cd055fbec30bf9011777ac517 $ 30 | */ 31 | 32 | #include "defs.h" 33 | #include "err.h" 34 | 35 | #define FMTMAX SBUFMM(2) 36 | #define MSGMAX (FMTMAX + LINEMAX) 37 | 38 | #define MYNAME "unknown" 39 | 40 | static void (*myerrexit)(int) = NULL; 41 | /*@observer@*/ 42 | static const char *myname = NULL; 43 | static pid_t mypid = -1; 44 | 45 | static void wmsg(int, const char *, va_list); 46 | 47 | /* 48 | * Handle all errors for the calling process. This includes printing 49 | * any specified non-NULL message to the standard error and calling 50 | * the error exit function pointed to by the global myerrexit. 51 | * This function may or may not return. 52 | */ 53 | void 54 | err(int es, const char *msgfmt, ...) 55 | { 56 | va_list va; 57 | 58 | if (msgfmt != NULL) { 59 | va_start(va, msgfmt); 60 | wmsg(FD2, msgfmt, va); 61 | va_end(va); 62 | } 63 | if (myerrexit == NULL) { 64 | fd_print(FD2, FMT1S, "err: Invalid myerrexit function pointer"); 65 | abort(); 66 | } 67 | 68 | (*myerrexit)(es); 69 | } 70 | 71 | /* 72 | * Print any specified non-NULL message to the file descriptor pfd. 73 | */ 74 | void 75 | fd_print(int pfd, const char *msgfmt, ...) 76 | { 77 | va_list va; 78 | 79 | if (msgfmt != NULL) { 80 | va_start(va, msgfmt); 81 | wmsg(pfd, msgfmt, va); 82 | va_end(va); 83 | } 84 | } 85 | 86 | /* 87 | * Return a pointer to the global myname on success. 88 | * Return a pointer to "(null)" on error. 89 | * 90 | * NOTE: Must call setmyname(argv[0]) first. 91 | */ 92 | const char * 93 | getmyname(void) 94 | { 95 | 96 | if (myname == NULL) 97 | return "(null)"; 98 | 99 | return myname; 100 | } 101 | 102 | /* 103 | * Return the global mypid on success. 104 | * Return 0 on error. 105 | * 106 | * NOTE: Must call setmypid(getpid()) first. 107 | */ 108 | pid_t 109 | getmypid(void) 110 | { 111 | 112 | if (mypid == -1) 113 | return 0; 114 | 115 | return mypid; 116 | } 117 | 118 | /* 119 | * Set the global myerrexit to the function pointed to by func. 120 | */ 121 | void 122 | setmyerrexit(void (*func)(int)) 123 | { 124 | 125 | if (func == NULL) 126 | return; 127 | 128 | myerrexit = func; 129 | } 130 | 131 | /* 132 | * Set the global myname to the basename of the string pointed to by s. 133 | */ 134 | void 135 | setmyname(const char *s) 136 | { 137 | const char *p; 138 | 139 | if (s != NULL && *s != EOS) { 140 | if ((p = strrchr(s, SLASH)) != NULL) 141 | p++; 142 | else 143 | p = s; 144 | if (*p == HYPHEN && *(p + 1) != EOS) 145 | p++; 146 | else if (*p == EOS) 147 | /* should never (but can) be true */ 148 | p = MYNAME; 149 | } else 150 | /* should never (but can) be true */ 151 | p = MYNAME; 152 | 153 | myname = p; 154 | } 155 | 156 | /* 157 | * Set the global mypid to the process ID p. 158 | */ 159 | void 160 | setmypid(const pid_t p) 161 | { 162 | 163 | if (mypid != -1) 164 | return; 165 | 166 | mypid = p; 167 | } 168 | 169 | /* 170 | * Cause all shell utility processes to exit appropriately on error. 171 | * This function is called by err() and never returns. 172 | */ 173 | void 174 | ut_errexit(int es) 175 | { 176 | 177 | #ifdef DEBUG 178 | fd_print(FD2, "ut_errexit: es == %d: Call %s(%d);\n", 179 | es, (getpid() == getmypid()) ? "exit" : "_exit", es); 180 | #endif 181 | 182 | EXIT(es); 183 | } 184 | 185 | /* 186 | * Write the specified message to the file descriptor wfd. 187 | * A diagnostic is written to FD2 on error. 188 | */ 189 | static void 190 | wmsg(int wfd, const char *msgfmt, va_list va) 191 | { 192 | char msg[MSGMAX]; 193 | char fmt[FMTMAX]; 194 | struct iovec ev[4]; 195 | int i; 196 | 197 | i = snprintf(fmt, sizeof(fmt), "%s", msgfmt); 198 | if (i >= 1 && i < (int)sizeof(fmt)) { 199 | i = vsnprintf(msg, sizeof(msg), fmt, va); 200 | if (i >= 0 && i < (int)sizeof(msg)) { 201 | if (write(wfd, msg, strlen(msg)) == -1) { 202 | ev[0].iov_base = (char *)getmyname(); 203 | ev[0].iov_len = strlen(getmyname()); 204 | ev[1].iov_base = ": "; 205 | ev[1].iov_len = (size_t)2; 206 | ev[2].iov_base = ERR_WRITE; 207 | ev[2].iov_len = strlen(ERR_WRITE); 208 | ev[3].iov_base = "\n"; 209 | ev[3].iov_len = (size_t)1; 210 | (void)writev(FD2, ev, 4); 211 | } 212 | } 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /err.h: -------------------------------------------------------------------------------- 1 | /* 2 | * osh - an enhanced port of the Sixth Edition (V6) UNIX Thompson shell 3 | */ 4 | /*- 5 | * Copyright (c) 2004-2011 6 | * Jeffrey Allen Neitzel . 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 19 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 27 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | * @(#)$Id: e928b9fb48cff519bf15f76c5c169fab7e265b29 $ 30 | */ 31 | 32 | #ifndef ERR_H 33 | #define ERR_H 34 | 35 | /* 36 | * required header files 37 | */ 38 | #include 39 | 40 | /* 41 | * diagnostics 42 | */ 43 | #define ERR_PAREN ") expected" 44 | #define ERR_ALIASLOOP "Alias loop error" 45 | #define ERR_GARGCOUNT "Arg count" 46 | #define ERR_E2BIG "Arg list too long" 47 | #define ERR_FORK "Cannot fork - try again" 48 | #define ERR_PIPE "Cannot pipe - try again" 49 | #define ERR_TRIM "Cannot trim" 50 | #define ERR_WRITE "Cannot write" 51 | #define ERR_GNOTFOUND "Command not found." 52 | #define ERR_ALINVAL "Invalid argument list" 53 | #define ERR_AVIINVAL "Invalid argv index" 54 | #define ERR_NODIR "No directory" 55 | #define ERR_NOHOMEDIR "No home directory" 56 | #define ERR_NOMATCH "No match" 57 | #define ERR_NOPWD "No previous directory" 58 | #define ERR_NOSHELL "No shell!" 59 | #define ERR_NOTTY "No terminal!" 60 | #define ERR_NOMEM "Out of memory" 61 | #define ERR_PATTOOLONG "Pattern too long" 62 | #define ERR_SETID "Set-ID execution denied" 63 | #define ERR_TMARGS "Too many args" 64 | #define ERR_TMCHARS "Too many characters" 65 | #define ERR_ARGCOUNT "arg count" 66 | #define ERR_ARGUMENT "argument expected" 67 | #define ERR_BADDIR "bad directory" 68 | #define ERR_BADMASK "bad mask" 69 | #define ERR_BADNAME "bad name" 70 | #define ERR_BADSIGNAL "bad signal" 71 | #define ERR_CREATE "cannot create" 72 | #define ERR_EXEC "cannot execute" 73 | #define ERR_OPEN "cannot open" 74 | #define ERR_SEEK "cannot seek" 75 | #define ERR_COMMAND "command expected" 76 | #define ERR_DIGIT "digit expected" 77 | #define ERR_GENERIC "error" 78 | #define ERR_EXPR "expression expected" 79 | #define ERR_LABNOTFOUND "label not found" 80 | #define ERR_LABTOOLONG "label too long" 81 | #define ERR_NOARGS "no args" 82 | #define ERR_NOTDIGIT "not a digit" 83 | #define ERR_NOTFOUND "not found" 84 | #define ERR_OPERATOR "operator expected" 85 | #define ERR_SYNTAX "syntax error" 86 | #define ERR_OPUNKNOWN "unknown operator" 87 | #define ERR_BRACE "} expected" 88 | #define FD2_USAGE "usage: %s [-e] [-f file] [--] command [arg ...]\n" 89 | 90 | #define FMT1S "%s\n" 91 | #define FMT2S "%s: %s\n" 92 | #define FMT3S "%s: %s: %s\n" 93 | #define FMT4S "%s: %s: %s: %s\n" 94 | 95 | /* 96 | * exit status values 97 | */ 98 | #define FC_ERR 124 /* fatal child error (changed in pwait()) */ 99 | #define SH_ERR 2 /* shell-detected error (default value) */ 100 | #define SH_FALSE 1 101 | #define SH_TRUE 0 102 | 103 | #define ESTATUS ((getpid() == getmypid()) ? SH_ERR : FC_ERR) 104 | #define EXIT(s) ((getpid() == getmypid()) ? exit((s)) : _exit((s))) 105 | 106 | #undef DEBUG 107 | 108 | /*@maynotreturn@*/ 109 | void err(int, /*@null@*/ const char *, /*@printflike@*/ ...); 110 | void fd_print(int, /*@null@*/ const char *, /*@printflike@*/ ...); 111 | /*@observer@*/ 112 | const char *getmyname(void); 113 | pid_t getmypid(void); 114 | void setmyerrexit(void (*)(int)); 115 | void setmyname(/*@null@*/ /*@observer@*/ const char *); 116 | void setmypid(const pid_t); 117 | /*@noreturn@*/ 118 | void ut_errexit(int); 119 | 120 | #endif /* !ERR_H */ 121 | -------------------------------------------------------------------------------- /examples/FILEPREP: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osh 2 | : 3 | : osh - " Force sh(1), csh(1), and other shells to exit w/ error! " <'' ;;; 4 | : 5 | : " @(#)$Id: 12bc3231bb952e422059dab9d296f8850c3eb788 $ " 6 | : 7 | : " The author of this file, J.A. Neitzel , " 8 | : " hereby grants it to the public domain. " 9 | : 10 | 11 | : 12 | : " Prepare system-wide rc files (etc.*) & user rc files (dot.*) " 13 | : " for installation on current machine so interactive & login " 14 | : " instances of osh can execute them on user's behalf. " 15 | : 16 | : " Print message, and exit w/ zero status on success. " 17 | : " Print diagnostic, and exit w/ non-zero status on error. " 18 | : 19 | : " usage: osh FILEPREP /path/to/nonexistent_directory " 20 | : 21 | 22 | : " Check for correct usage. " 23 | 24 | if X$0 != XFILEPREP -a X$0 != X./FILEPREP\ 25 | if { exit } fd2 -e echo FILEPREP: $0: Invalid FILEPREP pathname ; false 26 | if $n != 1 -o X$1 = X\ 27 | if { exit } fd2 -e echo usage: osh $0 /path/to/nonexistent_directory ;\ 28 | false 29 | if -e $1'' -o -h $1''\ 30 | if { exit } fd2 -e echo FILEPREP: $1: File exists ; false 31 | if { fd2 which . >/dev/null }\ 32 | if { exit } fd2 -e echo $0: which: Invalid results ; false 33 | if ! { which chmod cp head mkdir pwd rm strings tee tr >/dev/null }\ 34 | if { exit } false 35 | 36 | : " Do needed setup. " 37 | 38 | sigign + 2 3 ; umask 0022 39 | if { mkdir -p $1'' } cp *osh* $1/ 40 | if $s != 0 if { exit } false 41 | cd $1'' ; chmod 0644 * 42 | if ! { mkdir tmp-$$ } if { exit } false 43 | setenv OSHDIR tmp-$$ 44 | 45 | : " Prepare files for installation. " 46 | 47 | echo -n "<$1 ( rm -f $1 ; sed 's,@SYSCONFDIR@," >$d/sysconfdir 48 | which osh | sed 's,.*,strings &,' | osh |\ 49 | sed -n 's,\(.*\)/osh.login,\1,p' >$d/sysconfdir_path 50 | <$d/sysconfdir_path tr -d '\n' >>$d/sysconfdir 51 | echo ",' >$1 )" >>$d/sysconfdir 52 | osh - etc.osh.login etc.osh.oshrc etc.osh.logout ; goto EXECSHELL 53 | : Loop 54 | osh $d/sysconfdir $1 ; shift 55 | if $n = 0 exit 56 | goto Loop 57 | 58 | : EXECSHELL 59 | 60 | (\ 61 | echo -n "<$1 ( rm -f $1 ; sed 's,@EXECSHELL@," ;\ 62 | which osh | tr -d '\n' ; echo ",' >$1 )" ;\ 63 | ) >$d/execshell 64 | osh $d/execshell dot.osh.login 65 | : fallthrough 66 | 67 | : OSHDIR 68 | 69 | if ! { fd2 which oshdir >/dev/null } goto NotFound 70 | (\ 71 | echo -n "<$1 ( rm -f $1 ; sed 's,@SOURCE_OSHDIR@,source " ;\ 72 | which oshdir | tr -d '\n' ; echo " $$,' >$1 )" ;\ 73 | ) >$d/oshdir 74 | goto Done 75 | 76 | : NotFound 77 | 78 | (\ 79 | echo -n "<$1 ( rm -f $1 ; sed 's,@SOURCE_OSHDIR@," ;\ 80 | echo ": See http://v6shell.org/v6scripts/oshdir.osh .,' >$1 )" ;\ 81 | ) >$d/oshdir 82 | : fallthrough 83 | 84 | : Done - " Finish, clean up, and exit w/ zero status. " 85 | 86 | osh $d/oshdir dot.osh.login 87 | : fallthrough 88 | 89 | (echo Successful File Prep! From the:;echo;echo -n ' ';pwd;echo;\ 90 | echo ...;echo directory, please manually copy:;echo)|tee fileprep.log 91 | 92 | (osh - *osh*;echo;echo ...;echo after modifying each file to taste.)|\ 93 | tee -a fileprep.log;rm -rf $d;: zero status;exit 94 | : Loop1 95 | echo -n ' '$1' to ' 96 | head -1 <$1 | sed 's,^: \(.*\) - .*$,echo \1,' | osh ; shift 97 | if $n = 0 exit 98 | goto Loop1 99 | -------------------------------------------------------------------------------- /examples/LICENSE: -------------------------------------------------------------------------------- 1 | =================================================================== 2 | 3 | The files in this directory are hereby granted to the public domain 4 | by the author, Jeffrey Allen Neitzel . 5 | 6 | === 7 | 8 | Jeffrey Allen Neitzel 2010/02/28 9 | 10 | @(#)$Id: 285d0b26b1b37af68d6946c00659a5e3be9b3060 $ 11 | -------------------------------------------------------------------------------- /examples/README: -------------------------------------------------------------------------------- 1 | Welcome to osh rc files! 2 | 3 | The Sixth Edition Thompson shell did not read/execute rc (init and 4 | logout) files. The fact that osh does so is simply one of its 5 | enhancements. This makes osh a much better login shell than it 6 | might be otherwise, as the ability to execute rc files can make 7 | things much easier for the user. An rc file is simply a regular 8 | shell script, aka command file, that the shell treats specially. 9 | 10 | For full details about how osh handles rc files, please refer to 11 | the "Startup and shutdown" subsection of osh(1) manual page @ 12 | http://v6shell.org/man/osh.1.html#StartupAndShutdown . 13 | 14 | This collection of osh(1) rc files may be studied as is, used as 15 | templates, modified, and/or installed for personal or general use. 16 | 17 | ------- 18 | INSTALL: 19 | 1) Run FILEPREP script to prepare rc files for installation. 20 | 21 | usage: osh FILEPREP /path/to/nonexistent_directory 22 | 23 | 2) cd or chdir to specified directory. 24 | 25 | 3) Modify *osh* files to taste (e.g., change PATH, etc). 26 | 27 | 4) Copy *osh* files to destinations noted in fileprep.log . 28 | 29 | ... 30 | Depending on system configuration, you may need to become superuser 31 | in order to successfully install system-wide rc files. 32 | 33 | ------- 34 | I install and use variations of these files on several different 35 | systems. This includes GNU/Linux, Mac OS X, NetBSD, OpenBSD, and 36 | OpenSolaris. On GNU/Linux systems, you may wish to refer to the 37 | manual pages for the utilities invoked in these files as there might 38 | be incompatibilities that I have not encountered. For example, 39 | this is true for stty(1). 40 | 41 | If you have any comments or questions about this software, I encourage 42 | you to contact me via email. Thanks & Enjoy! 43 | 44 | Jeffrey Allen Neitzel 45 | 46 | http://v6shell.org/rc_files 2010/02/28 47 | 48 | @(#)$Id: 8be7e8c21f63c6c706785f89c56c6af0c1532fc5 $ 49 | -------------------------------------------------------------------------------- /examples/dot.osh.login: -------------------------------------------------------------------------------- 1 | : $h/.osh.login - " Modify to taste. " 2 | : 3 | : " @(#)$Id: d62260aaf502dba450c3989d2cc7c42867357495 $ " 4 | : 5 | : " The author of this file, J.A. Neitzel , " 6 | : " hereby grants it to the public domain. " 7 | : 8 | : " From: http://v6shell.org/rc_files " 9 | : 10 | 11 | : fd2 -e echo "debug: Executing `"$h/.osh.login"' now..." 12 | 13 | if X$u != Xroot goto continue 14 | 15 | : 16 | : " Give the superuser a different default PATH. " 17 | : 18 | setenv PATH /opt/local/bin:/usr/local/bin 19 | setenv PATH $p:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11/bin 20 | : fallthrough 21 | 22 | : continue - " Okay, continue as normal. " 23 | 24 | setenv MANPATH \ 25 | /opt/local/share/man:/usr/local/man:/usr/share/man:/usr/X11/share/man 26 | setenv PATH /usr/local/v6bin:$h/v6bin:$p:/usr/games 27 | setenv COMMAND_MODE unix2003 28 | setenv EXECSHELL @EXECSHELL@ 29 | setenv EDITOR '/bin/ed -p:' 30 | setenv VISUAL /opt/local/bin/vim 31 | setenv PAGER 'less -is' 32 | setenv LESS -M 33 | setenv TZ UTC 34 | 35 | : 36 | : " Make getopt(3) in the fd2 utility behave the same on " 37 | : " GNU/Linux systems as it does on *BSD & other systems. " 38 | : 39 | setenv POSIXLY_CORRECT 40 | 41 | if $n = 1 -a X$1 = Xsh6 goto sh6 42 | @SOURCE_OSHDIR@ 43 | : sh6 44 | 45 | : " Print a message or two at login time. " 46 | echo ; date '+%A, %Y-%m-%d, %T %Z' ; echo 47 | if -x /usr/games/fortune /usr/games/fortune -s 48 | : zero status 49 | -------------------------------------------------------------------------------- /examples/dot.osh.logout: -------------------------------------------------------------------------------- 1 | : $h/.osh.logout - " Modify to taste. " 2 | : 3 | : " @(#)$Id: 44e7be4dd0b869c5ffd9f3bd0537675f46cd562f $ " 4 | : 5 | : " The author of this file, J.A. Neitzel , " 6 | : " hereby grants it to the public domain. " 7 | : 8 | : " From: http://v6shell.org/rc_files " 9 | : 10 | 11 | sigign + 2 3 12 | 13 | : fd2 -e echo "debug: Executing `"$h/.osh.logout"' now..." 14 | 15 | : 16 | : " Check for OSHDIR ($d), and remove it before logout. " 17 | : 18 | if X$d = X -o ! -d $d'' goto Logout 19 | 20 | chdir ; rm -r $d ; chdir - 21 | : fallthrough 22 | 23 | : Logout - " Log out or start new login shell according to user response. " 24 | 25 | chdir ; fd2 -e echo 26 | fd2 -e echo -n 'Do you want to log out now? ([y]/n) ' 27 | head -1 <- | tr -d ' \t' >osh-logout-$$ 28 | 29 | if ! -s osh-logout-$$ -o \ 30 | { egrep '^$|^[Yy][A-Za-z]*$' osh-logout-$$ >/dev/null } \ 31 | if { rm -f osh-logout-$$ } exit 32 | if ! { which osh >/dev/null } \ 33 | if { rm -f osh-logout-$$ } if { exit } sleep 5 34 | 35 | rm -f osh-logout-$$ ; unsetenv TTY ; chdir - 36 | clear <- ; sigign - 2 3 ; exec osh -login <- 37 | -------------------------------------------------------------------------------- /examples/dot.oshrc: -------------------------------------------------------------------------------- 1 | : $h/.oshrc - " Modify to taste. " 2 | : 3 | : " @(#)$Id: 0febb63ee375d9e2e5e3f580ba9d0b55bb1e0dfb $ " 4 | : 5 | : " The author of this file, J.A. Neitzel , " 6 | : " hereby grants it to the public domain. " 7 | : 8 | : " From: http://v6shell.org/rc_files " 9 | : 10 | 11 | : fd2 -e echo "debug: Executing `"$h/.oshrc"' now..." 12 | 13 | printenv TERM >/dev/null 14 | if $s = 0 goto TERM_OK 15 | 16 | setenv TERM vt100 17 | : fallthrough 18 | 19 | : TERM_OK 20 | if ! \( $n = 1 -a X$1 = Xsh6 \) goto TTY_CHECK 21 | 22 | unsetenv TTY 23 | : fallthrough 24 | 25 | : TTY_CHECK 26 | printenv TTY | grep \^$t\$ >/dev/null 27 | if $s = 0 goto continue 28 | 29 | setenv TTY $t 30 | 31 | printenv TERM | grep '^rxvt$' >/dev/null 32 | if $s = 0 goto C 33 | 34 | : 35 | : " The terminal I normally use is rxvt-unicode (urxvt), " 36 | : " but I also use others on occasion. Normally, they're " 37 | : " UTF-8 capable, but that's not always true. " 38 | : 39 | setenv LC_ALL en_US.UTF-8 40 | setenv LESSCHARSET utf-8 41 | printf "%b" '\033]701;en_US.UTF-8\007' >/dev/tty 42 | goto Next 43 | 44 | : C - " Default to the C locale for rxvt. " 45 | 46 | setenv LC_ALL C 47 | : fallthrough 48 | 49 | : Next - " Set the window title for terminal emulators under X. " 50 | 51 | if $n = 1 -a X$1 = Xsh6 goto sh6 52 | xtitle ; goto stty 53 | : sh6 54 | sh6 -c xtitle 55 | : fallthrough 56 | 57 | : stty - " Set terminal options. " 58 | stty altwerase imaxbel -oxtabs <- 59 | stty status '^T' <- 60 | : fallthrough 61 | 62 | : continue - " Okay, continue as normal. " 63 | 64 | : 65 | : " Other initialization routines that the user wishes to execute " 66 | : " for each interactive shell can be placed here. " 67 | : 68 | 69 | if ! \( $n = 1 -a X$1 = Xsh6 \) goto osh 70 | if ! { which sh6 >/dev/null } goto shift 71 | : " Replace osh w/ sh6 . " ; exec sh6 <- 72 | : shift 73 | shift 74 | : osh 75 | -------------------------------------------------------------------------------- /examples/etc.osh.login: -------------------------------------------------------------------------------- 1 | : @SYSCONFDIR@/osh.login - " Modify to taste. " 2 | : 3 | : " @(#)$Id: ec8e95aa21e57c9fc6c1252dcdea5c97be3a7dd7 $ " 4 | : 5 | : " The author of this file, J.A. Neitzel , " 6 | : " hereby grants it to the public domain. " 7 | : 8 | : " From: http://v6shell.org/rc_files " 9 | : 10 | 11 | sigign + 1 2 3 13 14 15 ; : " Ignore HUP, INT, QUIT, PIPE, ALRM, and TERM. " 12 | sigign + 18 21 22 ; : " Ignore job-control signals: TSTP, TTIN, TTOU " 13 | 14 | : 15 | : " Set a default PATH and umask for all users. " 16 | : 17 | setenv PATH /opt/local/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11/bin 18 | umask 0022 19 | 20 | : fd2 -e echo "debug: Executing `@SYSCONFDIR@/osh.login' now..." 21 | 22 | setenv MAIL /var/mail/$u 23 | setenv CTTY $t 24 | stty status '^T' <- 25 | 26 | if X$h = X -o ! -d $h'' goto finish 27 | if ! { mkdir $h/.osh.setenv.$$ } goto finish 28 | 29 | : 30 | : " Use the output from `uname -n' to `setenv HOST value'. " 31 | : " Notice that doing so requires using a temporary file. " 32 | : 33 | uname -n | sed 's,\([^.]*\).*,setenv HOST \1,' >$h/.osh.setenv.$$/HOST 34 | source $h/.osh.setenv.$$/HOST 35 | rm -r $h/.osh.setenv.$$ 36 | : fallthrough 37 | 38 | : finish 39 | 40 | sigign - 1 2 3 13 14 15 ; : " Reset the ignored, non-job-control signals. " 41 | -------------------------------------------------------------------------------- /examples/etc.osh.logout: -------------------------------------------------------------------------------- 1 | : @SYSCONFDIR@/osh.logout - " Modify to taste. " 2 | : 3 | : " @(#)$Id: 443ba062ba42f5125f326de6e69717136df77834 $ " 4 | : 5 | : " The author of this file, J.A. Neitzel , " 6 | : " hereby grants it to the public domain. " 7 | : 8 | : " From: http://v6shell.org/rc_files " 9 | : 10 | 11 | sigign + 1 2 3 13 14 15 ; : " Ignore HUP, INT, QUIT, PIPE, ALRM, and TERM. " 12 | sigign + 18 21 22 ; : " Ignore job-control signals: TSTP, TTIN, TTOU " 13 | 14 | : fd2 -e echo "debug: Executing `@SYSCONFDIR@/osh.logout' now..." 15 | 16 | : Insert useful logout routines here. 17 | 18 | sigign - 1 2 3 13 14 15 ; : " Reset the ignored, non-job-control signals. " 19 | -------------------------------------------------------------------------------- /examples/etc.osh.oshrc: -------------------------------------------------------------------------------- 1 | : @SYSCONFDIR@/osh.oshrc - " Modify to taste. " 2 | : 3 | : " @(#)$Id: fbc6abb7ac0b85cd725d8b661d5ab791621f5ee2 $ " 4 | : 5 | : " The author of this file, J.A. Neitzel , " 6 | : " hereby grants it to the public domain. " 7 | : 8 | : " From: http://v6shell.org/rc_files " 9 | : 10 | 11 | sigign + 1 2 3 13 14 15 ; : " Ignore HUP, INT, QUIT, PIPE, ALRM, and TERM. " 12 | sigign + 18 21 22 ; : " Ignore job-control signals: TSTP, TTIN, TTOU " 13 | 14 | : fd2 -e echo "debug: Executing `@SYSCONFDIR@/osh.oshrc' now..." 15 | 16 | : Insert useful initialization routines here. 17 | 18 | sigign - 1 2 3 13 14 15 ; : " Reset the ignored, non-job-control signals. " 19 | -------------------------------------------------------------------------------- /fd2.1: -------------------------------------------------------------------------------- 1 | .\" 2 | .\" Copyright (c) 2005-2011 3 | .\" Jeffrey Allen Neitzel . 4 | .\" All rights reserved. 5 | .\" 6 | .\" Redistribution and use in source and binary forms, with or without 7 | .\" modification, are permitted provided that the following conditions 8 | .\" are met: 9 | .\" 1. Redistributions of source code must retain the above copyright 10 | .\" notice, this list of conditions and the following disclaimer. 11 | .\" 2. Redistributions in binary form must reproduce the above copyright 12 | .\" notice, this list of conditions and the following disclaimer in the 13 | .\" documentation and/or other materials provided with the distribution. 14 | .\" 15 | .\" THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 16 | .\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | .\" DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 19 | .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | .\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | .\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 | .\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | .\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 24 | .\" USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | .\" 26 | .\" @(#)$Id: 47bc042b4ff8e1193f87f27e321d28e9c723bdbc $ 27 | .\" 28 | .TH FD2 1 "@OSH_DATE@" "@OSH_VERSION@" "General Commands" 29 | .SH NAME 30 | fd2 \- redirect from/to file descriptor 2 31 | .SH SYNOPSIS 32 | .B fd2 33 | [\fB\-e\fR] [\fB\-f\fR \fIfile\fR] [\fB\-\-\fR] \fIcommand\fR [\fIarg ...\fR] 34 | .SH DESCRIPTION 35 | Since the Sixth Edition UNIX shell provides 36 | no way to redirect the diagnostic output, 37 | .I fd2 38 | makes this possible by executing the specified 39 | .I command 40 | with the given arguments 41 | and redirecting file descriptor 2 (standard error) 42 | to file descriptor 1 (standard output) by default. 43 | .PP 44 | The options are as follows: 45 | .TP 46 | .B \-e 47 | Causes all conventional output from 48 | .I command 49 | to be redirected to the standard error 50 | as diagnostic output. 51 | .TP 52 | .BI \-f \ file 53 | Causes all diagnostic output from 54 | .I command 55 | to be redirected to \fIfile\fR, 56 | which is created if it does not exist. 57 | If it already exists, 58 | all diagnostic output is appended 59 | to the end of \fIfile\fR. 60 | .TP 61 | .B \-\- 62 | Causes 63 | .I fd2 64 | to stop further option processing, 65 | forcing it to treat all following arguments 66 | as \fIcommand\fR [\fIarg ...\fR] . 67 | .SH "EXIT STATUS" 68 | If 69 | .I fd2 70 | detects an error, 71 | it prints an appropriate diagnostic 72 | and exits with a non-zero status. 73 | Otherwise, 74 | the exit status is that 75 | of the executed command. 76 | .SH ENVIRONMENT 77 | .TP 78 | .B EXECSHELL 79 | If set to a non-empty string, 80 | the value of this variable is taken as the 81 | path name of the shell which is invoked to 82 | execute the specified command when it does not 83 | begin with the proper magic number 84 | or a `#!shell' sequence. 85 | .TP 86 | .B PATH 87 | If set to a non-empty string, 88 | the value of this variable is taken as the 89 | sequence of directories which is used to 90 | search for the specified command. 91 | .SH EXAMPLES 92 | The examples below which refer to `/tmp/$$' assume 93 | that this directory exists and is writable by the user. 94 | The following command line: 95 | .PP 96 | .RS 6 97 | fd2 \-e echo progname: Error message 98 | .RE 99 | .PP 100 | causes all conventional output from 101 | .I echo 102 | to be redirected to the standard error 103 | as diagnostic output. 104 | The following command line: 105 | .PP 106 | .RS 6 107 | fd2 make foo >/tmp/$$/foo.outerr 108 | .RE 109 | .PP 110 | causes all conventional and diagnostic output from 111 | .I make 112 | to be redirected to the file `/tmp/$$/foo.outerr', 113 | which is first created by the shell. 114 | In contrast: 115 | .PP 116 | .RS 6 117 | fd2 \-f /tmp/$$/foo.err make foo >/tmp/$$/foo.out 118 | .RE 119 | .PP 120 | causes all conventional output to be redirected 121 | to the file `/tmp/$$/foo.out', 122 | which is created by the shell. 123 | All diagnostic output is redirected 124 | to the file `/tmp/$$/foo.err', 125 | which is created by 126 | .I fd2 127 | if it does not already exist. 128 | .SH "SEE ALSO" 129 | osh(1), 130 | sh6(1) 131 | .PP 132 | Osh home page: 133 | http://v6shell.org/ 134 | .SH AUTHOR 135 | This implementation of 136 | .I fd2 137 | is written by Jeffrey Allen Neitzel. 138 | .SH LICENSE 139 | See either the LICENSE file which is distributed with 140 | .I osh 141 | or 142 | http://v6shell.org/license/ 143 | for full details. 144 | .SH COPYRIGHT 145 | .nf 146 | Copyright (c) 2005-2011 147 | Jeffrey Allen Neitzel. All rights reserved. 148 | 149 | Copyright (c) 1985, 1989, 1991, 1993 150 | The Regents of the University of California. All rights reserved. 151 | .fi 152 | -------------------------------------------------------------------------------- /fd2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * fd2.c - redirect from/to file descriptor 2 3 | */ 4 | /*- 5 | * Copyright (c) 2005-2011 6 | * Jeffrey Allen Neitzel . 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 19 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 27 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | * @(#)$Id: 9d40c3ff203d9770a45ee4d9f390a133a46f3668 $ 30 | */ 31 | 32 | #include "defs.h" 33 | #include "err.h" 34 | #include "pexec.h" 35 | 36 | static bool fd_isopen(int); 37 | /*@noreturn@*/ 38 | static void usage(void); 39 | 40 | /* 41 | * NAME 42 | * fd2 - redirect from/to file descriptor 2 43 | * 44 | * SYNOPSIS 45 | * fd2 [-e] [-f file] [--] command [arg ...] 46 | * 47 | * DESCRIPTION 48 | * See the fd2(1) manual page for full details. 49 | */ 50 | int 51 | main(int argc, char **argv) 52 | { 53 | bool eopt; 54 | int efd, fd, nfd, ofd, opt; 55 | char *file; 56 | 57 | setmyerrexit(&ut_errexit); 58 | setmyname(argv[0]); 59 | setmypid(getpid()); 60 | 61 | /* 62 | * Set-ID execution is not supported. 63 | */ 64 | if (geteuid() != getuid() || getegid() != getgid()) 65 | err(FC_ERR, FMT2S, getmyname(), ERR_SETID); 66 | 67 | /* 68 | * File descriptors 0, 1, and 2 must be open. 69 | */ 70 | for (fd = 0; fd < 3; fd++) 71 | if (!fd_isopen(fd)) 72 | err(FC_ERR, "%s: %u: %s\n", 73 | getmyname(), (unsigned)fd, strerror(errno)); 74 | 75 | ofd = FD1, efd = FD2; 76 | eopt = false, file = NULL; 77 | while ((opt = getopt(argc, argv, ":ef:")) != -1) 78 | switch (opt) { 79 | case 'e': 80 | eopt = true; 81 | break; 82 | case 'f': 83 | file = optarg; 84 | break; 85 | default: 86 | usage(); 87 | } 88 | argc -= optind; 89 | argv += optind; 90 | if (argc < 1) 91 | usage(); 92 | 93 | if (file != NULL) { 94 | if ((nfd = open(file, O_WRONLY|O_APPEND|O_CREAT, 0666)) == -1) 95 | err(FC_ERR, FMT3S, getmyname(), file, ERR_CREATE); 96 | if (dup2(nfd, efd) == -1) 97 | err(FC_ERR, FMT2S, getmyname(), strerror(errno)); 98 | if (eopt && dup2(efd, ofd) == -1) 99 | err(FC_ERR, FMT2S, getmyname(), strerror(errno)); 100 | (void)close(nfd); 101 | } else { 102 | if (eopt) 103 | ofd = FD2, efd = FD1; 104 | if (dup2(ofd, efd) == -1) 105 | err(FC_ERR, FMT2S, getmyname(), strerror(errno)); 106 | } 107 | 108 | /* 109 | * Try to execute the specified command. 110 | */ 111 | (void)err_pexec(argv[0], argv); 112 | /*NOTREACHED*/ 113 | return FC_ERR; 114 | } 115 | 116 | static bool 117 | fd_isopen(int fd) 118 | { 119 | struct stat sb; 120 | 121 | return fstat(fd, &sb) == 0; 122 | } 123 | 124 | static void 125 | usage(void) 126 | { 127 | 128 | err(FC_ERR, FD2_USAGE, getmyname()); 129 | } 130 | -------------------------------------------------------------------------------- /glob6.1: -------------------------------------------------------------------------------- 1 | .\" 2 | .\" Copyright (c) 2006-2011 3 | .\" Jeffrey Allen Neitzel . 4 | .\" All rights reserved. 5 | .\" 6 | .\" Redistribution and use in source and binary forms, with or without 7 | .\" modification, are permitted provided that the following conditions 8 | .\" are met: 9 | .\" 1. Redistributions of source code must retain the above copyright 10 | .\" notice, this list of conditions and the following disclaimer. 11 | .\" 2. Redistributions in binary form must reproduce the above copyright 12 | .\" notice, this list of conditions and the following disclaimer in the 13 | .\" documentation and/or other materials provided with the distribution. 14 | .\" 15 | .\" THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 16 | .\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | .\" DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 19 | .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | .\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | .\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 | .\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | .\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 24 | .\" USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | .\" 26 | .\" @(#)$Id: 41d2be91029c76378d48da8294a3e02976d67490 $ 27 | .\" 28 | .\" Derived from: 29 | .\" - Sixth Edition UNIX /usr/man/man1/sh.1 30 | .\" - Sixth Edition UNIX /usr/man/man8/glob.8 31 | .\" 32 | .\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved. 33 | .\" 34 | .\" Redistribution and use in source and binary forms, with or without 35 | .\" modification, are permitted provided that the following conditions 36 | .\" are met: 37 | .\" 1. Redistributions of source code and documentation must retain the above 38 | .\" copyright notice, this list of conditions and the following disclaimer. 39 | .\" 2. Redistributions in binary form must reproduce the above copyright 40 | .\" notice, this list of conditions and the following disclaimer in the 41 | .\" documentation and/or other materials provided with the distribution. 42 | .\" 3. All advertising materials mentioning features or use of this software 43 | .\" must display the following acknowledgement: 44 | .\" This product includes software developed or owned by Caldera 45 | .\" International, Inc. 46 | .\" 4. Neither the name of Caldera International, Inc. nor the names of other 47 | .\" contributors may be used to endorse or promote products derived from 48 | .\" this software without specific prior written permission. 49 | .\" 50 | .\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 51 | .\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 52 | .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 53 | .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 54 | .\" IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 55 | .\" INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 56 | .\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 57 | .\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 | .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 59 | .\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 60 | .\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 61 | .\" POSSIBILITY OF SUCH DAMAGE. 62 | .\" 63 | .TH GLOB6 1 "@OSH_DATE@" "@OSH_VERSION@" "General Commands" 64 | .SH NAME 65 | glob6 \- global command (file name generation) 66 | .SH SYNOPSIS 67 | .B glob6 68 | \fIcommand\fR [\fIarg ...\fR] 69 | .SH DESCRIPTION 70 | .I Glob6 71 | is a port of the global command from Sixth Edition UNIX. 72 | It is passed an argument list by 73 | .IR sh6 (1) 74 | which contains one or more unquoted 75 | .I "pattern characters" 76 | (`*', `?', `[') 77 | and performs the actions described below 78 | on behalf of the shell. 79 | .PP 80 | .I Glob6 81 | attempts to generate file-name arguments which match 82 | the given pattern arguments. 83 | The name of the specified 84 | .I command 85 | may also be given as a pattern. 86 | The meaning of each pattern character is as follows: 87 | .IP o 4 88 | The `*' character in a pattern matches any string of 89 | characters in a file name (including the null string). 90 | .IP o 91 | The `?' character in a pattern matches any single character 92 | in a file name. 93 | .IP o 94 | The `[...]' brackets in a pattern specifies a class of characters 95 | which matches any single file-name character in the class. 96 | Within the brackets, 97 | each character is taken to be a member of the class. 98 | A pair of characters separated by an unquoted `\-' specifies 99 | the class as a range which matches each character lexically 100 | between the first and second member of the pair, inclusive. 101 | A `\-' matches itself when quoted or when first or last 102 | in the class. 103 | .PP 104 | Any other character in a pattern matches itself in a file name. 105 | .PP 106 | Notice that the `.' character at the beginning of a file name, 107 | or immediately following a `/', 108 | is always special in that it must be matched explicitly. 109 | The same is true of the `/' character itself. 110 | .PP 111 | If the pattern contains no `/' characters, 112 | the current directory is always used. 113 | Otherwise, 114 | the specified directory is the one obtained by taking the pattern 115 | up to the last `/' before the first unquoted `*', `?', or `['. 116 | The matching process matches the remainder of the pattern 117 | after this `/' against the files in the specified directory. 118 | .PP 119 | If the argument contains no unquoted pattern characters, 120 | .I glob6 121 | uses it as is. 122 | Otherwise, 123 | .I glob6 124 | searches for file names in the current (or specified) directory 125 | which match the pattern. 126 | It then sorts them in ascending ASCII order, 127 | and the new sequence of arguments replaces the given pattern. 128 | The same process is carried out for each of the given arguments; 129 | the resulting lists are 130 | .I not 131 | merged. 132 | Finally, 133 | .I glob6 134 | attempts to execute the command 135 | with the resulting argument list. 136 | .SH "EXIT STATUS" 137 | If 138 | .I glob6 139 | detects an error, 140 | it prints an appropriate diagnostic 141 | and exits with a non-zero status. 142 | Otherwise, 143 | the exit status is that 144 | of the executed command. 145 | .SH ENVIRONMENT 146 | Notice that the concept of `user environment' 147 | was not defined in Sixth Edition UNIX. 148 | Thus, 149 | use of the following environment variables 150 | by this port of the global command 151 | is an enhancement: 152 | .TP 153 | .B EXECSHELL 154 | If set to a non-empty string, 155 | the value of this variable is taken as the 156 | path name of the shell which is invoked to 157 | execute the specified command when it does not 158 | begin with the proper magic number 159 | or a `#!shell' sequence. 160 | .TP 161 | .B PATH 162 | If set to a non-empty string, 163 | the value of this variable is taken as the 164 | sequence of directories which is used to 165 | search for the specified command. 166 | Notice that the 167 | global command from Sixth Edition UNIX 168 | always used the equivalent of `.:/bin:/usr/bin', 169 | not PATH. 170 | .SH "SEE ALSO" 171 | sh6(1) 172 | .PP 173 | Osh home page: 174 | http://v6shell.org/ 175 | .SH HISTORY 176 | A 177 | .I glob 178 | command 179 | appeared as 180 | .I /etc/glob 181 | in First Edition UNIX. 182 | .SH LICENSE 183 | See either the LICENSE file which is distributed with 184 | .I osh 185 | or 186 | http://v6shell.org/license/ 187 | for full details. 188 | .SH COPYRIGHT 189 | .nf 190 | Copyright (c) 2006-2011 191 | Jeffrey Allen Neitzel. All rights reserved. 192 | 193 | Copyright (c) 2001-2002 194 | Caldera International Inc. All rights reserved. 195 | 196 | Copyright (c) 1985, 1989, 1991, 1993 197 | The Regents of the University of California. All rights reserved. 198 | .fi 199 | -------------------------------------------------------------------------------- /glob6.c: -------------------------------------------------------------------------------- 1 | /* 2 | * glob6.c - a port of the Sixth Edition (V6) UNIX global command 3 | */ 4 | /*- 5 | * Copyright (c) 2004-2011 6 | * Jeffrey Allen Neitzel . 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 19 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 27 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | * @(#)$Id: 6b27f006c7600de545a5f1c55ae0917d90816a14 $ 30 | */ 31 | /* 32 | * Derived from: Sixth Edition UNIX /usr/source/s1/glob.c 33 | */ 34 | /*- 35 | * Copyright (C) Caldera International Inc. 2001-2002. All rights reserved. 36 | * 37 | * Redistribution and use in source and binary forms, with or without 38 | * modification, are permitted provided that the following conditions 39 | * are met: 40 | * 1. Redistributions of source code and documentation must retain the above 41 | * copyright notice, this list of conditions and the following disclaimer. 42 | * 2. Redistributions in binary form must reproduce the above copyright 43 | * notice, this list of conditions and the following disclaimer in the 44 | * documentation and/or other materials provided with the distribution. 45 | * 3. All advertising materials mentioning features or use of this software 46 | * must display the following acknowledgement: 47 | * This product includes software developed or owned by Caldera 48 | * International, Inc. 49 | * 4. Neither the name of Caldera International, Inc. nor the names of other 50 | * contributors may be used to endorse or promote products derived from 51 | * this software without specific prior written permission. 52 | * 53 | * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 54 | * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 55 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 56 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 57 | * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 58 | * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 59 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 60 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 62 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 63 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 64 | * POSSIBILITY OF SUCH DAMAGE. 65 | */ 66 | 67 | #include "defs.h" 68 | #include "err.h" 69 | #include "pexec.h" 70 | 71 | static const char **gavp; /* points to current gav position */ 72 | static const char **gave; /* points to current gav end */ 73 | static size_t gavtot; /* total bytes used for all arguments */ 74 | 75 | static const char **gnew(/*@only@*/ const char **); 76 | static char *gcat(const char *, const char *); 77 | static const char **glob1(/*@only@*/ const char **, char *, int *); 78 | static bool glob2(const UChar *, const UChar *); 79 | static void gsort(const char **); 80 | /*@null@*/ 81 | static DIR *gopendir(const char *); 82 | 83 | /* 84 | * NAME 85 | * glob6 - global command (file name generation) 86 | * 87 | * SYNOPSIS 88 | * glob6 command [arg ...] 89 | * 90 | * DESCRIPTION 91 | * See glob6(1) the manual page for full details. 92 | */ 93 | int 94 | main(int argc, char **argv) 95 | { 96 | const char **gav; /* points to generated argument vector */ 97 | int pmc = 0; /* pattern-match count */ 98 | 99 | setmyerrexit(&ut_errexit); 100 | setmyname(argv[0]); 101 | setmypid(getpid()); 102 | 103 | /* 104 | * Set-ID execution is not supported. 105 | */ 106 | if (geteuid() != getuid() || getegid() != getgid()) 107 | err(SH_ERR, FMT1S, ERR_SETID); 108 | 109 | if (argc < 2) 110 | err(SH_ERR, FMT1S, ERR_GARGCOUNT); 111 | 112 | if ((gav = malloc(GAVNEW * sizeof(char *))) == NULL) 113 | err(SH_ERR, FMT1S, ERR_NOMEM); 114 | 115 | *gav = NULL, gavp = gav; 116 | gave = &gav[GAVNEW - 1]; 117 | while (*++argv != NULL) 118 | gav = glob1(gav, *argv, &pmc); 119 | gavp = NULL; 120 | 121 | if (pmc == 0) 122 | err(SH_ERR, FMT1S, ERR_NOMATCH); 123 | 124 | (void)err_pexec(gav[0], (char *const *)gav); 125 | /*NOTREACHED*/ 126 | return SH_ERR; 127 | } 128 | 129 | static const char ** 130 | gnew(const char **gav) 131 | { 132 | size_t siz; 133 | ptrdiff_t gidx; 134 | const char **nav; 135 | static unsigned mult = 1; 136 | 137 | if (gavp == gave) { 138 | mult *= GAVMULT; 139 | gidx = (ptrdiff_t)(gavp - gav); 140 | siz = (size_t)((gidx + (GAVNEW * mult)) * sizeof(char *)); 141 | if ((nav = realloc(gav, siz)) == NULL) 142 | err(SH_ERR, FMT1S, ERR_NOMEM); 143 | gav = nav; 144 | gavp = gav + gidx; 145 | gave = &gav[gidx + (GAVNEW * mult) - 1]; 146 | } 147 | return gav; 148 | } 149 | 150 | static char * 151 | gcat(const char *src1, const char *src2) 152 | { 153 | size_t siz; 154 | char *b, buf[PATHMAX], c, *dst; 155 | const char *s; 156 | 157 | *buf = EOS, b = buf, s = src1; 158 | while ((c = *s++) != EOS) { 159 | if (b >= &buf[PATHMAX - 1]) 160 | err(SH_ERR, FMT1S, strerror(ENAMETOOLONG)); 161 | if ((c &= ASCII) == EOS) { 162 | *b++ = SLASH; 163 | break; 164 | } 165 | *b++ = c; 166 | } 167 | 168 | s = src2; 169 | do { 170 | if (b >= &buf[PATHMAX]) 171 | err(SH_ERR, FMT1S, strerror(ENAMETOOLONG)); 172 | *b++ = c = *s++; 173 | } while (c != EOS); 174 | 175 | siz = b - buf; 176 | gavtot += siz; 177 | if (gavtot > GAVMAX) 178 | err(SH_ERR, FMT1S, ERR_E2BIG); 179 | if ((dst = malloc(siz)) == NULL) { 180 | err(SH_ERR, FMT1S, ERR_NOMEM); 181 | /*NOTREACHED*/ 182 | } 183 | 184 | (void)memcpy(dst, buf, siz); 185 | return dst; 186 | } 187 | 188 | static const char ** 189 | glob1(const char **gav, char *as, int *pmc) 190 | { 191 | DIR *dirp; 192 | struct dirent *entry; 193 | ptrdiff_t gidx; 194 | const char *ds; 195 | char *ps; 196 | 197 | ds = ps = as; 198 | while (*ps != ASTERISK && *ps != QUESTION && *ps != LBRACKET) 199 | if (*ps++ == EOS) { 200 | gav = gnew(gav); 201 | *gavp++ = gcat(as, ""); 202 | *gavp = NULL; 203 | return gav; 204 | } 205 | if (strlen(as) >= PATHMAX) 206 | err(SH_ERR, FMT1S, ERR_PATTOOLONG); 207 | for (;;) { 208 | if (ps == ds) { 209 | ds = ""; 210 | break; 211 | } 212 | if ((*--ps & ASCII) == SLASH) { 213 | *ps = EOS; 214 | if (ds == ps) 215 | ds = "/"; 216 | *ps++ = (char)QUOTE; 217 | break; 218 | } 219 | } 220 | if ((dirp = gopendir(*ds != EOS ? ds : ".")) == NULL) { 221 | err(SH_ERR, FMT1S, ERR_NODIR); 222 | /*NOTREACHED*/ 223 | } 224 | gidx = (ptrdiff_t)(gavp - gav); 225 | while ((entry = readdir(dirp)) != NULL) { 226 | if (entry->d_name[0] == DOT && (*ps & ASCII) != DOT) 227 | continue; 228 | if (glob2(UCPTR(entry->d_name), UCPTR(ps))) { 229 | gav = gnew(gav); 230 | *gavp++ = gcat(ds, entry->d_name); 231 | (*pmc)++; 232 | } 233 | } 234 | (void)closedir(dirp); 235 | gsort(gav + gidx); 236 | *gavp = NULL; 237 | return gav; 238 | } 239 | 240 | static bool 241 | glob2(const UChar *ename, const UChar *pattern) 242 | { 243 | int cok, rok; /* `[...]' - cok (class), rok (range) */ 244 | UChar c, ec, pc; 245 | const UChar *e, *n, *p; 246 | 247 | e = ename; 248 | p = pattern; 249 | if ((ec = *e++) != EOS) 250 | if ((ec &= ASCII) == EOS) 251 | ec = (UChar)QUOTE; 252 | 253 | switch (pc = *p++) { 254 | case EOS: 255 | return ec == EOS; 256 | 257 | case ASTERISK: 258 | /* 259 | * Ignore all but the last `*' in a group of consecutive 260 | * `*' characters to avoid unnecessary glob2() recursion. 261 | */ 262 | while (*p++ == ASTERISK) 263 | ; /* nothing */ 264 | if (*--p == EOS) 265 | return true; 266 | e--; 267 | while (*e != EOS) 268 | if (glob2(e++, p)) 269 | return true; 270 | break; 271 | 272 | case QUESTION: 273 | if (ec != EOS) 274 | return glob2(e, p); 275 | break; 276 | 277 | case LBRACKET: 278 | if (*p == EOS) 279 | break; 280 | for (c = UCHAR(EOS), cok = rok = 0, n = p + 1; ; ) { 281 | pc = *p++; 282 | if (pc == RBRACKET && p > n) { 283 | if (cok > 0 || rok > 0) 284 | return glob2(e, p); 285 | break; 286 | } 287 | if (*p == EOS) 288 | break; 289 | if (pc == HYPHEN && c != EOS && *p != RBRACKET) { 290 | pc = *p++ & ASCII; 291 | if (*p == EOS) 292 | break; 293 | if (c <= ec && ec <= pc) 294 | rok++; 295 | else if (c == ec) 296 | cok--; 297 | c = UCHAR(EOS); 298 | } else { 299 | c = pc & ASCII; 300 | if (ec == c) 301 | cok++; 302 | } 303 | } 304 | break; 305 | 306 | default: 307 | if ((pc & ASCII) == ec) 308 | return glob2(e, p); 309 | } 310 | return false; 311 | } 312 | 313 | static void 314 | gsort(const char **ogavp) 315 | { 316 | const char **p1, **p2, *sap; 317 | 318 | p1 = ogavp; 319 | while (gavp - p1 > 1) { 320 | p2 = p1; 321 | while (++p2 < gavp) 322 | if (strcmp(*p1, *p2) > 0) { 323 | sap = *p1; 324 | *p1 = *p2; 325 | *p2 = sap; 326 | } 327 | p1++; 328 | } 329 | } 330 | 331 | static DIR * 332 | gopendir(const char *dname) 333 | { 334 | char *b, buf[PATHMAX]; 335 | const char *d; 336 | 337 | for (*buf = EOS, b = buf, d = dname; b < &buf[PATHMAX]; b++, d++) 338 | if ((*b = (*d & ASCII)) == EOS) 339 | break; 340 | return (b >= &buf[PATHMAX]) ? NULL : opendir(buf); 341 | } 342 | -------------------------------------------------------------------------------- /goto.1: -------------------------------------------------------------------------------- 1 | .\" 2 | .\" Copyright (c) 2004-2011 3 | .\" Jeffrey Allen Neitzel . 4 | .\" All rights reserved. 5 | .\" 6 | .\" Redistribution and use in source and binary forms, with or without 7 | .\" modification, are permitted provided that the following conditions 8 | .\" are met: 9 | .\" 1. Redistributions of source code must retain the above copyright 10 | .\" notice, this list of conditions and the following disclaimer. 11 | .\" 2. Redistributions in binary form must reproduce the above copyright 12 | .\" notice, this list of conditions and the following disclaimer in the 13 | .\" documentation and/or other materials provided with the distribution. 14 | .\" 15 | .\" THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 16 | .\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | .\" DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 19 | .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | .\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | .\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 | .\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | .\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 24 | .\" USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | .\" 26 | .\" @(#)$Id: 68ddc4e7be63b887697a9e24e2c87c923c66a07f $ 27 | .\" 28 | .\" Derived from: Sixth Edition UNIX /usr/man/man1/goto.1 29 | .\" 30 | .\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved. 31 | .\" 32 | .\" Redistribution and use in source and binary forms, with or without 33 | .\" modification, are permitted provided that the following conditions 34 | .\" are met: 35 | .\" 1. Redistributions of source code and documentation must retain the above 36 | .\" copyright notice, this list of conditions and the following disclaimer. 37 | .\" 2. Redistributions in binary form must reproduce the above copyright 38 | .\" notice, this list of conditions and the following disclaimer in the 39 | .\" documentation and/or other materials provided with the distribution. 40 | .\" 3. All advertising materials mentioning features or use of this software 41 | .\" must display the following acknowledgement: 42 | .\" This product includes software developed or owned by Caldera 43 | .\" International, Inc. 44 | .\" 4. Neither the name of Caldera International, Inc. nor the names of other 45 | .\" contributors may be used to endorse or promote products derived from 46 | .\" this software without specific prior written permission. 47 | .\" 48 | .\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 49 | .\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 50 | .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 51 | .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 52 | .\" IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 53 | .\" INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 54 | .\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 55 | .\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 | .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 57 | .\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 58 | .\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 59 | .\" POSSIBILITY OF SUCH DAMAGE. 60 | .\" 61 | .TH GOTO 1 "@OSH_DATE@" "@OSH_VERSION@" "General Commands" 62 | .SH NAME 63 | goto \- transfer command 64 | .SH SYNOPSIS 65 | .BI 66 | .B goto 67 | \fIlabel\fR [\fI...\fR] 68 | .SH DESCRIPTION 69 | .I Goto 70 | is allowed only when the shell is taking 71 | commands from a seekable command file (see 72 | .IR lseek (2)). 73 | .PP 74 | The entire command file is searched for a line beginning 75 | with a \fB:\fR as the first non-blank character, 76 | followed by one or more blanks, 77 | and then the 78 | .IR label . 79 | If such a line is found, 80 | .I goto 81 | repositions the command-file offset to 82 | the line after the label and exits. 83 | This effectively causes the shell to transfer 84 | to the labelled line. 85 | .PP 86 | \fB:\fR is a special command which causes 87 | the shell to do nothing. 88 | .SH "EXIT STATUS" 89 | The 90 | .I goto 91 | command exits with one of the following values: 92 | .TP 93 | 0 94 | The label was found. 95 | .TP 96 | 1 97 | The label was not found. 98 | .TP 99 | 2 100 | An error was detected. 101 | .SH "SEE ALSO" 102 | if(1), 103 | osh(1), 104 | sh6(1) 105 | .PP 106 | Osh home page: 107 | http://v6shell.org/ 108 | .SH COMPATIBILITY 109 | The 110 | .I goto 111 | command from Sixth Edition UNIX 112 | requires \fB:\fR to be the first character 113 | on the labelled line. 114 | Otherwise, 115 | the label cannot be found. 116 | .PP 117 | This port differs in that \fB:\fR may be preceded by blanks. 118 | This allows labelled lines to be indented so that complex 119 | command files might be easier to read and understand. 120 | .SH HISTORY 121 | A 122 | .I goto 123 | command 124 | appeared as 125 | .I /bin/goto 126 | in Third Edition UNIX. 127 | .SH LICENSE 128 | See either the LICENSE file which is distributed with 129 | .I osh 130 | or 131 | http://v6shell.org/license/ 132 | for full details. 133 | .SH COPYRIGHT 134 | .nf 135 | Copyright (c) 2004-2011 136 | Jeffrey Allen Neitzel. All rights reserved. 137 | 138 | Copyright (c) 2001-2002 139 | Caldera International Inc. All rights reserved. 140 | .fi 141 | -------------------------------------------------------------------------------- /goto.c: -------------------------------------------------------------------------------- 1 | /* 2 | * goto.c - a port of the Sixth Edition (V6) UNIX transfer command 3 | */ 4 | /*- 5 | * Copyright (c) 2004-2011 6 | * Jeffrey Allen Neitzel . 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 19 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 27 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | * @(#)$Id: 3f87b0ec3ca5ec1f08977caecff78719523e8fd8 $ 30 | */ 31 | /* 32 | * Derived from: Sixth Edition UNIX /usr/source/s1/goto.c 33 | */ 34 | /*- 35 | * Copyright (C) Caldera International Inc. 2001-2002. All rights reserved. 36 | * 37 | * Redistribution and use in source and binary forms, with or without 38 | * modification, are permitted provided that the following conditions 39 | * are met: 40 | * 1. Redistributions of source code and documentation must retain the above 41 | * copyright notice, this list of conditions and the following disclaimer. 42 | * 2. Redistributions in binary form must reproduce the above copyright 43 | * notice, this list of conditions and the following disclaimer in the 44 | * documentation and/or other materials provided with the distribution. 45 | * 3. All advertising materials mentioning features or use of this software 46 | * must display the following acknowledgement: 47 | * This product includes software developed or owned by Caldera 48 | * International, Inc. 49 | * 4. Neither the name of Caldera International, Inc. nor the names of other 50 | * contributors may be used to endorse or promote products derived from 51 | * this software without specific prior written permission. 52 | * 53 | * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 54 | * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 55 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 56 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 57 | * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 58 | * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 59 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 60 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 62 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 63 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 64 | * POSSIBILITY OF SUCH DAMAGE. 65 | */ 66 | 67 | #include "defs.h" 68 | #include "err.h" 69 | 70 | #ifndef CONFIG_SUNOS 71 | static off_t offset; 72 | #endif 73 | 74 | static bool getlabel(/*@out@*/ char *, int, size_t); 75 | static int xgetc(void); 76 | 77 | /* 78 | * NAME 79 | * goto - transfer command 80 | * 81 | * SYNOPSIS 82 | * goto label [...] 83 | * 84 | * DESCRIPTION 85 | * See the goto(1) manual page for full details. 86 | */ 87 | int 88 | main(int argc, char **argv) 89 | { 90 | size_t siz; 91 | char label[LABELMAX]; 92 | 93 | setmyerrexit(&ut_errexit); 94 | setmyname(argv[0]); 95 | setmypid(getpid()); 96 | 97 | if (argc < 2 || *argv[1] == EOS || isatty(FD0) != 0) 98 | err(FC_ERR, FMT2S, getmyname(), ERR_GENERIC); 99 | if ((siz = strlen(argv[1]) + 1) > sizeof(label)) 100 | err(FC_ERR, FMT3S, getmyname(), argv[1], ERR_LABTOOLONG); 101 | if (lseek(FD0, (off_t)0, SEEK_SET) == -1) 102 | err(FC_ERR, FMT2S, getmyname(), ERR_SEEK); 103 | 104 | while (getlabel(label, *argv[1] & 0377, siz)) 105 | if (strcmp(label, argv[1]) == 0) { 106 | #ifndef CONFIG_SUNOS 107 | (void)lseek(FD0, offset, SEEK_SET); 108 | #endif 109 | return SH_TRUE; 110 | } 111 | 112 | fd_print(FD2, FMT3S, getmyname(), argv[1], ERR_LABNOTFOUND); 113 | return SH_FALSE; 114 | } 115 | 116 | /* 117 | * Search for the first occurrence of a possible label with both 118 | * the same first character (fc) and the same length (siz - 1) 119 | * as argv[1], and copy this possible label to buf. 120 | * Return true (1) if possible label found. 121 | * Return false (0) at end-of-file. 122 | */ 123 | static bool 124 | getlabel(char *buf, int fc, size_t siz) 125 | { 126 | int c; 127 | char *b; 128 | 129 | while ((c = xgetc()) != EOF) { 130 | /* `:' may be preceded by blanks. */ 131 | while (c == SPACE || c == TAB) 132 | c = xgetc(); 133 | if (c != COLON) { 134 | while (c != EOL && c != EOF) 135 | c = xgetc(); 136 | continue; 137 | } 138 | 139 | /* Prepare for possible label. */ 140 | while ((c = xgetc()) == SPACE || c == TAB) 141 | ; /* nothing */ 142 | if (c != fc) /* not label */ 143 | continue; 144 | 145 | /* 146 | * Try to copy possible label (first word only) 147 | * to buf, ignoring it if it becomes too long. 148 | */ 149 | b = buf; 150 | do { 151 | if (c == EOL || c == SPACE || c == TAB || c == EOF) { 152 | *b = EOS; 153 | break; 154 | } 155 | *b = c; 156 | c = xgetc(); 157 | } while (++b < &buf[siz]); 158 | 159 | /* Ignore any remaining characters on labelled line. */ 160 | while (c != EOL && c != EOF) 161 | c = xgetc(); 162 | if (c == EOF) 163 | break; 164 | 165 | if ((size_t)(b - buf) != siz - 1) /* not label */ 166 | continue; 167 | return true; 168 | } 169 | 170 | *buf = EOS; 171 | return false; 172 | } 173 | 174 | /* 175 | * If not at end-of-file, return the next character from the standard 176 | * input as an unsigned char converted to an int while incrementing 177 | * the global offset. Otherwise, return EOF at end-of-file. 178 | */ 179 | static int 180 | xgetc(void) 181 | { 182 | #ifndef CONFIG_SUNOS 183 | int nc; 184 | 185 | offset++; 186 | nc = getchar(); 187 | return (nc != EOF) ? nc & 0377 : EOF; 188 | #else 189 | unsigned char nc; 190 | 191 | return (read(FD0, &nc, (size_t)1) == 1) ? nc : EOF; 192 | #endif 193 | } 194 | -------------------------------------------------------------------------------- /if.1: -------------------------------------------------------------------------------- 1 | .\" 2 | .\" Copyright (c) 2004-2011 3 | .\" Jeffrey Allen Neitzel . 4 | .\" All rights reserved. 5 | .\" 6 | .\" Redistribution and use in source and binary forms, with or without 7 | .\" modification, are permitted provided that the following conditions 8 | .\" are met: 9 | .\" 1. Redistributions of source code must retain the above copyright 10 | .\" notice, this list of conditions and the following disclaimer. 11 | .\" 2. Redistributions in binary form must reproduce the above copyright 12 | .\" notice, this list of conditions and the following disclaimer in the 13 | .\" documentation and/or other materials provided with the distribution. 14 | .\" 15 | .\" THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 16 | .\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | .\" DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 19 | .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | .\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | .\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 | .\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | .\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 24 | .\" USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | .\" 26 | .\" @(#)$Id: 1ddc76276b973bf7dc67c8391917706f58a9bf15 $ 27 | .\" 28 | .\" Derived from: Sixth Edition UNIX /usr/man/man1/if.1 29 | .\" 30 | .\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved. 31 | .\" 32 | .\" Redistribution and use in source and binary forms, with or without 33 | .\" modification, are permitted provided that the following conditions 34 | .\" are met: 35 | .\" 1. Redistributions of source code and documentation must retain the above 36 | .\" copyright notice, this list of conditions and the following disclaimer. 37 | .\" 2. Redistributions in binary form must reproduce the above copyright 38 | .\" notice, this list of conditions and the following disclaimer in the 39 | .\" documentation and/or other materials provided with the distribution. 40 | .\" 3. All advertising materials mentioning features or use of this software 41 | .\" must display the following acknowledgement: 42 | .\" This product includes software developed or owned by Caldera 43 | .\" International, Inc. 44 | .\" 4. Neither the name of Caldera International, Inc. nor the names of other 45 | .\" contributors may be used to endorse or promote products derived from 46 | .\" this software without specific prior written permission. 47 | .\" 48 | .\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 49 | .\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 50 | .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 51 | .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 52 | .\" IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 53 | .\" INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 54 | .\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 55 | .\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 | .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 57 | .\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 58 | .\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 59 | .\" POSSIBILITY OF SUCH DAMAGE. 60 | .\" 61 | .TH IF 1 "@OSH_DATE@" "@OSH_VERSION@" "General Commands" 62 | .SH NAME 63 | if \- conditional command 64 | .SH SYNOPSIS 65 | .B if 66 | [\fIexpression\fR [\fIcommand\fR [\fIarg ...\fR]]] 67 | .SH DESCRIPTION 68 | .I If 69 | evaluates the specified 70 | .IR expression , 71 | and if its value is true, 72 | returns a zero exit status or executes 73 | the specified 74 | .I command 75 | with the given arguments. 76 | Otherwise, 77 | it returns a non-zero exit status. 78 | When 79 | .I expression 80 | is not specified, 81 | .I if 82 | also returns a non-zero exit status. 83 | .PP 84 | The following primaries are used to construct 85 | .IR expression : 86 | .TP 10 87 | \fB{\fR \fIcommand\fR [\fIarg ...\fR] \fB}\fR 88 | The specified \fIcommand\fR is executed with the 89 | given arguments to obtain its exit status. 90 | A zero status is \fItrue\fR; 91 | a non-zero status is \fIfalse\fR. 92 | .TP 93 | .BI \-d \ file 94 | True if \fIfile\fR exists and is a directory. 95 | .TP 96 | .BI \-e \ file 97 | True if \fIfile\fR exists. 98 | .TP 99 | .BI \-f \ file 100 | True if \fIfile\fR exists and is a regular file. 101 | .TP 102 | .BI \-h \ file 103 | True if \fIfile\fR exists and is a symbolic link. 104 | .TP 105 | .BI \-r \ file 106 | True if \fIfile\fR exists and is readable. 107 | .TP 108 | .BI \-s \ file 109 | True if \fIfile\fR exists and has a size greater than zero bytes. 110 | .TP 111 | .BI \-t \ fildes 112 | True if the file whose file descriptor number is 113 | .I fildes 114 | is open and associated with a terminal device. 115 | .I Fildes 116 | must be a decimal digit (0 \- 9). 117 | .TP 118 | .BI \-w \ file 119 | True if \fIfile\fR exists and is writable. 120 | .TP 121 | .BI \-x \ file 122 | True if \fIfile\fR exists and is executable, 123 | or if \fIfile\fR is a searchable directory. 124 | .TP 125 | .IB file1 \ \-ef \ file2 126 | True if \fIfile1\fR and \fIfile2\fR both exist and refer 127 | to the same file (same device, same inode). 128 | .TP 129 | .IB file1 \ \-nt \ file2 130 | True if \fIfile1\fR and \fIfile2\fR both exist 131 | and last data-modification time of \fIfile1\fR 132 | is newer than that of \fIfile2\fR. 133 | .TP 134 | .IB file1 \ \-ot \ file2 135 | True if \fIfile1\fR and \fIfile2\fR both exist 136 | and last data-modification time of \fIfile1\fR 137 | is older than that of \fIfile2\fR. 138 | .TP 139 | .IB s1 \ = \ s2 140 | True if the strings 141 | .I s1 142 | and 143 | .I s2 144 | are equal. 145 | .TP 146 | .IB s1 \ != \ s2 147 | True if the strings 148 | .I s1 149 | and 150 | .I s2 151 | are not equal. 152 | .PP 153 | These primaries may also be combined 154 | with the following operators: 155 | .TP 10 156 | .BI ! \ expression 157 | unary 158 | .I negation 159 | operator 160 | .TP 161 | .IB expression1 \ \-a \ expression2 162 | binary 163 | .I and 164 | operator 165 | .TP 166 | .IB expression1 \ \-o \ expression2 167 | binary 168 | .I or 169 | operator 170 | .TP 171 | .BI ( \ expression \ ) 172 | parentheses for grouping 173 | .PP 174 | .B \-a 175 | has higher precedence than 176 | .BR \-o . 177 | Notice that all of the operators and flags 178 | are separate arguments to 179 | .IR if . 180 | Notice also that parentheses are meaningful 181 | to the shell and must be escaped. 182 | .PP 183 | In addition, 184 | except for the 185 | .B \-h 186 | primary, 187 | symbolic links are followed for all 188 | other \fIfile\fR-related primaries. 189 | .\" primaries that refer to filesystem objects. 190 | .\" primaries that refer to files. 191 | .SH "EXIT STATUS" 192 | The 193 | .I if 194 | command exits with one of the following values: 195 | .TP 196 | 0 197 | The expression was true (see below). 198 | .TP 199 | 1 200 | The expression was false or was not specified. 201 | .TP 202 | 2 203 | An error was detected. 204 | .TP 205 | 125 206 | The specified command was found 207 | but did not begin with the proper 208 | magic number or a `#!shell' sequence, 209 | and a valid shell was not specified by 210 | EXECSHELL 211 | with which to execute it. 212 | .TP 213 | 126 214 | The specified command was found 215 | but could not be executed. 216 | .TP 217 | 127 218 | The specified command was not found. 219 | .PP 220 | If the expression is true and if 221 | .I command 222 | is specified and executed, 223 | the exit status is that of the executed 224 | .IR command . 225 | .SH ENVIRONMENT 226 | Notice that the concept of `user environment' 227 | was not defined in Sixth Edition UNIX. 228 | Thus, 229 | use of the following environment variables 230 | by this port of the conditional command is an enhancement: 231 | .TP 232 | .B EXECSHELL 233 | If set to a non-empty string, 234 | the value of this variable is taken as the 235 | path name of the shell which is invoked to 236 | execute the specified command when it does not 237 | begin with the proper magic number 238 | or a `#!shell' sequence. 239 | .TP 240 | .B PATH 241 | If set to a non-empty string, 242 | the value of this variable is taken as the 243 | sequence of directories which is used to 244 | search for the specified command. 245 | Notice that the 246 | conditional command from Sixth Edition UNIX 247 | always used the equivalent of `.:/bin:/usr/bin', 248 | not PATH. 249 | .SH "SEE ALSO" 250 | goto(1), 251 | osh(1), 252 | sh6(1), 253 | test(1) 254 | .PP 255 | Osh home page: 256 | http://v6shell.org/ 257 | .SH COMPATIBILITY 258 | The 259 | .I if 260 | command from Sixth Edition UNIX 261 | does not support the 262 | .BR \-d , 263 | .BR \-e , 264 | .BR \-f , 265 | .BR \-h , 266 | .BR \-s , 267 | .BR \-t , 268 | .BR \-x , 269 | .BR \-ef , 270 | .BR \-nt , 271 | and 272 | .B \-ot 273 | operators. 274 | .PP 275 | In addition to supporting the above operators, 276 | this port also differs from the original in that 277 | the exit status returned varies according to whether 278 | the expression is true or false, 279 | as is the case with 280 | .IR test (1). 281 | .SH HISTORY 282 | An 283 | .I if 284 | command 285 | appeared as 286 | .I /bin/if 287 | in Third Edition UNIX. 288 | .SH LICENSE 289 | See either the LICENSE file which is distributed with 290 | .I osh 291 | or 292 | http://v6shell.org/license/ 293 | for full details. 294 | .SH COPYRIGHT 295 | .nf 296 | Copyright (c) 2004-2011 297 | Jeffrey Allen Neitzel. All rights reserved. 298 | 299 | Copyright (c) 2001-2002 300 | Caldera International Inc. All rights reserved. 301 | 302 | Copyright (c) 1985, 1989, 1991, 1993 303 | The Regents of the University of California. All rights reserved. 304 | .fi 305 | -------------------------------------------------------------------------------- /if.c: -------------------------------------------------------------------------------- 1 | /* 2 | * if.c - a port of the Sixth Edition (V6) UNIX conditional command 3 | */ 4 | /*- 5 | * Copyright (c) 2004-2011 6 | * Jeffrey Allen Neitzel . 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 19 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 27 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | * @(#)$Id: 62e41f4cabb8392840b7b60698d7821e466da1d5 $ 30 | */ 31 | /* 32 | * Derived from: 33 | * - Sixth Edition UNIX /usr/source/s1/if.c 34 | * - Seventh Edition UNIX /usr/src/cmd/test.c 35 | */ 36 | /*- 37 | * Copyright (C) Caldera International Inc. 2001-2002. All rights reserved. 38 | * 39 | * Redistribution and use in source and binary forms, with or without 40 | * modification, are permitted provided that the following conditions 41 | * are met: 42 | * 1. Redistributions of source code and documentation must retain the above 43 | * copyright notice, this list of conditions and the following disclaimer. 44 | * 2. Redistributions in binary form must reproduce the above copyright 45 | * notice, this list of conditions and the following disclaimer in the 46 | * documentation and/or other materials provided with the distribution. 47 | * 3. All advertising materials mentioning features or use of this software 48 | * must display the following acknowledgement: 49 | * This product includes software developed or owned by Caldera 50 | * International, Inc. 51 | * 4. Neither the name of Caldera International, Inc. nor the names of other 52 | * contributors may be used to endorse or promote products derived from 53 | * this software without specific prior written permission. 54 | * 55 | * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 56 | * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 57 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 58 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 59 | * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 60 | * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 61 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 62 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 63 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 64 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 65 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 66 | * POSSIBILITY OF SUCH DAMAGE. 67 | */ 68 | 69 | #include "defs.h" 70 | #include "err.h" 71 | #include "pexec.h" 72 | #include "sasignal.h" 73 | 74 | static int ac; 75 | static int ap; 76 | static char **av; 77 | static uid_t ifeuid; 78 | 79 | /*@noreturn@*/ 80 | static void doex(bool); 81 | static bool e1(void); 82 | static bool e2(void); 83 | static bool e3(void); 84 | static bool equal(/*@null@*/ const char *, /*@null@*/ const char *); 85 | static bool expr(void); 86 | static bool ifaccess(/*@null@*/ const char *, int); 87 | static bool ifstat1(/*@null@*/ const char *, mode_t); 88 | static bool ifstat2(/*@null@*/ const char *, /*@null@*/ const char *, int); 89 | /*@null@*/ 90 | static char *nxtarg(bool); 91 | 92 | /* 93 | * NAME 94 | * if - conditional command 95 | * 96 | * SYNOPSIS 97 | * if [expression [command [arg ...]]] 98 | * 99 | * DESCRIPTION 100 | * See the if(1) manual page for full details. 101 | */ 102 | int 103 | main(int argc, char **argv) 104 | { 105 | bool re; /* return value of expr() */ 106 | 107 | setmyerrexit(&ut_errexit); 108 | setmyname(argv[0]); 109 | setmypid(getpid()); 110 | 111 | ifeuid = geteuid(); 112 | 113 | /* 114 | * Set-ID execution is not supported. 115 | */ 116 | if (ifeuid != getuid() || getegid() != getgid()) 117 | err(FC_ERR, FMT2S, getmyname(), ERR_SETID); 118 | 119 | (void)sasignal(SIGCHLD, SIG_DFL); 120 | 121 | if (argc > 1) { 122 | ac = argc; 123 | av = argv; 124 | ap = 1; 125 | re = expr(); 126 | if (re && ap < ac) 127 | doex(!FORKED); 128 | } else 129 | re = false; 130 | 131 | return re ? SH_TRUE : SH_FALSE; 132 | } 133 | 134 | /* 135 | * Evaluate the expression. 136 | * Return true (1) or false (0). 137 | */ 138 | static bool 139 | expr(void) 140 | { 141 | bool re; 142 | 143 | re = e1(); 144 | if (equal(nxtarg(RETERR), "-o")) 145 | return re | expr(); 146 | ap--; 147 | return re; 148 | } 149 | 150 | static bool 151 | e1(void) 152 | { 153 | bool re; 154 | 155 | re = e2(); 156 | if (equal(nxtarg(RETERR), "-a")) 157 | return re & e1(); 158 | ap--; 159 | return re; 160 | } 161 | 162 | static bool 163 | e2(void) 164 | { 165 | 166 | if (equal(nxtarg(RETERR), "!")) 167 | return !e3(); 168 | ap--; 169 | return e3(); 170 | } 171 | 172 | static bool 173 | e3(void) 174 | { 175 | bool re; 176 | pid_t cpid, tpid; 177 | int cstat, d; 178 | char *a, *b; 179 | 180 | if ((a = nxtarg(RETERR)) == NULL) 181 | err(FC_ERR, FMT3S, getmyname(), av[ap - 2], ERR_EXPR); 182 | 183 | /* 184 | * Deal w/ parentheses for grouping. 185 | */ 186 | if (equal(a, "(")) { 187 | re = expr(); 188 | if (!equal(nxtarg(RETERR), ")")) 189 | err(FC_ERR, FMT3S, getmyname(), a, ERR_PAREN); 190 | return re; 191 | } 192 | 193 | /* 194 | * Execute { command [arg ...] } to obtain its exit status. 195 | */ 196 | if (equal(a, "{")) { 197 | if ((cpid = fork()) == -1) 198 | err(FC_ERR, FMT2S, getmyname(), ERR_FORK); 199 | if (cpid == 0) 200 | /**** Child! ****/ 201 | doex(FORKED); 202 | else { 203 | /**** Parent! ****/ 204 | tpid = wait(&cstat); 205 | while ((a = nxtarg(RETERR)) != NULL && !equal(a, "}")) 206 | ; /* nothing */ 207 | if (a == NULL) 208 | ap--; 209 | return (tpid == cpid && cstat == 0) ? true : false; 210 | } 211 | } 212 | 213 | /* 214 | * file existence/permission tests 215 | */ 216 | if (equal(a, "-e")) 217 | return ifaccess(nxtarg(!RETERR), F_OK); 218 | if (equal(a, "-r")) 219 | return ifaccess(nxtarg(!RETERR), R_OK); 220 | if (equal(a, "-w")) 221 | return ifaccess(nxtarg(!RETERR), W_OK); 222 | if (equal(a, "-x")) 223 | return ifaccess(nxtarg(!RETERR), X_OK); 224 | 225 | /* 226 | * file existence/type tests 227 | */ 228 | if (equal(a, "-d")) 229 | return ifstat1(nxtarg(!RETERR), S_IFDIR); 230 | if (equal(a, "-f")) 231 | return ifstat1(nxtarg(!RETERR), S_IFREG); 232 | if (equal(a, "-h")) 233 | return ifstat1(nxtarg(!RETERR), S_IFLNK); 234 | if (equal(a, "-s")) 235 | return ifstat1(nxtarg(!RETERR), F_GZ); 236 | if (equal(a, "-t")) { 237 | /* Does the descriptor refer to a terminal device? */ 238 | b = nxtarg(RETERR); 239 | if (b == NULL || *b == EOS) 240 | err(FC_ERR, FMT3S, getmyname(), a, ERR_DIGIT); 241 | if (*b >= '0' && *b <= '9' && *(b + 1) == EOS) { 242 | d = *b - '0'; 243 | if (IS_DIGIT(d, *b)) 244 | return isatty(d) != 0; 245 | } 246 | err(FC_ERR, FMT3S, getmyname(), b, ERR_NOTDIGIT); 247 | } 248 | 249 | /* 250 | * binary comparisons 251 | */ 252 | if ((b = nxtarg(RETERR)) == NULL) 253 | err(FC_ERR, FMT3S, getmyname(), a, ERR_OPERATOR); 254 | if (equal(b, "=")) 255 | return equal(a, nxtarg(!RETERR)); 256 | if (equal(b, "!=")) 257 | return !equal(a, nxtarg(!RETERR)); 258 | if (equal(b, "-ot")) 259 | return ifstat2(a, nxtarg(!RETERR), F_OT); 260 | if (equal(b, "-nt")) 261 | return ifstat2(a, nxtarg(!RETERR), F_NT); 262 | if (equal(b, "-ef")) 263 | return ifstat2(a, nxtarg(!RETERR), F_EF); 264 | err(FC_ERR, FMT3S, getmyname(), b, ERR_OPUNKNOWN); 265 | /*NOTREACHED*/ 266 | return false; 267 | } 268 | 269 | static void 270 | doex(bool forked) 271 | { 272 | char **xap, **xav; 273 | 274 | if (ap < 2 || ap > ac) /* should never (but can) be true */ 275 | err(FC_ERR, FMT2S, getmyname(), ERR_AVIINVAL); 276 | 277 | xav = xap = &av[ap]; 278 | while (*xap != NULL) { 279 | if (forked && equal(*xap, "}")) 280 | break; 281 | xap++; 282 | } 283 | if (forked && xap - xav > 0 && !equal(*xap, "}")) 284 | err(FC_ERR, FMT3S, getmyname(), av[ap - 1], ERR_BRACE); 285 | *xap = NULL; 286 | if (xav[0] == NULL) { 287 | if (forked) 288 | err(FC_ERR, FMT3S, getmyname(),av[ap - 1],ERR_COMMAND); 289 | else 290 | /* Currently unreachable; do not remove. */ 291 | err(FC_ERR, FMT2S, getmyname(), ERR_COMMAND); 292 | } 293 | 294 | /* Invoke the ":" or "exit" special command. */ 295 | if (equal(xav[0], ":")) 296 | EXIT(SH_TRUE); 297 | if (equal(xav[0], "exit")) { 298 | (void)lseek(FD0, (off_t)0, SEEK_END); 299 | EXIT(SH_TRUE); 300 | } 301 | 302 | (void)err_pexec(xav[0], xav); 303 | } 304 | 305 | /* 306 | * Check access permission for file according to mode while 307 | * dealing w/ special cases for the superuser and `-x': 308 | * - Always grant search access on directories. 309 | * - If not a directory, require at least one execute bit. 310 | * Return true (1) if access is granted. 311 | * Return false (0) if access is denied. 312 | */ 313 | static bool 314 | ifaccess(const char *file, int mode) 315 | { 316 | struct stat sb; 317 | bool ra; 318 | 319 | if (file == NULL || *file == EOS) 320 | return false; 321 | 322 | ra = access(file, mode) == 0; 323 | 324 | if (ra && mode == X_OK && ifeuid == 0) { 325 | if (stat(file, &sb) < 0) 326 | ra = false; 327 | else if (S_ISDIR(sb.st_mode)) 328 | ra = true; 329 | else 330 | ra = (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) != 0; 331 | } 332 | 333 | return ra; 334 | } 335 | 336 | static bool 337 | ifstat1(const char *file, mode_t type) 338 | { 339 | struct stat sb; 340 | bool rs; 341 | 342 | if (file == NULL || *file == EOS) 343 | return false; 344 | 345 | if (type == S_IFLNK) { 346 | if (lstat(file, &sb) < 0) 347 | rs = false; 348 | else 349 | rs = (sb.st_mode & S_IFMT) == type; 350 | } else if (stat(file, &sb) < 0) 351 | rs = false; 352 | else if (type == S_IFDIR || type == S_IFREG) 353 | rs = (sb.st_mode & S_IFMT) == type; 354 | else if (type == F_GZ) 355 | rs = sb.st_size > (off_t)0; 356 | else 357 | rs = false; 358 | 359 | return rs; 360 | } 361 | 362 | static bool 363 | ifstat2(const char *file1, const char *file2, int act) 364 | { 365 | struct stat sb1, sb2; 366 | bool rs; 367 | 368 | if (file1 == NULL || *file1 == EOS) 369 | return false; 370 | if (file2 == NULL || *file2 == EOS) 371 | return false; 372 | 373 | if (stat(file1, &sb1) < 0) 374 | return false; 375 | if (stat(file2, &sb2) < 0) 376 | return false; 377 | 378 | if (act == F_OT) 379 | rs = sb1.st_mtime < sb2.st_mtime; 380 | else if (act == F_NT) 381 | rs = sb1.st_mtime > sb2.st_mtime; 382 | else if (act == F_EF) 383 | rs = sb1.st_dev == sb2.st_dev && sb1.st_ino == sb2.st_ino; 384 | else 385 | rs = false; 386 | 387 | return rs; 388 | } 389 | 390 | static char * 391 | nxtarg(bool reterr) 392 | { 393 | char *nap; 394 | 395 | if (ap < 1 || ap > ac) /* should never (but can) be true */ 396 | err(FC_ERR, FMT2S, getmyname(), ERR_AVIINVAL); 397 | 398 | if (ap == ac) { 399 | if (reterr) { 400 | ap++; 401 | return NULL; 402 | } 403 | err(FC_ERR, FMT3S, getmyname(), av[ap - 1], ERR_ARGUMENT); 404 | } 405 | nap = av[ap]; 406 | ap++; 407 | return nap; 408 | } 409 | 410 | static bool 411 | equal(const char *a, const char *b) 412 | { 413 | 414 | if (a == NULL || b == NULL) 415 | return false; 416 | return EQUAL(a, b); 417 | } 418 | -------------------------------------------------------------------------------- /mkconfig: -------------------------------------------------------------------------------- 1 | #!/bin/sh - 2 | # 3 | # @(#)$Id: 4bae0d32bd9c5aec5cfad6b6b8f7aee9d7a4ea32 $ 4 | # 5 | # Write out an appropriate "config.h" file. 6 | # This script is invoked automatically from the Makefile. 7 | # Thus, the user does not need to run it manually. 8 | # 9 | # Exit w/ a status of 0 on success. 10 | # Exit w/ a status of 1 on error. 11 | # -- 12 | # Jeffrey Allen Neitzel 13 | # 14 | 15 | CONFIG_H="config.h" 16 | rm -f $CONFIG_H 17 | trap 'status=$? ; rm -f $CONFIG_H ; exit $status' HUP INT QUIT TERM 18 | 19 | # 20 | # This function searches for the pathname of utility and defines 21 | # constant w/ the resulting value. If utility cannot be found, 22 | # constant is defined as the empty string. 23 | # 24 | # usage: definePathnameConstant constant utility 25 | # 26 | definePathnameConstant() 27 | { 28 | const="$1" ; util="$2" 29 | dirlist="/bin /sbin /usr/bin /usr/sbin /usr/libexec /usr/games" 30 | moderr=" Modify value in \"$CONFIG_H\" if this is incorrect." 31 | modout=" /* Modify value if incorrect. */" 32 | for dir in $dirlist ; do 33 | if test -f "$dir/$util" -a -x "$dir/$util" ; then 34 | pname="$dir/$util" ; break 35 | else 36 | pname="" 37 | fi 38 | done 39 | 40 | #echo "$PATH" >&2 41 | wpname="`which $util /dev/null | grep -v 'not found'`" 42 | #echo "$wpname" >&2 43 | if test X"$pname" != X -a \( \ 44 | X"$wpname" = X -o X"$wpname" = X"$pname" \ 45 | \) ; then 46 | (echo "$PROGNAME: $const == \"$pname\"";echo "$moderr") >&2 47 | def="#define $const \"$pname\"$modout" 48 | elif test X"$wpname" != X ; then 49 | (echo "$PROGNAME: $const == \"$wpname\"";echo "$moderr") >&2 50 | def="#define $const \"$wpname\"$modout" 51 | else 52 | # This should rarely be true, but it is possible. 53 | (echo "$PROGNAME: $const == \"\"";echo "$moderr") >&2 54 | def="#define $const \"\"$modout" 55 | fi 56 | 57 | echo "$def" 58 | } 59 | 60 | UNAME_S="`uname -s`" 61 | UNAME_SRM="`uname -srm`" 62 | PROGNAME="`basename $0`" 63 | if test $# -ne 0 ; then echo 'usage: $(SHELL) ./'"$PROGNAME" >&2 ; exit 1 ; fi 64 | if test X"$UNAME_S" = X -o X"$UNAME_SRM" = X ; then 65 | echo "$PROGNAME: Fatal uname(1) error" >&2 ; exit 1 66 | fi 67 | 68 | cat <$CONFIG_H 69 | /* 70 | * osh - an enhanced port of the Sixth Edition (V6) UNIX Thompson shell 71 | */ 72 | /* 73 | * _XOPEN_SOURCE and/or _BSD_SOURCE should be defined only if needed 74 | * to avoid compilation errors or warnings for the osh package on a 75 | * given system. The systems where these feature test macros are 76 | * (known to be) needed are defined in the mkconfig script. 77 | * 78 | * This includes only Linux and SunOS (Solaris/OpenSolaris) 79 | * at the present time. 80 | * 81 | * Configured for: $UNAME_SRM 82 | */ 83 | 84 | #ifndef CONFIG_H 85 | #define CONFIG_H 86 | 87 | `definePathnameConstant PATH_LOGIN login` 88 | `definePathnameConstant PATH_NEWGRP newgrp` 89 | 90 | EOI 91 | 92 | case "$UNAME_S" in 93 | *BSD|Darwin|DragonFly) 94 | echo "/* $UNAME_S: No need for _XOPEN_SOURCE or _BSD_SOURCE */" \ 95 | >>$CONFIG_H 96 | ;; 97 | Linux) 98 | echo '#define _XOPEN_SOURCE 600' >>$CONFIG_H 99 | echo '#define _BSD_SOURCE' >>$CONFIG_H 100 | ;; 101 | SunOS) 102 | ( echo '#define CONFIG_SUNOS' ; echo ) >>$CONFIG_H 103 | echo '#define _XOPEN_SOURCE 600' >>$CONFIG_H 104 | ;; 105 | *) 106 | # 107 | # This may or may not cause a compilation error. 108 | # Simply try it to see if it works or not. 109 | # 110 | echo "$PROGNAME: WARNING: Check \"$CONFIG_H\" if compilation fails." >&2 111 | cat <>$CONFIG_H 112 | /* 113 | * WARNING: $UNAME_SRM: Unknown system 114 | * 115 | * Please report this result to the developer if possible. 116 | */ 117 | EOI 118 | ;; 119 | esac 120 | 121 | echo >>$CONFIG_H 122 | echo '#endif /* !CONFIG_H */' >>$CONFIG_H 123 | -------------------------------------------------------------------------------- /pexec.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2005-2011 3 | * Jeffrey Allen Neitzel . 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 16 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 24 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | * 26 | * @(#)$Id: 6368bcb827bb40f7fe175d35491f8e9d4eeeeb1c $ 27 | */ 28 | /* 29 | * Derived from: 30 | * - /usr/src/lib/libc/gen/execvp.c: 31 | * $NetBSD: execvp.c,v 1.24 2003/08/07 16:42:47 agc Exp $ 32 | */ 33 | /*- 34 | * Copyright (c) 1991, 1993 35 | * The Regents of the University of California. All rights reserved. 36 | * 37 | * Redistribution and use in source and binary forms, with or without 38 | * modification, are permitted provided that the following conditions 39 | * are met: 40 | * 1. Redistributions of source code must retain the above copyright 41 | * notice, this list of conditions and the following disclaimer. 42 | * 2. Redistributions in binary form must reproduce the above copyright 43 | * notice, this list of conditions and the following disclaimer in the 44 | * documentation and/or other materials provided with the distribution. 45 | * 3. Neither the name of the University nor the names of its contributors 46 | * may be used to endorse or promote products derived from this software 47 | * without specific prior written permission. 48 | * 49 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 | * SUCH DAMAGE. 60 | * 61 | * @(#)exec.c 8.1 (Berkeley) 6/4/93 62 | */ 63 | 64 | #include "defs.h" 65 | #include "err.h" 66 | #include "pexec.h" 67 | 68 | extern char **environ; 69 | 70 | /* 71 | * Execute a file or path name. 72 | */ 73 | int 74 | pexec(const char *file, char *const *argv) 75 | { 76 | const char **esh_argv; 77 | size_t dlen, flen; 78 | int cnt, eacces = 0; 79 | const char *d, *esh, *f, *pnp, *upp; 80 | char pnbuf[PATHMAX]; 81 | 82 | /* 83 | * Fail if the value of file, argv, or argv[0] is invalid. 84 | */ 85 | errno = 0; 86 | if (file == NULL || argv == NULL || argv[0] == NULL) { 87 | errno = EINVAL; 88 | goto fail; 89 | } 90 | if (*file == EOS || *argv[0] == EOS) 91 | goto fail; 92 | flen = strlen(file); 93 | 94 | /* 95 | * If the name of the specified file contains one or more 96 | * `/' characters, it is used as the path name to execute. 97 | */ 98 | for (f = file; *f != EOS; f++) 99 | if (*f == SLASH) { 100 | pnp = file; 101 | upp = ""; 102 | goto exec_pathname; 103 | } 104 | *pnbuf = EOS; 105 | pnp = pnbuf; 106 | 107 | /* 108 | * Get the user's PATH. Fail if PATH is unset or is 109 | * set to the empty string, as no PATH search shall be 110 | * performed in such a case. 111 | */ 112 | upp = getenv("PATH"); 113 | if (upp == NULL || *upp == EOS) 114 | goto fail; 115 | 116 | do { 117 | /* Find the end of this PATH element. */ 118 | for (d = upp; *upp != COLON && *upp != EOS; upp++) 119 | ; /* nothing */ 120 | /* 121 | * Since this is a shell PATH, double, leading, and/or 122 | * trailing colons indicate the current directory. 123 | */ 124 | if (d == upp) { 125 | d = "."; 126 | dlen = 1; 127 | } else 128 | dlen = (size_t)(upp - d); 129 | 130 | /* 131 | * Complain if this path name for file would be too long. 132 | * Otherwise, use this PATH element to build a possible 133 | * path name for file. Then, attempt to execve(2) it. 134 | */ 135 | if (dlen + flen + 1 >= sizeof(pnbuf)) { 136 | struct iovec msg[3]; 137 | msg[0].iov_base = (char *)"pexec: "; 138 | msg[0].iov_len = (size_t)7; 139 | msg[1].iov_base = (char *)d; 140 | msg[1].iov_len = dlen; 141 | msg[2].iov_base = (char *)": path too long\n"; 142 | msg[2].iov_len = (size_t)16; 143 | (void)writev(FD2, msg, 3); 144 | continue; 145 | } 146 | (void)memcpy(pnbuf, d, dlen); 147 | pnbuf[dlen] = SLASH; 148 | (void)memcpy(pnbuf + dlen + 1, file, flen); 149 | pnbuf[dlen + flen + 1] = EOS; 150 | 151 | exec_pathname: 152 | (void)execve(pnp, argv, environ); 153 | switch (errno) { 154 | case EACCES: 155 | #if defined(__OpenBSD__) 156 | case EISDIR: /* Treat it as an EACCES error. */ 157 | #endif 158 | eacces = 1; 159 | /*FALLTHROUGH*/ 160 | case ELOOP: 161 | case ENAMETOOLONG: 162 | case ENOENT: 163 | case ENOTDIR: 164 | break; 165 | case ENOEXEC: 166 | /* 167 | * Get the user's EXECSHELL. 168 | * Fail if it is unset or is set to an unusable value. 169 | */ 170 | esh = getenv("EXECSHELL"); 171 | if (esh==NULL||*esh==EOS||strlen(esh)>=sizeof(pnbuf)) 172 | goto fail; 173 | for (cnt = 0; argv[cnt] != NULL; cnt++) 174 | ; /* nothing */ 175 | esh_argv = malloc((cnt + 2) * sizeof(char *)); 176 | if (esh_argv == NULL) 177 | goto fail; 178 | esh_argv[0] = esh; 179 | esh_argv[1] = pnp; 180 | (void)memcpy(&esh_argv[2],&argv[1],cnt*sizeof(char *)); 181 | (void)execve(esh, (char *const *)esh_argv, environ); 182 | free(esh_argv); 183 | errno = (errno == E2BIG) ? E2BIG : ENOEXEC; 184 | /*FALLTHROUGH*/ 185 | default: 186 | goto fail; 187 | } 188 | } while (*upp++ == COLON); /* Otherwise, *upp was NUL. */ 189 | if (eacces != 0) 190 | errno = EACCES; 191 | 192 | fail: 193 | if (errno == 0) 194 | errno = ENOENT; 195 | return -1; 196 | } 197 | 198 | /* 199 | * Execute a file or path name w/ error handling. 200 | * This function never returns. 201 | */ 202 | void 203 | err_pexec(const char *file, char *const *argv) 204 | { 205 | const char *f, *n; 206 | 207 | (void)pexec(file, argv); 208 | 209 | f = (file == NULL) ? "(null)" : file; 210 | n = getmyname(); 211 | 212 | if (EQUAL(n, "glob6")) { 213 | if (errno == ENOEXEC) 214 | err(SH_ERR, FMT1S, ERR_NOSHELL); 215 | if (errno == E2BIG) 216 | err(SH_ERR, FMT1S, ERR_E2BIG); 217 | err(SH_ERR, FMT1S, ERR_GNOTFOUND); 218 | } else if (EQUAL(n, "sh6")) { 219 | if (errno == ENOEXEC) 220 | err(125, FMT1S, ERR_NOSHELL); 221 | if (errno == E2BIG) 222 | err(126, FMT2S, f, ERR_E2BIG); 223 | if (errno != ENOENT && errno != ENOTDIR) 224 | err(126, FMT2S, f, ERR_EXEC); 225 | err(127, FMT2S, f, ERR_NOTFOUND); 226 | } else { 227 | if (errno == ENOEXEC) 228 | err(125, FMT3S, n, f, ERR_NOSHELL); 229 | if (errno == E2BIG) 230 | err(126, FMT3S, n, f, ERR_E2BIG); 231 | if (errno != ENOENT && errno != ENOTDIR) 232 | err(126, FMT3S, n, f, ERR_EXEC); 233 | err(127, FMT3S, n, f, ERR_NOTFOUND); 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /pexec.h: -------------------------------------------------------------------------------- 1 | /* 2 | * osh - an enhanced port of the Sixth Edition (V6) UNIX Thompson shell 3 | */ 4 | /*- 5 | * Copyright (c) 2005-2011 6 | * Jeffrey Allen Neitzel . 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 19 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 27 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | * @(#)$Id: ec40357f1af8e540dd2464a226d16e86840887c3 $ 30 | */ 31 | 32 | #ifndef PEXEC_H 33 | #define PEXEC_H 34 | 35 | /* 36 | * NAME 37 | * pexec - execute a file or path name 38 | * 39 | * SYNOPSIS 40 | * #include "pexec.h" 41 | * 42 | * extern char **environ; 43 | * 44 | * int 45 | * pexec(const char *file, char *const argv[]); 46 | * 47 | * DESCRIPTION 48 | * The pexec() function replaces the current process with a new process 49 | * by calling execve(2). The file argument specifies a file or path name 50 | * to execute. The argv argument is a pointer to a NULL-terminated array 51 | * of pointers to `\0'-terminated strings, which specifies the argument 52 | * list for the new process. 53 | * 54 | * If the name of the specified file contains one or more `/' characters, 55 | * it is used as the path name to execute. 56 | * 57 | * Otherwise, a path search is performed. The environment variable PATH 58 | * specifies the search path to be used. The search builds a sequence of 59 | * possible path names for the specified file, attempting to execve(2) 60 | * each one until success or failure. The search continues on any of 61 | * the following errors if PATH is not yet exhausted: 62 | * 63 | * EACCES, EISDIR (OpenBSD), ELOOP, ENAMETOOLONG, ENOENT, ENOTDIR 64 | * 65 | * If an EACCES, or EISDIR (OpenBSD), error occurs during the search 66 | * and if no other executable file is found, pexec() sets errno to 67 | * EACCES upon failure. The search ceases immediately on any error 68 | * not mentioned above (except ENOEXEC), or when PATH is exhausted. 69 | * 70 | * If execve(2) fails and sets errno to ENOEXEC, pexec() attempts to 71 | * execute the path name with the shell specified by the environment 72 | * variable EXECSHELL. If this attempt fails, pexec() also fails. 73 | * 74 | * Notice that if PATH is unset or is set to the empty string, the 75 | * name of the specified file must contain one or more `/' characters 76 | * in order to be executed. Otherwise, pexec() shall fail. 77 | * 78 | * Notice also that if EXECSHELL is unset or is set to the empty 79 | * string, pexec() shall make no attempt to execute the specified 80 | * file with any shell. Instead, pexec() shall fail. 81 | * 82 | * RETURN VALUES 83 | * On success, pexec() does not return. Otherwise, it returns 84 | * a value of -1 and sets errno according to the error. 85 | * 86 | * ERRORS 87 | * Possible errno values set by pexec() shall correspond to those 88 | * set by execve(2), with the following special exceptions: 89 | * 90 | * EINVAL The value of file, argv, or argv[0] is NULL. 91 | * 92 | * ENOEXEC The file argument specifies an executable file 93 | * which does not begin with the proper magic number. 94 | * At the same time, the value of EXECSHELL is unset, 95 | * is set to the empty string, or is set to another 96 | * unusable value which causes execve(2) to fail. 97 | */ 98 | 99 | /*@maynotreturn@*/ 100 | int pexec(/*@null@*/ const char *, /*@null@*/ char *const *); 101 | 102 | /* 103 | * NAME 104 | * err_pexec - execute a file or path name w/ error handling 105 | * 106 | * SYNOPSIS 107 | * #include "pexec.h" 108 | * 109 | * extern char **environ; 110 | * 111 | * void 112 | * err_pexec(const char *file, char *const argv[]); 113 | */ 114 | 115 | /*@noreturn@*/ 116 | void err_pexec(/*@null@*/ const char *, /*@null@*/ char *const *); 117 | 118 | #endif /* !PEXEC_H */ 119 | -------------------------------------------------------------------------------- /sasignal.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2008-2011 3 | * Jeffrey Allen Neitzel . 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 16 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 24 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | * 26 | * @(#)$Id: 76c8d3af2cd3ea3d27d4c61fb4e6e11fac19b15a $ 27 | */ 28 | /* 29 | * Derived from: 30 | * - /usr/src/lib/libc/gen/signal.c: 31 | * $OpenBSD: signal.c,v 1.7 2005/08/08 08:05:34 espie Exp $ 32 | */ 33 | /*- 34 | * Copyright (c) 1985, 1989, 1993 35 | * The Regents of the University of California. All rights reserved. 36 | * 37 | * Redistribution and use in source and binary forms, with or without 38 | * modification, are permitted provided that the following conditions 39 | * are met: 40 | * 1. Redistributions of source code must retain the above copyright 41 | * notice, this list of conditions and the following disclaimer. 42 | * 2. Redistributions in binary form must reproduce the above copyright 43 | * notice, this list of conditions and the following disclaimer in the 44 | * documentation and/or other materials provided with the distribution. 45 | * 3. Neither the name of the University nor the names of its contributors 46 | * may be used to endorse or promote products derived from this software 47 | * without specific prior written permission. 48 | * 49 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 | * SUCH DAMAGE. 60 | */ 61 | 62 | #include "defs.h" 63 | #include "sasignal.h" 64 | 65 | action_type 66 | sasignal(int sig, action_type act) 67 | { 68 | struct sigaction a, oa; 69 | 70 | (void)memset(&a, 0, sizeof(a)); 71 | (void)sigemptyset(&a.sa_mask); 72 | (void)sigaddset(&a.sa_mask, sig); 73 | 74 | a.sa_handler = act; 75 | a.sa_flags = SA_RESTART; 76 | 77 | if (sigaction(sig, &a, &oa) < 0) 78 | return SIG_ERR; 79 | 80 | return oa.sa_handler; 81 | } 82 | -------------------------------------------------------------------------------- /sasignal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * osh - an enhanced port of the Sixth Edition (V6) UNIX Thompson shell 3 | */ 4 | /*- 5 | * Copyright (c) 2008-2011 6 | * Jeffrey Allen Neitzel . 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 19 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 27 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | * @(#)$Id: 8275d7bbe7db26dcce394f01aac2bc336147d305 $ 30 | */ 31 | 32 | #ifndef SASIGNAL_H 33 | #define SASIGNAL_H 34 | 35 | /* 36 | * required header files 37 | */ 38 | #include 39 | 40 | /* 41 | * The sasignal() function is a signal() with BSD-like semantics. 42 | * On success, sasignal() returns the previous action. Otherwise, 43 | * it returns SIG_ERR and sets errno according to the error. 44 | */ 45 | 46 | typedef void (*action_type)(int); /* signal action type */ 47 | 48 | action_type sasignal(int, action_type); 49 | 50 | #endif /* !SASIGNAL_H */ 51 | -------------------------------------------------------------------------------- /sh.h: -------------------------------------------------------------------------------- 1 | /* 2 | * osh - an enhanced port of the Sixth Edition (V6) UNIX Thompson shell 3 | */ 4 | /*- 5 | * Copyright (c) 2004-2011 6 | * Jeffrey Allen Neitzel . 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 19 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 27 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | * @(#)$Id: 9d322d78e9e290c64e1253f5321d7f54a6943bfc $ 30 | */ 31 | 32 | #ifndef SH_H 33 | #define SH_H 34 | 35 | /* 36 | * signal flags 37 | */ 38 | enum sigflags { 39 | S_SIGINT = 01, 40 | S_SIGQUIT = 02, 41 | S_SIGTERM = 04 42 | }; 43 | 44 | #ifdef OSH_SHELL 45 | /* 46 | * shell special built-in (sbi) command keys 47 | */ 48 | enum sbikey { 49 | SBI_NULL, SBI_ALIAS, SBI_CD, SBI_CHDIR, SBI_ECHO, 50 | SBI_EXEC, SBI_EXIT, SBI_FD2, SBI_GOTO, SBI_IF, 51 | SBI_LOGIN, SBI_NEWGRP, SBI_SETENV, SBI_SHIFT, SBI_SIGIGN, 52 | SBI_SOURCE, SBI_UMASK, SBI_UNALIAS, SBI_UNSETENV, SBI_WAIT, 53 | SBI_UNKNOWN 54 | }; 55 | 56 | /* 57 | * shell alias node structure 58 | */ 59 | struct anode { 60 | /*@null@*/struct anode *next; 61 | /*@null@*/char *name; 62 | /*@null@*/char *string; 63 | }; 64 | #endif 65 | 66 | /* 67 | * shell command tree node flags 68 | */ 69 | enum tnflags { 70 | FAND = 0001, /* A `&' designates asynchronous execution. */ 71 | FCAT = 0002, /* A `>>' appends output to file. */ 72 | FFIN = 0004, /* A `<' redirects input from file. */ 73 | FPIN = 0010, /* A `|' or `^' redirects input from pipe. */ 74 | FPOUT = 0020, /* A `|' or `^' redirects output to pipe. */ 75 | FNOFORK = 0040, /* No fork(2) for last command in `( list )'. */ 76 | FINTR = 0100, /* Child process ignores SIGINT and SIGQUIT. */ 77 | FPRS = 0200 /* Print process ID of child as a string. */ 78 | }; 79 | 80 | /* 81 | * shell command tree node structure 82 | */ 83 | struct tnode { 84 | /*@null@*/struct tnode *nleft; /* Pointer to left node. */ 85 | /*@null@*/struct tnode *nright; /* Pointer to right node. */ 86 | /*@null@*/struct tnode *nsub; /* Pointer to TSUBSHELL node. */ 87 | /*@null@*/char *nfin; /* Pointer to input file (<). */ 88 | /*@null@*/char *nfout; /* Pointer to output file (>, >>). */ 89 | /*@null@*/char **nav; /* Argument vector for TCOMMAND. */ 90 | #ifdef OSH_SHELL 91 | enum sbikey nkey; /* Shell sbi command key. */ 92 | #endif 93 | enum tnflags nflags; /* Shell command tree node flags. */ 94 | enum { /* Shell command tree node type. */ 95 | TLIST = 1, /* pipelines separated by `;', `&', or `\n' */ 96 | TPIPE = 2, /* commands separated by `|' or `^' */ 97 | TCOMMAND = 3, /* command [arg ...] [< in] [> [>] out] */ 98 | TSUBSHELL = 4 /* ( list ) [< in] [> [>] out] */ 99 | } ntype; 100 | }; 101 | 102 | #ifdef OSH_SHELL 103 | /* osh.c */ 104 | extern uid_t sheuid; /* effective shell user ID */ 105 | 106 | enum sbikey cmd_lookup(const char *); 107 | 108 | /* util.c */ 109 | /*@maynotreturn@*/ 110 | int uexec(enum sbikey, int, char **); 111 | #endif 112 | 113 | #endif /* !SH_H */ 114 | -------------------------------------------------------------------------------- /sh6.1: -------------------------------------------------------------------------------- 1 | .\" 2 | .\" Copyright (c) 2003-2011 3 | .\" Jeffrey Allen Neitzel . 4 | .\" All rights reserved. 5 | .\" 6 | .\" Redistribution and use in source and binary forms, with or without 7 | .\" modification, are permitted provided that the following conditions 8 | .\" are met: 9 | .\" 1. Redistributions of source code must retain the above copyright 10 | .\" notice, this list of conditions and the following disclaimer. 11 | .\" 2. Redistributions in binary form must reproduce the above copyright 12 | .\" notice, this list of conditions and the following disclaimer in the 13 | .\" documentation and/or other materials provided with the distribution. 14 | .\" 15 | .\" THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 16 | .\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | .\" DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 19 | .\" DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | .\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | .\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 | .\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | .\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 24 | .\" USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | .\" 26 | .\" @(#)$Id: 4175a6c800650106814c55f19291695f7c73b7e8 $ 27 | .\" 28 | .\" Derived from: Sixth Edition UNIX /usr/man/man1/sh.1 29 | .\" 30 | .\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved. 31 | .\" 32 | .\" Redistribution and use in source and binary forms, with or without 33 | .\" modification, are permitted provided that the following conditions 34 | .\" are met: 35 | .\" 1. Redistributions of source code and documentation must retain the above 36 | .\" copyright notice, this list of conditions and the following disclaimer. 37 | .\" 2. Redistributions in binary form must reproduce the above copyright 38 | .\" notice, this list of conditions and the following disclaimer in the 39 | .\" documentation and/or other materials provided with the distribution. 40 | .\" 3. All advertising materials mentioning features or use of this software 41 | .\" must display the following acknowledgement: 42 | .\" This product includes software developed or owned by Caldera 43 | .\" International, Inc. 44 | .\" 4. Neither the name of Caldera International, Inc. nor the names of other 45 | .\" contributors may be used to endorse or promote products derived from 46 | .\" this software without specific prior written permission. 47 | .\" 48 | .\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 49 | .\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 50 | .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 51 | .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 52 | .\" IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 53 | .\" INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 54 | .\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 55 | .\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 | .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 57 | .\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 58 | .\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 59 | .\" POSSIBILITY OF SUCH DAMAGE. 60 | .\" 61 | .TH SH6 1 "@OSH_DATE@" "@OSH_VERSION@" "General Commands" 62 | .SH NAME 63 | sh6 \- shell (command interpreter) 64 | .SH SYNOPSIS 65 | .B sh6 66 | [\fB\-\fR | 67 | \fB\-c\fR [\fIstring\fR] | 68 | \fB\-t\fR | 69 | \fIfile\fR [\fIarg1 ...\fR]] 70 | .SH DESCRIPTION 71 | .I Sh6 72 | is a port of the 73 | standard command interpreter from Sixth Edition UNIX. 74 | It may be used either as an interactive shell 75 | or as a non-interactive shell. 76 | Throughout this manual, 77 | `(+)' indicates those cases where 78 | .I sh6 79 | is known to differ from the original 80 | .IR sh (1), 81 | as it appeared in Sixth Edition UNIX. 82 | .PP 83 | The options are as follows: 84 | .TP 85 | .B \- 86 | The shell reads and executes command lines 87 | from the standard input until 88 | end-of-file or 89 | .BR exit . 90 | .TP 91 | \fB\-c\fR [\fIstring\fR] 92 | If a 93 | .I string 94 | is specified, 95 | the shell executes it 96 | as a command line and exits. 97 | Otherwise, 98 | the shell treats it as the 99 | .B \- 100 | option. 101 | .TP 102 | .B \-t 103 | The shell reads a single line from the standard input, 104 | executes it as a command line, 105 | and exits. 106 | .PP 107 | The shell may also be invoked non-interactively 108 | to read, interpret, and execute an ASCII command file. 109 | The specified 110 | .I file 111 | and any arguments 112 | are treated as positional parameters 113 | (see 114 | .I "Parameter substitution" 115 | below) 116 | during execution of the command file. 117 | .PP 118 | Otherwise, 119 | if no arguments are specified and if both 120 | the standard input and standard error are 121 | connected to a terminal, 122 | the shell is interactive. 123 | An interactive shell prompts the user 124 | with a `%\ ' (or `#\ ' for the superuser) 125 | before reading each command line from the terminal. 126 | .SS Commands 127 | Each command is a sequence of non-blank command arguments 128 | separated by blanks (spaces or tabs). 129 | The first argument specifies the name of a command to be executed. 130 | Except for certain types of special arguments described below, 131 | the arguments other than the command name are passed 132 | without interpretation to the invoked command. 133 | .PP 134 | If the first argument names a special command, 135 | the shell executes it (see 136 | .I "Special commands" 137 | below). 138 | Otherwise, 139 | the shell treats it as an external command, 140 | which is located as follows. 141 | .PP 142 | (+) If the command name contains no `/' characters, 143 | the sequence of directories in the environment variable PATH 144 | is searched for the first occurrence 145 | of an executable file by that name, 146 | which the shell attempts to execute. 147 | However, 148 | if the command name contains one or more `/' characters, 149 | the shell attempts to execute it without 150 | performing any PATH search. 151 | .PP 152 | (+) If an executable file does not begin with 153 | the proper magic number or a `#!shell' sequence, 154 | it is assumed to be an ASCII command file, 155 | and a new shell is automatically invoked to execute it. 156 | The environment variable EXECSHELL 157 | specifies the shell which is invoked 158 | to execute such a file. 159 | .PP 160 | If a command cannot be found or executed, 161 | a diagnostic is printed. 162 | .SS Command lines 163 | Commands separated by `|' or `^' constitute a chain of 164 | .IR filters , 165 | or a 166 | .IR pipeline . 167 | The standard output of each command but the last 168 | is taken as the standard input of the next command. 169 | Each command is run as a separate process, connected 170 | by pipes (see 171 | .IR pipe (2)) 172 | to its neighbors. 173 | .PP 174 | A 175 | .IR "command line" , 176 | or 177 | .IR list , 178 | consists of one or more pipelines separated, 179 | and perhaps terminated by `;' or `&'. 180 | The semicolon designates sequential execution. 181 | The ampersand designates asynchronous execution, 182 | which causes the preceding pipeline to be executed 183 | without waiting for it to finish. 184 | The process ID of each command in such a pipeline is reported, 185 | so that it may be used if necessary for a subsequent 186 | .IR kill (1). 187 | .PP 188 | A list contained within parentheses such as `(\ list\ )' 189 | is executed in a subshell and may appear 190 | in place of a simple command as a filter. 191 | .PP 192 | If a command line is syntactically incorrect, 193 | a diagnostic is printed. 194 | .SS Termination reporting 195 | All terminations other than exit and interrupt 196 | are considered to be abnormal. 197 | If a sequential process terminates abnormally, 198 | a message is printed. 199 | The termination report for an asynchronous process 200 | is given upon execution of the first 201 | sequential command subsequent to its termination, 202 | or when the 203 | .B wait 204 | special command is executed. 205 | The following is a list of the possible 206 | termination messages: 207 | .PP 208 | .nf 209 | Hangup 210 | Quit 211 | Illegal instruction 212 | Trace/BPT trap 213 | IOT trap 214 | EMT trap 215 | Floating exception 216 | Killed 217 | Bus error 218 | Memory fault 219 | Bad system call 220 | .fi 221 | .PP 222 | For an asynchronous process, 223 | its process ID is prepended to the appropriate message. 224 | If a core image is produced, 225 | `\ \-\-\ Core\ dumped' is appended 226 | to the appropriate message. 227 | .SS I/O redirection 228 | Each of the following argument forms 229 | is interpreted as a 230 | .I redirection 231 | by the shell itself. 232 | Such a redirection may appear anywhere among 233 | the arguments of a simple command, 234 | or before or after a parenthesized command list, 235 | and is associated with that command or command list. 236 | .PP 237 | A redirection of the form `arg' causes the file `arg' 242 | to be used as the standard output (file descriptor 1) 243 | for the associated command. 244 | If `arg' does not already exist, it is created; 245 | otherwise, it is truncated at the outset. 246 | .PP 247 | A redirection of the form `>>arg' is the same as `>arg', 248 | except if `arg' already exists the command output is 249 | always appended to the end of the file. 250 | .PP 251 | For example, either of the following command lines: 252 | .PP 253 | .nf 254 | % date >.dirlist ; pwd >>.dirlist ; ls \-l >>.dirlist 255 | % ( date ; pwd ; ls \-l ) >.dirlist 256 | .fi 257 | .PP 258 | creates on the file `.dirlist', 259 | the current date and time, 260 | followed by the name and a long listing 261 | of the current working directory. 262 | .PP 263 | A `>arg' or `>>arg' redirection associated with any 264 | but the last command of a pipeline is ineffectual, 265 | as is a `', and others 286 | described in this manual. 287 | If such characters are quoted, 288 | they represent themselves and may be passed 289 | as part of arguments. 290 | .PP 291 | An individual 292 | .I backslash 293 | (\\) quotes, 294 | or 295 | .IR escapes , 296 | the next individual character. 297 | A backslash followed by a newline is a special case 298 | which allows continuation of command-line input 299 | onto the next line. 300 | Each backslash-newline sequence in the input 301 | is translated into a blank. 302 | .PP 303 | Individual characters, and sequences of characters, 304 | are also quoted when enclosed by a matched pair of 305 | .I double 306 | (") or 307 | .I single 308 | (') quotes. 309 | For example: 310 | .PP 311 | .nf 312 | % awk '{ print NR "\\t" $0 }' README ^ more 313 | .fi 314 | .PP 315 | causes 316 | .IR awk (1) 317 | to write each line in `README', 318 | preceded by its line number and a tab, 319 | to the standard output which is piped to 320 | .IR more (1) 321 | for viewing. 322 | The quotes prevent the shell from trying 323 | to interpret any part of the string, 324 | which is then passed as a single argument to awk. 325 | .PP 326 | If a double or single quote appears 327 | but is not part of a matched pair, 328 | a diagnostic is printed. 329 | .SS Parameter substitution 330 | When the shell is invoked as a non-interactive command, 331 | it has additional string processing capabilities 332 | which are not available when it is interactive. 333 | A non-interactive shell may be invoked 334 | as follows: 335 | .PP 336 | .nf 337 | \fBsh6\fR \fIname\fR [\fIarg1 ...\fR] 338 | .fi 339 | .PP 340 | If the first character of 341 | .I name 342 | is not `\-', 343 | it is taken as the name of an ASCII 344 | .IR "command file" , 345 | or 346 | .IR "shell script" , 347 | which is opened as the standard input 348 | for a new shell instance. 349 | Thus, 350 | the new shell reads and interprets command lines 351 | from the named file. 352 | .PP 353 | Otherwise, 354 | .I name 355 | is taken as one of the shell options, 356 | and a new shell instance is invoked 357 | to read and interpret command lines 358 | from its standard input. 359 | However, 360 | notice that the 361 | .B \-c 362 | option followed by a 363 | .I string 364 | is the one case where 365 | the shell does not read and interpret command lines 366 | from its standard input. 367 | Instead, 368 | the string itself is taken as a command line 369 | and executed. 370 | .PP 371 | In each command line, 372 | an unquoted character sequence of the form `$N', 373 | where 374 | .I N 375 | is a digit, 376 | is treated as a 377 | .I "positional parameter" 378 | by the shell. 379 | Each occurrence of a positional parameter in the 380 | command line is substituted with the value of the 381 | \fIN\fRth argument to the invocation of the shell 382 | (\fIargN\fR). 383 | `$0' is substituted with 384 | .IR name . 385 | .PP 386 | In both interactive and non-interactive shells, 387 | `$$' is substituted with the process ID of 388 | the current shell. 389 | The value is represented as a 5-digit ASCII string, 390 | padded on the left with zeros when the process ID 391 | is less than 10000. 392 | .PP 393 | All substitution on a command line is performed 394 | .I before 395 | the line is interpreted. 396 | Thus, 397 | no action which alters the value of any parameter 398 | can have any effect on a reference to that parameter 399 | occurring on the 400 | .I same 401 | line. 402 | .PP 403 | A positional-parameter value may contain 404 | any number of characters with special meaning 405 | to the shell. 406 | Each one which is 407 | .IR unquoted , 408 | or 409 | .IR unescaped , 410 | within a positional-parameter value retains 411 | its special meaning when the value is substituted 412 | in a command line by the invoked shell. 413 | .PP 414 | Take the following two shell invocations for example: 415 | .PP 416 | .nf 417 | % sh6 \-c '$1' 'echo Hello! >/dev/null' 418 | % sh6 \-c '$1' 'echo Hello! \\>/dev/null' 419 | Hello! >/dev/null 420 | .fi 421 | .PP 422 | In the first invocation, 423 | the `>' in the value substituted by `$1' 424 | retains its special meaning. 425 | This causes all output from 426 | .IR echo (1) 427 | to be redirected to `/dev/null'. 428 | However, 429 | in the second invocation, 430 | the meaning of `>' is escaped by `\\' 431 | in the value substituted by `$1'. 432 | This causes the shell to pass `>/dev/null' 433 | as an argument to echo instead of interpreting 434 | it as a redirection. 435 | .SS File name generation 436 | Prior to executing an external command, 437 | the shell scans each argument for 438 | unquoted `*', `?', or `[' characters. 439 | If one or more of these characters appears, 440 | the argument is treated as a 441 | .IR pattern , 442 | and the shell uses 443 | .IR glob6 (1) 444 | to search for file names which 445 | .I match 446 | it. 447 | Otherwise, 448 | the argument is used as is. 449 | .PP 450 | The meaning of each pattern character is as follows: 451 | .IP o 4 452 | The `*' character in a pattern matches any string of 453 | characters in a file name (including the null string). 454 | .IP o 455 | The `?' character in a pattern matches any single character 456 | in a file name. 457 | .IP o 458 | The `[...]' brackets in a pattern specifies a class of characters 459 | which matches any single file-name character in the class. 460 | Within the brackets, 461 | each character is taken to be a member of the class. 462 | A pair of characters separated by an unquoted `\-' specifies 463 | the class as a range which matches each character lexically 464 | between the first and second member of the pair, inclusive. 465 | A `\-' matches itself when quoted or when first or last 466 | in the class. 467 | .PP 468 | Any other character in a pattern matches itself in a file name. 469 | .PP 470 | Notice that the `.' character at the beginning of a file name, 471 | or immediately following a `/', 472 | is always special in that it must be matched explicitly. 473 | The same is true of the `/' character itself. 474 | .PP 475 | If the pattern contains no `/' characters, 476 | the current directory is always used. 477 | Otherwise, 478 | the specified directory is the one obtained by taking the pattern 479 | up to the last `/' before the first unquoted `*', `?', or `['. 480 | The matching process matches the remainder of the pattern 481 | after this `/' against the files in the specified directory. 482 | .PP 483 | In any event, 484 | a list of file names is obtained from the current 485 | (or specified) directory which match the given pattern. 486 | This list is sorted in ascending ASCII order, 487 | and the new sequence of arguments 488 | replaces the given pattern. 489 | The same process is carried out for each 490 | of the given pattern arguments; 491 | the resulting lists are 492 | .I not 493 | merged. 494 | Finally, 495 | the shell 496 | attempts to execute the command 497 | with the resulting argument list. 498 | .PP 499 | If a pattern argument refers to 500 | a directory which cannot be opened, 501 | a `No\ directory' diagnostic is printed. 502 | .PP 503 | If a command has only 504 | .I one 505 | pattern argument, 506 | a `No\ match' diagnostic is printed if it fails 507 | to match any files. 508 | However, 509 | if a command has more than one pattern argument, 510 | a diagnostic is printed only when they 511 | .I all 512 | fail to match any files. 513 | Otherwise, 514 | each pattern argument failing to match 515 | any files is simply removed from the argument list. 516 | .SS End of file 517 | An end-of-file in the shell's input 518 | causes it to exit. 519 | If the shell is interactive, 520 | this means it exits by default when 521 | the user types an EOT (^D) at the prompt. 522 | If desired, 523 | the user may change or disable 524 | the end-of-file character with 525 | .IR stty (1). 526 | .SS Special commands 527 | The following commands are special in that they are 528 | executed by the shell without creating a new process. 529 | .TP 530 | \fB:\fR [\fIarg ...\fR] 531 | Does nothing and sets the exit status to zero. 532 | .TP 533 | \fBchdir\fR \fIdir\fR [\fI...\fR] 534 | Changes the shell's current working directory to 535 | .IR dir . 536 | .TP 537 | .B exit 538 | Causes the shell to cease execution of a file. 539 | This means exit has no effect at the prompt 540 | of an interactive shell. 541 | .TP 542 | \fBlogin\fR [\fIarg ...\fR] 543 | Replaces the current interactive shell with 544 | .IR login (1). 545 | .TP 546 | \fBnewgrp\fR [\fIarg ...\fR] 547 | Replaces the current interactive shell with 548 | .IR newgrp (1). 549 | .TP 550 | .B shift 551 | Shifts all positional-parameter values to the 552 | left by 1, 553 | so that the old value of `$2' becomes the new 554 | value of `$1' and so forth. 555 | The value of `$0' does not shift. 556 | .TP 557 | .B wait 558 | Waits for all asynchronous processes to terminate, 559 | reporting on abnormal terminations. 560 | .SS Signals (+) 561 | If the shell is interactive, 562 | it ignores the SIGINT, SIGQUIT, and SIGTERM 563 | signals (see 564 | .IR signal (3)). 565 | However, 566 | if the shell is invoked with 567 | any option argument, 568 | it only ignores SIGINT and SIGQUIT. 569 | .PP 570 | If SIGINT, SIGQUIT, or SIGTERM is already ignored 571 | when the shell starts, 572 | it is also ignored by the current shell and all of its 573 | child processes. 574 | Otherwise, 575 | SIGINT and SIGQUIT are reset to the 576 | default action for sequential child processes, 577 | whereas SIGTERM is reset to the default action 578 | for all child processes. 579 | .PP 580 | For any signal not mentioned above, 581 | the shell inherits the signal action (default or ignore) 582 | from its parent process and passes it to its child processes. 583 | .PP 584 | Asynchronous child processes always ignore 585 | both SIGINT and SIGQUIT. 586 | Also, 587 | if such a process has not redirected its 588 | input with a `<', `|', or `^', 589 | the shell automatically redirects it to come from 590 | .IR /dev/null . 591 | .SH "EXIT STATUS (+)" 592 | The exit status of the shell is generally that of 593 | the last command executed prior to end-of-file or 594 | .BR exit . 595 | .PP 596 | However, 597 | if the shell is interactive and detects an error, 598 | it exits with a non-zero status if the user 599 | types an EOT at the next prompt. 600 | .PP 601 | Otherwise, 602 | if the shell is non-interactive and is reading 603 | commands from a file, 604 | any shell-detected error causes the shell 605 | to cease execution of that file. 606 | This results in a non-zero exit status. 607 | .PP 608 | A non-zero exit status returned by the shell 609 | itself is always one of the values described 610 | in the following list, 611 | each of which may be accompanied 612 | by an appropriate diagnostic: 613 | .TP 614 | 2 615 | The shell detected a syntax, redirection, 616 | or other error not described in this list. 617 | .TP 618 | 125 619 | An external command was found 620 | but did not begin with the proper 621 | magic number or a `#!shell' sequence, 622 | and a valid shell was not specified by 623 | EXECSHELL with which to execute it. 624 | .TP 625 | 126 626 | An external command was found 627 | but could not be executed. 628 | .TP 629 | 127 630 | An external command was not found. 631 | .TP 632 | >128 633 | An external command was terminated by a signal. 634 | .SH "ENVIRONMENT (+)" 635 | Notice that the concept of `user environment' 636 | was not defined in Sixth Edition UNIX. 637 | Thus, 638 | use of the following environment variables 639 | by this port of the shell is an enhancement: 640 | .TP 641 | .B EXECSHELL 642 | If set to a non-empty string, 643 | the value of this variable is taken as the 644 | path name of the shell which is invoked to 645 | execute an external command when it does not 646 | begin with the proper magic number 647 | or a `#!shell' sequence. 648 | .TP 649 | .B PATH 650 | If set to a non-empty string, 651 | the value of this variable is taken as the 652 | sequence of directories used 653 | by the shell to search for external commands. 654 | Notice that the Sixth Edition UNIX 655 | shell always used the equivalent of `.:/bin:/usr/bin', 656 | not PATH. 657 | .SH FILES 658 | .TP 659 | .I /dev/null 660 | default source of input for asynchronous processes 661 | .SH "SEE ALSO" 662 | awk(1), 663 | echo(1), 664 | env(1), 665 | expr(1), 666 | fd2(1), 667 | glob6(1), 668 | goto(1), 669 | grep(1), 670 | if(1), 671 | kill(1), 672 | login(1), 673 | newgrp(1), 674 | osh(1), 675 | sed(1), 676 | stty(1) 677 | .PP 678 | Osh home page: 679 | http://v6shell.org/ 680 | .SH AUTHORS 681 | This port of the Thompson shell is derived from 682 | Sixth Edition UNIX /usr/source/s2/sh.c, 683 | which was principally written by Ken Thompson of Bell Labs. 684 | Jeffrey Allen Neitzel initially ported it in January 2004 685 | and currently maintains it as 686 | .IR sh6 (1). 687 | .SH HISTORY 688 | A 689 | .I sh 690 | command 691 | appeared as 692 | .I /bin/sh 693 | in First Edition UNIX. 694 | .PP 695 | The Thompson shell 696 | was used as the standard command interpreter 697 | through Sixth Edition UNIX. 698 | Then, 699 | in the Seventh Edition, 700 | it was replaced by the Bourne shell. 701 | However, 702 | the Thompson shell 703 | was still distributed with the system as 704 | .I osh 705 | because of known portability problems 706 | with the Bourne shell's memory management 707 | in Seventh Edition UNIX. 708 | .SH LICENSE 709 | See either the LICENSE file which is distributed with 710 | .I osh 711 | or 712 | http://v6shell.org/license/ 713 | for full details. 714 | .SH COPYRIGHT 715 | .nf 716 | Copyright (c) 2003-2011 717 | Jeffrey Allen Neitzel. All rights reserved. 718 | 719 | Copyright (c) 2001-2002 720 | Caldera International Inc. All rights reserved. 721 | 722 | Copyright (c) 1985, 1989, 1991, 1993 723 | The Regents of the University of California. All rights reserved. 724 | .fi 725 | .SH NOTES 726 | Since 727 | .I sh6 728 | does not read any startup files, 729 | it should not be added to the shell database 730 | (see 731 | .IR shells (5)) 732 | unless the system administrator is willing 733 | to deal with this fact. 734 | .PP 735 | .I Sh6 736 | has no facilities for setting, unsetting, or otherwise 737 | manipulating environment variables within the shell. 738 | This must be accomplished by using other tools such as 739 | .IR env (1). 740 | .PP 741 | Like the original, 742 | .I sh6 743 | is not 8-bit clean as it uses the high-order bit 744 | of characters for quoting. 745 | Thus, 746 | the only complete character set it can handle 747 | is 7-bit ASCII. 748 | .PP 749 | Notice that certain shell oddities were historically 750 | undocumented in this manual page. 751 | Particularly noteworthy is the fact that there 752 | is no such thing as a usage error. 753 | Thus, 754 | the following shell invocations are perfectly valid: 755 | .PP 756 | .nf 757 | sh6 \-cats_are_nice!!! ': "Good kitty =)"' 758 | sh6 \-tabbies_are_too! 759 | sh6 \-s 760 | .fi 761 | .PP 762 | The first two cases correspond to the 763 | .B \-c 764 | and 765 | .B \-t 766 | options 767 | respectively; 768 | the third case corresponds to the 769 | .B \- 770 | option. 771 | .SH SECURITY 772 | This port of the Thompson shell does not support 773 | being used in a set-ID context. 774 | If the effective user (group) ID of the shell 775 | process is not equal to its real user (group) ID, 776 | the shell prints a diagnostic and exits with a 777 | non-zero status. 778 | The reasons for this are as follows. 779 | .PP 780 | First, 781 | the way in which the shell uses positional parameters 782 | (see 783 | .I "Parameter substitution" 784 | above) 785 | makes it a simple matter to invoke an interactive shell 786 | from a command file if the user knows the name 787 | of the current terminal (if any). 788 | This is distinctly 789 | .I not 790 | a bug and can be very useful in the normal case. 791 | .PP 792 | However, 793 | if the shell did support set-ID execution, 794 | this could possibly allow a user to violate the 795 | security policy on a host where the shell is used. 796 | For example, 797 | if the shell were running a setuid-root command file, 798 | a regular user could invoke an interactive root shell 799 | as a result. 800 | .SH BUGS 801 | The shell makes no attempt to recover from 802 | .IR read (2) 803 | errors and exits 804 | if this system call fails for any reason. 805 | -------------------------------------------------------------------------------- /util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * util.c - special built-in shell utilities for osh 3 | */ 4 | /*- 5 | * Copyright (c) 2004-2011 6 | * Jeffrey Allen Neitzel . 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 19 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 27 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | * @(#)$Id: 19f71205bbb12fdec1b0a4f93ff0d7ebda998863 $ 30 | */ 31 | /* 32 | * Derived from: osh-20080629 33 | * fd2.c (r404 2008-05-09 16:52:15Z jneitzel) 34 | * goto.c (r465 2008-06-25 22:11:58Z jneitzel) 35 | * if.c (r465 2008-06-25 22:11:58Z jneitzel) 36 | */ 37 | /*- 38 | * Copyright (C) Caldera International Inc. 2001-2002. All rights reserved. 39 | * 40 | * Redistribution and use in source and binary forms, with or without 41 | * modification, are permitted provided that the following conditions 42 | * are met: 43 | * 1. Redistributions of source code and documentation must retain the above 44 | * copyright notice, this list of conditions and the following disclaimer. 45 | * 2. Redistributions in binary form must reproduce the above copyright 46 | * notice, this list of conditions and the following disclaimer in the 47 | * documentation and/or other materials provided with the distribution. 48 | * 3. All advertising materials mentioning features or use of this software 49 | * must display the following acknowledgement: 50 | * This product includes software developed or owned by Caldera 51 | * International, Inc. 52 | * 4. Neither the name of Caldera International, Inc. nor the names of other 53 | * contributors may be used to endorse or promote products derived from 54 | * this software without specific prior written permission. 55 | * 56 | * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 57 | * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 58 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 59 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 60 | * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 61 | * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 62 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 63 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 64 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 65 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 66 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 67 | * POSSIBILITY OF SUCH DAMAGE. 68 | */ 69 | 70 | #define OSH_SHELL 71 | 72 | #include "defs.h" 73 | #include "err.h" 74 | #include "pexec.h" 75 | #include "sh.h" 76 | 77 | #define IS_SBI(k) \ 78 | ((k) == SBI_ECHO || (k) == SBI_FD2 || (k) == SBI_GOTO || (k) == SBI_IF) 79 | 80 | static int sbi_echo(int, char **); 81 | /*@maynotreturn@*/ 82 | static int sbi_fd2(int, char **); 83 | /*@maynotreturn@*/ 84 | static int sbi_goto(int, char **); 85 | /*@maynotreturn@*/ 86 | static int sbi_if(int, char **); 87 | 88 | /* 89 | * Execute the shell utility specified by key w/ the argument 90 | * count ac and the argument vector pointed to by av. Return 91 | * status s of the last call in the chain on success. Do not 92 | * return on invalid-utility error. 93 | */ 94 | int 95 | uexec(enum sbikey key, int ac, char **av) 96 | { 97 | int (*util)(int, char **); 98 | int r; 99 | static int cnt, cnt1, s; 100 | 101 | if (cnt == 0) setmyerrexit(&ut_errexit); 102 | 103 | switch (key) { 104 | case SBI_ECHO: util = &sbi_echo; break; 105 | case SBI_FD2: util = &sbi_fd2; break; 106 | case SBI_GOTO: util = &sbi_goto; break; 107 | case SBI_IF: util = &sbi_if; break; 108 | default: 109 | err(FC_ERR, FMT2S, getmyname(), "uexec: Invalid utility"); 110 | /*NOTREACHED*/ 111 | return FC_ERR; 112 | } 113 | 114 | cnt1 = cnt++; 115 | 116 | r = (*util)(ac, av); 117 | 118 | if (cnt-- > cnt1) 119 | s = r; 120 | 121 | #ifdef DEBUG 122 | if (cnt == 0) fd_print(FD2, "uexec: return %d;\n", s); 123 | #endif 124 | 125 | return s; 126 | } 127 | 128 | /* 129 | * NAME 130 | * echo - write arguments to standard output 131 | * 132 | * SYNOPSIS 133 | * echo [-n] [string ...] 134 | * 135 | * DESCRIPTION 136 | * Echo writes its string arguments (if any) separated by 137 | * blanks and terminated by a newline to the standard output. 138 | * If `-n' is specified, the terminating newline is not written. 139 | */ 140 | static int 141 | sbi_echo(int argc, char **argv) 142 | { 143 | bool nopt; 144 | char **avp, **ave; 145 | 146 | argc--, argv++; 147 | if (*argv != NULL && EQUAL(*argv, "-n")) { 148 | argc--, argv++; 149 | nopt = true; 150 | } else 151 | nopt = false; 152 | 153 | for (avp = argv, ave = &argv[argc]; avp < ave; avp++) 154 | fd_print(FD1, "%s%s", *avp, (avp + 1 < ave) ? " " : ""); 155 | if (!nopt) 156 | fd_print(FD1, FMT1S, ""); 157 | 158 | return SH_TRUE; 159 | } 160 | 161 | /*@noreturn@*/ 162 | static void fd2_usage(void); 163 | 164 | /* 165 | * NAME 166 | * fd2 - redirect from/to file descriptor 2 167 | * 168 | * SYNOPSIS 169 | * fd2 [-e] [-f file] [--] command [arg ...] 170 | * 171 | * DESCRIPTION 172 | * See the fd2(1) manual page for full details. 173 | */ 174 | static int 175 | sbi_fd2(int argc, char **argv) 176 | { 177 | bool eopt; 178 | enum sbikey key; 179 | int efd, nfd, ofd, opt; 180 | char *file; 181 | 182 | setmyname(argv[0]); 183 | 184 | ofd = FD1, efd = FD2; 185 | eopt = false, file = NULL; 186 | while ((opt = getopt(argc, argv, ":ef:")) != -1) 187 | switch (opt) { 188 | case 'e': 189 | eopt = true; 190 | break; 191 | case 'f': 192 | file = optarg; 193 | break; 194 | default: 195 | fd2_usage(); 196 | } 197 | argc -= optind; 198 | argv += optind; 199 | if (argc < 1) 200 | fd2_usage(); 201 | 202 | if (file != NULL) { 203 | if ((nfd = open(file, O_WRONLY|O_APPEND|O_CREAT, 0666)) == -1) 204 | err(FC_ERR, FMT3S, getmyname(), file, ERR_CREATE); 205 | if (dup2(nfd, efd) == -1) 206 | err(FC_ERR, FMT2S, getmyname(), strerror(errno)); 207 | if (eopt && dup2(efd, ofd) == -1) 208 | err(FC_ERR, FMT2S, getmyname(), strerror(errno)); 209 | (void)close(nfd); 210 | } else { 211 | if (eopt) 212 | ofd = FD2, efd = FD1; 213 | if (dup2(ofd, efd) == -1) 214 | err(FC_ERR, FMT2S, getmyname(), strerror(errno)); 215 | } 216 | 217 | /* 218 | * Try to execute the specified command. 219 | */ 220 | key = cmd_lookup(argv[0]); 221 | if (IS_SBI(key)) 222 | return uexec(key, argc, argv); 223 | 224 | (void)err_pexec(argv[0], argv); 225 | /*NOTREACHED*/ 226 | return FC_ERR; 227 | } 228 | 229 | static void 230 | fd2_usage(void) 231 | { 232 | 233 | err(FC_ERR, FD2_USAGE, getmyname()); 234 | } 235 | 236 | static off_t offset; 237 | 238 | static bool getlabel(/*@out@*/ char *, int, size_t); 239 | static int xgetc(void); 240 | 241 | /* 242 | * NAME 243 | * goto - transfer command 244 | * 245 | * SYNOPSIS 246 | * goto label [...] 247 | * 248 | * DESCRIPTION 249 | * See the goto(1) manual page for full details. 250 | */ 251 | static int 252 | sbi_goto(int argc, char **argv) 253 | { 254 | size_t siz; 255 | char label[LABELMAX]; 256 | 257 | setmyname(argv[0]); 258 | 259 | if (argc < 2 || *argv[1] == EOS || isatty(FD0) != 0) 260 | err(FC_ERR, FMT2S, getmyname(), ERR_GENERIC); 261 | if ((siz = strlen(argv[1]) + 1) > sizeof(label)) 262 | err(FC_ERR, FMT3S, getmyname(), argv[1], ERR_LABTOOLONG); 263 | if (lseek(FD0, (off_t)0, SEEK_SET) == -1) 264 | err(FC_ERR, FMT2S, getmyname(), ERR_SEEK); 265 | 266 | while (getlabel(label, *argv[1] & 0377, siz)) 267 | if (strcmp(label, argv[1]) == 0) { 268 | (void)lseek(FD0, offset, SEEK_SET); 269 | return SH_TRUE; 270 | } 271 | 272 | fd_print(FD2, FMT3S, getmyname(), argv[1], ERR_LABNOTFOUND); 273 | return SH_FALSE; 274 | } 275 | 276 | /* 277 | * Search for the first occurrence of a possible label with both 278 | * the same first character (fc) and the same length (siz - 1) 279 | * as argv[1], and copy this possible label to buf. 280 | * Return true (1) if possible label found. 281 | * Return false (0) at end-of-file. 282 | */ 283 | static bool 284 | getlabel(char *buf, int fc, size_t siz) 285 | { 286 | int c; 287 | char *b; 288 | 289 | while ((c = xgetc()) != EOF) { 290 | /* `:' may be preceded by blanks. */ 291 | while (c == SPACE || c == TAB) 292 | c = xgetc(); 293 | if (c != COLON) { 294 | while (c != EOL && c != EOF) 295 | c = xgetc(); 296 | continue; 297 | } 298 | 299 | /* Prepare for possible label. */ 300 | while ((c = xgetc()) == SPACE || c == TAB) 301 | ; /* nothing */ 302 | if (c != fc) /* not label */ 303 | continue; 304 | 305 | /* 306 | * Try to copy possible label (first word only) 307 | * to buf, ignoring it if it becomes too long. 308 | */ 309 | b = buf; 310 | do { 311 | if (c == EOL || c == SPACE || c == TAB || c == EOF) { 312 | *b = EOS; 313 | break; 314 | } 315 | *b = c; 316 | c = xgetc(); 317 | } while (++b < &buf[siz]); 318 | 319 | /* Ignore any remaining characters on labelled line. */ 320 | while (c != EOL && c != EOF) 321 | c = xgetc(); 322 | if (c == EOF) 323 | break; 324 | 325 | if ((size_t)(b - buf) != siz - 1) /* not label */ 326 | continue; 327 | return true; 328 | } 329 | 330 | *buf = EOS; 331 | return false; 332 | } 333 | 334 | /* 335 | * If not at end-of-file, return the next character from the standard 336 | * input as an unsigned char converted to an int while incrementing 337 | * the global offset. Otherwise, return EOF at end-of-file. 338 | */ 339 | static int 340 | xgetc(void) 341 | { 342 | int nc; 343 | 344 | offset++; 345 | nc = getchar(); 346 | return (nc != EOF) ? nc & 0377 : EOF; 347 | } 348 | 349 | static int iac; 350 | static int iap; 351 | static char **iav; 352 | 353 | /*@maynotreturn@*/ 354 | static void doex(bool); 355 | static bool e1(void); 356 | static bool e2(void); 357 | static bool e3(void); 358 | static bool equal(/*@null@*/ const char *, /*@null@*/ const char *); 359 | static bool expr(void); 360 | static bool ifaccess(/*@null@*/ const char *, int); 361 | static bool ifstat1(/*@null@*/ const char *, mode_t); 362 | static bool ifstat2(/*@null@*/ const char *, /*@null@*/ const char *, int); 363 | /*@null@*/ 364 | static char *nxtarg(bool); 365 | 366 | /* 367 | * NAME 368 | * if - conditional command 369 | * 370 | * SYNOPSIS 371 | * if [expression [command [arg ...]]] 372 | * 373 | * DESCRIPTION 374 | * See the if(1) manual page for full details. 375 | */ 376 | static int 377 | sbi_if(int argc, char **argv) 378 | { 379 | bool re; /* return value of expr() */ 380 | 381 | setmyname(argv[0]); 382 | 383 | if (argc > 1) { 384 | iac = argc; 385 | iav = argv; 386 | iap = 1; 387 | re = expr(); 388 | if (re && iap < iac) 389 | doex(!FORKED); 390 | } else 391 | re = false; 392 | 393 | return re ? SH_TRUE : SH_FALSE; 394 | } 395 | 396 | /* 397 | * Evaluate the expression. 398 | * Return true (1) or false (0). 399 | */ 400 | static bool 401 | expr(void) 402 | { 403 | bool re; 404 | 405 | re = e1(); 406 | if (equal(nxtarg(RETERR), "-o")) 407 | return re | expr(); 408 | iap--; 409 | return re; 410 | } 411 | 412 | static bool 413 | e1(void) 414 | { 415 | bool re; 416 | 417 | re = e2(); 418 | if (equal(nxtarg(RETERR), "-a")) 419 | return re & e1(); 420 | iap--; 421 | return re; 422 | } 423 | 424 | static bool 425 | e2(void) 426 | { 427 | 428 | if (equal(nxtarg(RETERR), "!")) 429 | return !e3(); 430 | iap--; 431 | return e3(); 432 | } 433 | 434 | static bool 435 | e3(void) 436 | { 437 | bool re; 438 | pid_t cpid, tpid; 439 | int cstat, d; 440 | char *a, *b; 441 | 442 | if ((a = nxtarg(RETERR)) == NULL) 443 | err(FC_ERR, FMT3S, getmyname(), iav[iap - 2], ERR_EXPR); 444 | 445 | /* 446 | * Deal w/ parentheses for grouping. 447 | */ 448 | if (equal(a, "(")) { 449 | re = expr(); 450 | if (!equal(nxtarg(RETERR), ")")) 451 | err(FC_ERR, FMT3S, getmyname(), a, ERR_PAREN); 452 | return re; 453 | } 454 | 455 | /* 456 | * Execute { command [arg ...] } to obtain its exit status. 457 | */ 458 | if (equal(a, "{")) { 459 | if ((cpid = fork()) == -1) 460 | err(FC_ERR, FMT2S, getmyname(), ERR_FORK); 461 | if (cpid == 0) 462 | /**** Child! ****/ 463 | doex(FORKED); 464 | else { 465 | /**** Parent! ****/ 466 | tpid = wait(&cstat); 467 | while ((a = nxtarg(RETERR)) != NULL && !equal(a, "}")) 468 | ; /* nothing */ 469 | if (a == NULL) 470 | iap--; 471 | return (tpid == cpid && cstat == 0) ? true : false; 472 | } 473 | } 474 | 475 | /* 476 | * file existence/permission tests 477 | */ 478 | if (equal(a, "-e")) 479 | return ifaccess(nxtarg(!RETERR), F_OK); 480 | if (equal(a, "-r")) 481 | return ifaccess(nxtarg(!RETERR), R_OK); 482 | if (equal(a, "-w")) 483 | return ifaccess(nxtarg(!RETERR), W_OK); 484 | if (equal(a, "-x")) 485 | return ifaccess(nxtarg(!RETERR), X_OK); 486 | 487 | /* 488 | * file existence/type tests 489 | */ 490 | if (equal(a, "-d")) 491 | return ifstat1(nxtarg(!RETERR), S_IFDIR); 492 | if (equal(a, "-f")) 493 | return ifstat1(nxtarg(!RETERR), S_IFREG); 494 | if (equal(a, "-h")) 495 | return ifstat1(nxtarg(!RETERR), S_IFLNK); 496 | if (equal(a, "-s")) 497 | return ifstat1(nxtarg(!RETERR), F_GZ); 498 | if (equal(a, "-t")) { 499 | /* Does the descriptor refer to a terminal device? */ 500 | b = nxtarg(RETERR); 501 | if (b == NULL || *b == EOS) 502 | err(FC_ERR, FMT3S, getmyname(), a, ERR_DIGIT); 503 | if (*b >= '0' && *b <= '9' && *(b + 1) == EOS) { 504 | d = *b - '0'; 505 | if (IS_DIGIT(d, *b)) 506 | return isatty(d) != 0; 507 | } 508 | err(FC_ERR, FMT3S, getmyname(), b, ERR_NOTDIGIT); 509 | } 510 | 511 | /* 512 | * binary comparisons 513 | */ 514 | if ((b = nxtarg(RETERR)) == NULL) 515 | err(FC_ERR, FMT3S, getmyname(), a, ERR_OPERATOR); 516 | if (equal(b, "=")) 517 | return equal(a, nxtarg(!RETERR)); 518 | if (equal(b, "!=")) 519 | return !equal(a, nxtarg(!RETERR)); 520 | if (equal(b, "-ot")) 521 | return ifstat2(a, nxtarg(!RETERR), F_OT); 522 | if (equal(b, "-nt")) 523 | return ifstat2(a, nxtarg(!RETERR), F_NT); 524 | if (equal(b, "-ef")) 525 | return ifstat2(a, nxtarg(!RETERR), F_EF); 526 | err(FC_ERR, FMT3S, getmyname(), b, ERR_OPUNKNOWN); 527 | /*NOTREACHED*/ 528 | return false; 529 | } 530 | 531 | static void 532 | doex(bool forked) 533 | { 534 | enum sbikey xak; 535 | char **xap, **xav; 536 | 537 | if (iap < 2 || iap > iac) /* should never (but can) be true */ 538 | err(FC_ERR, FMT2S, getmyname(), ERR_AVIINVAL); 539 | 540 | xav = xap = &iav[iap]; 541 | while (*xap != NULL) { 542 | if (forked && equal(*xap, "}")) 543 | break; 544 | xap++; 545 | } 546 | if (forked && xap - xav > 0 && !equal(*xap, "}")) 547 | err(FC_ERR, FMT3S, getmyname(), iav[iap - 1], ERR_BRACE); 548 | *xap = NULL; 549 | if (xav[0] == NULL) { 550 | if (forked) 551 | err(FC_ERR, FMT3S, getmyname(), iav[iap - 1], ERR_COMMAND); 552 | else 553 | /* Currently unreachable; do not remove. */ 554 | err(FC_ERR, FMT2S, getmyname(), ERR_COMMAND); 555 | } 556 | 557 | /* Invoke the ":" or "exit" special command. */ 558 | if (equal(xav[0], ":")) 559 | _exit(SH_TRUE); 560 | if (equal(xav[0], "exit")) { 561 | (void)lseek(FD0, (off_t)0, SEEK_END); 562 | _exit(SH_TRUE); 563 | } 564 | 565 | xak = cmd_lookup(xav[0]); 566 | if (IS_SBI(xak)) { 567 | if (forked) 568 | _exit(uexec(xak, (int)(xap - xav), xav)); 569 | else 570 | (void)uexec(xak, (int)(xap - xav), xav); 571 | return; 572 | } 573 | 574 | (void)err_pexec(xav[0], xav); 575 | } 576 | 577 | /* 578 | * Check access permission for file according to mode while 579 | * dealing w/ special cases for the superuser and `-x': 580 | * - Always grant search access on directories. 581 | * - If not a directory, require at least one execute bit. 582 | * Return true (1) if access is granted. 583 | * Return false (0) if access is denied. 584 | */ 585 | static bool 586 | ifaccess(const char *file, int mode) 587 | { 588 | struct stat sb; 589 | bool ra; 590 | 591 | if (file == NULL || *file == EOS) 592 | return false; 593 | 594 | ra = access(file, mode) == 0; 595 | 596 | if (ra && mode == X_OK && sheuid == 0) { 597 | if (stat(file, &sb) < 0) 598 | ra = false; 599 | else if (S_ISDIR(sb.st_mode)) 600 | ra = true; 601 | else 602 | ra = (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) != 0; 603 | } 604 | 605 | return ra; 606 | } 607 | 608 | static bool 609 | ifstat1(const char *file, mode_t type) 610 | { 611 | struct stat sb; 612 | bool rs; 613 | 614 | if (file == NULL || *file == EOS) 615 | return false; 616 | 617 | if (type == S_IFLNK) { 618 | if (lstat(file, &sb) < 0) 619 | rs = false; 620 | else 621 | rs = (sb.st_mode & S_IFMT) == type; 622 | } else if (stat(file, &sb) < 0) 623 | rs = false; 624 | else if (type == S_IFDIR || type == S_IFREG) 625 | rs = (sb.st_mode & S_IFMT) == type; 626 | else if (type == F_GZ) 627 | rs = sb.st_size > (off_t)0; 628 | else 629 | rs = false; 630 | 631 | return rs; 632 | } 633 | 634 | static bool 635 | ifstat2(const char *file1, const char *file2, int act) 636 | { 637 | struct stat sb1, sb2; 638 | bool rs; 639 | 640 | if (file1 == NULL || *file1 == EOS) 641 | return false; 642 | if (file2 == NULL || *file2 == EOS) 643 | return false; 644 | 645 | if (stat(file1, &sb1) < 0) 646 | return false; 647 | if (stat(file2, &sb2) < 0) 648 | return false; 649 | 650 | if (act == F_OT) 651 | rs = sb1.st_mtime < sb2.st_mtime; 652 | else if (act == F_NT) 653 | rs = sb1.st_mtime > sb2.st_mtime; 654 | else if (act == F_EF) 655 | rs = sb1.st_dev == sb2.st_dev && sb1.st_ino == sb2.st_ino; 656 | else 657 | rs = false; 658 | 659 | return rs; 660 | } 661 | 662 | static char * 663 | nxtarg(bool reterr) 664 | { 665 | char *nap; 666 | 667 | if (iap < 1 || iap > iac) /* should never (but can) be true */ 668 | err(FC_ERR, FMT2S, getmyname(), ERR_AVIINVAL); 669 | 670 | if (iap == iac) { 671 | if (reterr) { 672 | iap++; 673 | return NULL; 674 | } 675 | err(FC_ERR, FMT3S, getmyname(), iav[iap - 1], ERR_ARGUMENT); 676 | } 677 | nap = iav[iap]; 678 | iap++; 679 | return nap; 680 | } 681 | 682 | static bool 683 | equal(const char *a, const char *b) 684 | { 685 | 686 | if (a == NULL || b == NULL) 687 | return false; 688 | return EQUAL(a, b); 689 | } 690 | -------------------------------------------------------------------------------- /v.c: -------------------------------------------------------------------------------- 1 | /* 2 | * v.c - osh package version and copyright notices 3 | */ 4 | /*- 5 | * Copyright (c) 2008-2011 6 | * Jeffrey Allen Neitzel . 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY 19 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY 22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 27 | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | * 29 | * @(#)$Id: 2a3586ec60952dafe9805823be6f00966854c828 $ 30 | */ 31 | 32 | #ifndef lint 33 | #ifndef OSH_ATTR 34 | # if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 4 35 | # define OSH_ATTR __attribute__((__used__)) 36 | # elif defined(__GNUC__) 37 | # define OSH_ATTR __attribute__((__unused__)) 38 | # else 39 | # define OSH_ATTR /* nothing */ 40 | # endif 41 | #endif /* !OSH_ATTR */ 42 | /*@unused@*/ 43 | static const char cid[] OSH_ATTR = "\100(#)\044Id: Copyright (c) 1985, 1989, 1991, 1993 The Regents of the University of California. \044"; 44 | /*@unused@*/ 45 | static const char cid1[] OSH_ATTR = "\100(#)\044Id: Copyright (c) 2001-2002 Caldera International Inc. \044"; 46 | /*@unused@*/ 47 | static const char cid2[] OSH_ATTR = "\100(#)\044Id: Copyright (c) 2003-2011 Jeffrey Allen Neitzel. \044"; 48 | /*@unused@*/ 49 | static const char vid[] OSH_ATTR = "\100(#)\044Id: " OSH_VERSION " \044"; 50 | #endif /* !lint */ 51 | --------------------------------------------------------------------------------