Initial Spring 2016 commit.

This commit is contained in:
Geoffrey Challen
2015-12-23 00:50:04 +00:00
commit cafa9f5690
732 changed files with 92195 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <stdlib.h>
#include <unistd.h>
/*
* C standard function: panic exit from a user program.
*
* On most Unix systems, this sends the current process a fatal signal.
* We can't do that (no signals in OS/161) so we just exit with a
* nonzero exit code, skipping any libc cleanup.
*/
void
abort(void)
{
_exit(255);
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <stdlib.h>
#include <unistd.h>
/*
* C standard function: exit process.
*/
void
exit(int code)
{
/*
* In a more complicated libc, this would call functions registered
* with atexit() before calling the syscall to actually exit.
*/
#ifdef __mips__
/*
* Because gcc knows that _exit doesn't return, if we call it
* directly it will drop any code that follows it. This means
* that if _exit *does* return, as happens before it's
* implemented, undefined and usually weird behavior ensues.
*
* As a hack (this is quite gross) do the call by hand in an
* asm block. Then gcc doesn't know what it is, and won't
* optimize the following code out, and we can make sure
* that exit() at least really does not return.
*
* This asm block violates gcc's asm rules by destroying a
* register it doesn't declare ($4, which is a0) but this
* hopefully doesn't matter as the only local it can lose
* track of is "code" and we don't use it afterwards.
*/
__asm volatile("jal _exit;" /* call _exit */
"move $4, %0" /* put code in a0 (delay slot) */
: /* no outputs */
: "r" (code)); /* code is an input */
/*
* Ok, exiting doesn't work; see if we can get our process
* killed by making an illegal memory access. Use a magic
* number address so the symptoms are recognizable and
* unlikely to occur by accident otherwise.
*/
__asm volatile("li $2, 0xeeeee00f;" /* load magic addr into v0 */
"lw $2, 0($2)" /* fetch from it */
:: ); /* no args */
#else
_exit(code);
#endif
/*
* We can't return; so if we can't exit, the only other choice
* is to loop.
*/
while (1) { }
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright (c) 2013
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <stdlib.h>
#include <string.h>
/*
* getenv(): ANSI C
*
* Get an environment variable.
*/
/*
* This is initialized by crt0, though it actually lives in errno.c
*/
extern char **__environ;
/*
* This is what we use by default if the kernel didn't supply an
* environment.
*/
static const char *__default_environ[] = {
"PATH=/bin:/sbin:/testbin",
"SHELL=/bin/sh",
"TERM=vt220",
NULL
};
char *
getenv(const char *var)
{
size_t varlen, thislen;
char *s;
unsigned i;
if (__environ == NULL) {
__environ = (char **)__default_environ;
}
varlen = strlen(var);
for (i=0; __environ[i] != NULL; i++) {
s = strchr(__environ[i], '=');
if (s == NULL) {
/* ? */
continue;
}
thislen = s - __environ[i];
if (thislen == varlen && !memcmp(__environ[i], var, thislen)) {
return s + 1;
}
}
return NULL;
}

View File

@@ -0,0 +1,591 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* User-level malloc and free implementation.
*
* This is a basic first-fit allocator. It's intended to be simple and
* easy to follow. It performs abysmally if the heap becomes larger than
* physical memory. To get (much) better out-of-core performance, port
* the kernel's malloc. :-)
*/
#include <stdlib.h>
#include <stdint.h> // for uintptr_t on non-OS/161 platforms
#include <unistd.h>
#include <err.h>
#include <assert.h>
#undef MALLOCDEBUG
#if defined(__mips__) || defined(__i386__)
#define MALLOC32
#elif defined(__alpha__) || defined(__x86_64__)
#define MALLOC64
#else
#error "please fix me"
#endif
/*
* malloc block header.
*
* mh_prevblock is the downwards offset to the previous header, 0 if this
* is the bottom of the heap.
*
* mh_nextblock is the upwards offset to the next header.
*
* mh_pad is unused.
* mh_inuse is 1 if the block is in use, 0 if it is free.
* mh_magic* should always be a fixed value.
*
* MBLOCKSIZE should equal sizeof(struct mheader) and be a power of 2.
* MBLOCKSHIFT is the log base 2 of MBLOCKSIZE.
* MMAGIC is the value for mh_magic*.
*/
struct mheader {
#if defined(MALLOC32)
#define MBLOCKSIZE 8
#define MBLOCKSHIFT 3
#define MMAGIC 2
/*
* 32-bit platform. size_t is 32 bits (4 bytes).
* Block size is 8 bytes.
*/
unsigned mh_prevblock:29;
unsigned mh_pad:1;
unsigned mh_magic1:2;
unsigned mh_nextblock:29;
unsigned mh_inuse:1;
unsigned mh_magic2:2;
#elif defined(MALLOC64)
#define MBLOCKSIZE 16
#define MBLOCKSHIFT 4
#define MMAGIC 6
/*
* 64-bit platform. size_t is 64 bits (8 bytes)
* Block size is 16 bytes.
*/
unsigned mh_prevblock:60;
unsigned mh_pad:1;
unsigned mh_magic1:3;
unsigned mh_nextblock:60;
unsigned mh_inuse:1;
unsigned mh_magic2:3;
#else
#error "please fix me"
#endif
};
/*
* Operator macros on struct mheader.
*
* M_NEXT/PREVOFF: return offset to next/previous header
* M_NEXT/PREV: return next/previous header
*
* M_DATA: return data pointer of a header
* M_SIZE: return data size of a header
*
* M_OK: true if the magic values are correct
*
* M_MKFIELD: prepare a value for mh_next/prevblock.
* (value should include the header size)
*/
#define M_NEXTOFF(mh) ((size_t)(((size_t)((mh)->mh_nextblock))<<MBLOCKSHIFT))
#define M_PREVOFF(mh) ((size_t)(((size_t)((mh)->mh_prevblock))<<MBLOCKSHIFT))
#define M_NEXT(mh) ((struct mheader *)(((char*)(mh))+M_NEXTOFF(mh)))
#define M_PREV(mh) ((struct mheader *)(((char*)(mh))-M_PREVOFF(mh)))
#define M_DATA(mh) ((void *)((mh)+1))
#define M_SIZE(mh) (M_NEXTOFF(mh)-MBLOCKSIZE)
#define M_OK(mh) ((mh)->mh_magic1==MMAGIC && (mh)->mh_magic2==MMAGIC)
#define M_MKFIELD(off) ((off)>>MBLOCKSHIFT)
/*
* System page size. In POSIX you're supposed to call
* sysconf(_SC_PAGESIZE). If _SC_PAGESIZE isn't defined, as on OS/161,
* assume 4K.
*/
#ifdef _SC_PAGESIZE
static size_t __malloc_pagesize;
#define PAGE_SIZE __malloc_pagesize
#else
#define PAGE_SIZE 4096
#endif
////////////////////////////////////////////////////////////
/*
* Static variables - the bottom and top addresses of the heap.
*/
static uintptr_t __heapbase, __heaptop;
/*
* Setup function.
*/
static
void
__malloc_init(void)
{
void *x;
/*
* Check various assumed properties of the sizes.
*/
if (sizeof(struct mheader) != MBLOCKSIZE) {
errx(1, "malloc: Internal error - MBLOCKSIZE wrong");
}
if ((MBLOCKSIZE & (MBLOCKSIZE-1))!=0) {
errx(1, "malloc: Internal error - MBLOCKSIZE not power of 2");
}
if (1<<MBLOCKSHIFT != MBLOCKSIZE) {
errx(1, "malloc: Internal error - MBLOCKSHIFT wrong");
}
/* init should only be called once. */
if (__heapbase!=0 || __heaptop!=0) {
errx(1, "malloc: Internal error - bad init call");
}
/* Get the page size, if needed. */
#ifdef _SC_PAGESIZE
__malloc_pagesize = sysconf(_SC_PAGESIZE);
#endif
/* Use sbrk to find the base of the heap. */
x = sbrk(0);
if (x==(void *)-1) {
err(1, "malloc: initial sbrk failed");
}
if (x==(void *) 0) {
errx(1, "malloc: Internal error - heap began at 0");
}
__heapbase = __heaptop = (uintptr_t)x;
/*
* Make sure the heap base is aligned the way we want it.
* (On OS/161, it will begin on a page boundary. But on
* an arbitrary Unix, it may not be, as traditionally it
* begins at _end.)
*/
if (__heapbase % MBLOCKSIZE != 0) {
size_t adjust = MBLOCKSIZE - (__heapbase % MBLOCKSIZE);
x = sbrk(adjust);
if (x==(void *)-1) {
err(1, "malloc: sbrk failed aligning heap base");
}
if ((uintptr_t)x != __heapbase) {
err(1, "malloc: heap base moved during init");
}
#ifdef MALLOCDEBUG
warnx("malloc: adjusted heap base upwards by %lu bytes",
(unsigned long) adjust);
#endif
__heapbase += adjust;
__heaptop = __heapbase;
}
}
////////////////////////////////////////////////////////////
#ifdef MALLOCDEBUG
/*
* Debugging print function to iterate and dump the entire heap.
*/
static
void
__malloc_dump(void)
{
struct mheader *mh;
uintptr_t i;
size_t rightprevblock;
warnx("heap: ************************************************");
rightprevblock = 0;
for (i=__heapbase; i<__heaptop; i += M_NEXTOFF(mh)) {
mh = (struct mheader *) i;
if (!M_OK(mh)) {
errx(1, "malloc: Heap corrupt; header at 0x%lx"
" has bad magic bits",
(unsigned long) i);
}
if (mh->mh_prevblock != rightprevblock) {
errx(1, "malloc: Heap corrupt; header at 0x%lx"
" has bad previous-block size %lu "
"(should be %lu)",
(unsigned long) i,
(unsigned long) mh->mh_prevblock << MBLOCKSHIFT,
(unsigned long) rightprevblock << MBLOCKSHIFT);
}
rightprevblock = mh->mh_nextblock;
warnx("heap: 0x%lx 0x%-6lx (next: 0x%lx) %s",
(unsigned long) i + MBLOCKSIZE,
(unsigned long) M_SIZE(mh),
(unsigned long) (i+M_NEXTOFF(mh)),
mh->mh_inuse ? "INUSE" : "FREE");
}
if (i!=__heaptop) {
errx(1, "malloc: Heap corrupt; ran off end");
}
warnx("heap: ************************************************");
}
#endif /* MALLOCDEBUG */
////////////////////////////////////////////////////////////
/*
* Get more memory (at the top of the heap) using sbrk, and
* return a pointer to it.
*/
static
void *
__malloc_sbrk(size_t size)
{
void *x;
x = sbrk(size);
if (x == (void *)-1) {
return NULL;
}
if ((uintptr_t)x != __heaptop) {
errx(1, "malloc: Internal error - "
"heap top moved itself from 0x%lx to 0x%lx",
(unsigned long) __heaptop,
(unsigned long) (uintptr_t) x);
}
__heaptop += size;
return x;
}
/*
* Make a new (free) block from the block passed in, leaving size
* bytes for data in the current block. size must be a multiple of
* MBLOCKSIZE.
*
* Only split if the excess space is at least twice the blocksize -
* one blocksize to hold a header and one for data.
*/
static
void
__malloc_split(struct mheader *mh, size_t size)
{
struct mheader *mhnext, *mhnew;
size_t oldsize;
if (size % MBLOCKSIZE != 0) {
errx(1, "malloc: Internal error (size %lu passed to split)",
(unsigned long) size);
}
if (M_SIZE(mh) - size < 2*MBLOCKSIZE) {
/* no room */
return;
}
mhnext = M_NEXT(mh);
oldsize = M_SIZE(mh);
mh->mh_nextblock = M_MKFIELD(size + MBLOCKSIZE);
mhnew = M_NEXT(mh);
if (mhnew==mhnext) {
errx(1, "malloc: Internal error (split screwed up?)");
}
mhnew->mh_prevblock = M_MKFIELD(size + MBLOCKSIZE);
mhnew->mh_pad = 0;
mhnew->mh_magic1 = MMAGIC;
mhnew->mh_nextblock = M_MKFIELD(oldsize - size);
mhnew->mh_inuse = 0;
mhnew->mh_magic2 = MMAGIC;
if (mhnext != (struct mheader *) __heaptop) {
mhnext->mh_prevblock = mhnew->mh_nextblock;
}
}
/*
* malloc itself.
*/
void *
malloc(size_t size)
{
struct mheader *mh;
uintptr_t i;
size_t rightprevblock;
size_t morespace;
void *p;
if (__heapbase==0) {
__malloc_init();
}
if (__heapbase==0 || __heaptop==0 || __heapbase > __heaptop) {
warnx("malloc: Internal error - local data corrupt");
errx(1, "malloc: heapbase 0x%lx; heaptop 0x%lx",
(unsigned long) __heapbase, (unsigned long) __heaptop);
}
#ifdef MALLOCDEBUG
warnx("malloc: about to allocate %lu (0x%lx) bytes",
(unsigned long) size, (unsigned long) size);
__malloc_dump();
#endif
/* Round size up to an integral number of blocks. */
size = ((size + MBLOCKSIZE - 1) & ~(size_t)(MBLOCKSIZE-1));
/*
* First-fit search algorithm for available blocks.
* Check to make sure the next/previous sizes all agree.
*/
rightprevblock = 0;
mh = NULL;
for (i=__heapbase; i<__heaptop; i += M_NEXTOFF(mh)) {
mh = (struct mheader *) i;
if (!M_OK(mh)) {
errx(1, "malloc: Heap corrupt; header at 0x%lx"
" has bad magic bits",
(unsigned long) i);
}
if (mh->mh_prevblock != rightprevblock) {
errx(1, "malloc: Heap corrupt; header at 0x%lx"
" has bad previous-block size %lu "
"(should be %lu)",
(unsigned long) i,
(unsigned long) mh->mh_prevblock << MBLOCKSHIFT,
(unsigned long) rightprevblock << MBLOCKSHIFT);
}
rightprevblock = mh->mh_nextblock;
/* Can't allocate a block that's in use. */
if (mh->mh_inuse) {
continue;
}
/* Can't allocate a block that isn't big enough. */
if (M_SIZE(mh) < size) {
continue;
}
/* Try splitting block. */
__malloc_split(mh, size);
/*
* Now, allocate.
*/
mh->mh_inuse = 1;
#ifdef MALLOCDEBUG
warnx("malloc: allocating at %p", M_DATA(mh));
__malloc_dump();
#endif
return M_DATA(mh);
}
if (i!=__heaptop) {
errx(1, "malloc: Heap corrupt; ran off end");
}
/*
* Didn't find anything. Expand the heap.
*
* If the heap is nonempty and the top block (the one mh is
* left pointing to after the above loop) is free, we can
* expand it. Otherwise we need a new block.
*/
if (mh != NULL && !mh->mh_inuse) {
assert(size > M_SIZE(mh));
morespace = size - M_SIZE(mh);
}
else {
morespace = MBLOCKSIZE + size;
}
/* Round the amount of space we ask for up to a whole page. */
morespace = PAGE_SIZE * ((morespace + PAGE_SIZE - 1) / PAGE_SIZE);
p = __malloc_sbrk(morespace);
if (p == NULL) {
return NULL;
}
if (mh != NULL && !mh->mh_inuse) {
/* update old header */
mh->mh_nextblock = M_MKFIELD(M_NEXTOFF(mh) + morespace);
mh->mh_inuse = 1;
}
else {
/* fill out new header */
mh = p;
mh->mh_prevblock = rightprevblock;
mh->mh_magic1 = MMAGIC;
mh->mh_magic2 = MMAGIC;
mh->mh_pad = 0;
mh->mh_inuse = 1;
mh->mh_nextblock = M_MKFIELD(morespace);
}
/*
* Either way, try splitting the block we got as because of
* the page rounding it might be quite a bit bigger than we
* needed.
*/
__malloc_split(mh, size);
#ifdef MALLOCDEBUG
warnx("malloc: allocating at %p", M_DATA(mh));
__malloc_dump();
#endif
return M_DATA(mh);
}
////////////////////////////////////////////////////////////
/*
* Clear a range of memory with 0xdeadbeef.
* ptr must be suitably aligned.
*/
static
void
__malloc_deadbeef(void *ptr, size_t size)
{
uint32_t *x = ptr;
size_t i, n = size/sizeof(uint32_t);
for (i=0; i<n; i++) {
x[i] = 0xdeadbeef;
}
}
/*
* Attempt to merge two adjacent blocks (mh below mhnext).
*/
static
void
__malloc_trymerge(struct mheader *mh, struct mheader *mhnext)
{
struct mheader *mhnextnext;
if (mh->mh_nextblock != mhnext->mh_prevblock) {
errx(1, "free: Heap corrupt (%p and %p inconsistent)",
mh, mhnext);
}
if (mh->mh_inuse || mhnext->mh_inuse) {
/* can't merge */
return;
}
mhnextnext = M_NEXT(mhnext);
mh->mh_nextblock = M_MKFIELD(MBLOCKSIZE + M_SIZE(mh) +
MBLOCKSIZE + M_SIZE(mhnext));
if (mhnextnext != (struct mheader *)__heaptop) {
mhnextnext->mh_prevblock = mh->mh_nextblock;
}
/* Deadbeef out the memory used by the now-obsolete header */
__malloc_deadbeef(mhnext, sizeof(struct mheader));
}
/*
* The actual free() implementation.
*/
void
free(void *x)
{
struct mheader *mh, *mhnext, *mhprev;
if (x==NULL) {
/* safest practice */
return;
}
/* Consistency check. */
if (__heapbase==0 || __heaptop==0 || __heapbase > __heaptop) {
warnx("free: Internal error - local data corrupt");
errx(1, "free: heapbase 0x%lx; heaptop 0x%lx",
(unsigned long) __heapbase, (unsigned long) __heaptop);
}
/* Don't allow freeing pointers that aren't on the heap. */
if ((uintptr_t)x < __heapbase || (uintptr_t)x >= __heaptop) {
errx(1, "free: Invalid pointer %p freed (out of range)", x);
}
#ifdef MALLOCDEBUG
warnx("free: about to free %p", x);
__malloc_dump();
#endif
mh = ((struct mheader *)x)-1;
if (!M_OK(mh)) {
errx(1, "free: Invalid pointer %p freed (corrupt header)", x);
}
if (!mh->mh_inuse) {
errx(1, "free: Invalid pointer %p freed (already free)", x);
}
/* mark it free */
mh->mh_inuse = 0;
/* wipe it */
__malloc_deadbeef(M_DATA(mh), M_SIZE(mh));
/* Try merging with the block above (but not if we're at the top) */
mhnext = M_NEXT(mh);
if (mhnext != (struct mheader *)__heaptop) {
__malloc_trymerge(mh, mhnext);
}
/* Try merging with the block below (but not if we're at the bottom) */
if (mh != (struct mheader *)__heapbase) {
mhprev = M_PREV(mh);
__malloc_trymerge(mhprev, mh);
}
#ifdef MALLOCDEBUG
warnx("free: freed %p", x);
__malloc_dump();
#endif
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright (c) 2014
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/*
* qsort() for OS/161, where it isn't in libc.
*/
void
qsort(void *vdata, unsigned num, size_t size,
int (*f)(const void *, const void *))
{
unsigned pivot, head, tail;
char *data = vdata;
char tmp[size];
#define COMPARE(aa, bb) \
((aa) == (bb) ? 0 : f(data + (aa) * size, data + (bb) * size))
#define EXCHANGE(aa, bb) \
memcpy(tmp, data + (aa) * size, size); \
memcpy(data + (aa) * size, data + (bb) * size, size); \
memcpy(data + (bb) * size, tmp, size)
if (num <= 1) {
return;
}
if (num == 2) {
if (COMPARE(0, 1) > 0) {
EXCHANGE(0, 1);
return;
}
}
/*
* 1. Pick a pivot value. For simplicity, always use the
* middle of the array.
*/
pivot = num / 2;
/*
* 2. Shift all values less than or equal to the pivot value
* to the front of the array.
*/
head = 0;
tail = num - 1;
while (head < tail) {
if (COMPARE(head, pivot) <= 0) {
head++;
}
else if (COMPARE(tail, pivot) > 0) {
tail--;
}
else {
EXCHANGE(head, tail);
if (pivot == head) {
pivot = tail;
}
else if (pivot == tail) {
pivot = head;
}
head++;
tail--;
}
}
/*
* 3. If there's an even number of elements and we swapped the
* last two, the head and tail indexes will cross. In this
* case the first entry on the tail side is tail+1. If there's
* an odd number of elements, we stop with head == tail, and
* the first entry on the tail side is this value (hence,
* tail) if it's is greater than the pivot value, and the next
* element (hence, tail+1) if it's less than or equal to the
* pivot value.
*
* Henceforth use "tail" to hold the index of the first entry
* of the back portion of the array.
*/
if (head > tail || COMPARE(head, pivot) <= 0) {
tail++;
}
/*
* 4. If we got a bad pivot that gave us only one partition,
* because of the order of the advances in the loop above it
* will always put everything in the front portion of the
* array (so tail == num). This happens if we picked the
* largest value. Move the pivot to the end, if necessary, lop
* off all values equal to it, and recurse on the rest. (If
* there is no rest, the array is already sorted and we're
* done.)
*/
if (tail == num) {
if (pivot < num - 1) {
if (COMPARE(pivot, num - 1) > 0) {
EXCHANGE(pivot, num - 1);
}
}
tail = num - 1;
while (tail > 0 && COMPARE(tail - 1, tail) == 0) {
tail--;
}
if (tail > 0) {
qsort(vdata, tail, size, f);
}
return;
}
assert(tail > 0 && tail < num);
/*
* 5. Recurse on each subpart of the array.
*/
qsort(vdata, tail, size, f);
qsort((char *)vdata + tail * size, num - tail, size, f);
}

View File

@@ -0,0 +1,453 @@
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* From:
* NetBSD: random.c,v 1.19 2000/01/22 22:19:20 mycroft Exp
*
* Hacked gruesomely for OS/161.
*/
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
/*
* For a thread-safe libc, declare a lock for this file and change
* these to be nonempty.
*/
#define LOCKME()
#define UNLOCKME()
static void srandom_unlocked(unsigned long);
static long random_unlocked(void);
/*
* random.c:
*
* An improved random number generation package. In addition to the standard
* rand()/srand() like interface, this package also has a special state info
* interface. The initstate() routine is called with a seed, an array of
* bytes, and a count of how many bytes are being passed in; this array is
* then initialized to contain information for random number generation with
* that much state information. Good sizes for the amount of state
* information are 32, 64, 128, and 256 bytes. The state can be switched by
* calling the setstate() routine with the same array as was initiallized
* with initstate(). By default, the package runs with 128 bytes of state
* information and generates far better random numbers than a linear
* congruential generator. If the amount of state information is less than
* 32 bytes, a simple linear congruential R.N.G. is used.
*
* Internally, the state information is treated as an array of longs; the
* zeroeth element of the array is the type of R.N.G. being used (small
* integer); the remainder of the array is the state information for the
* R.N.G. Thus, 32 bytes of state information will give 7 longs worth of
* state information, which will allow a degree seven polynomial. (Note:
* the zeroeth word of state information also has some other information
* stored in it -- see setstate() for details).
*
* The random number generation technique is a linear feedback shift register
* approach, employing trinomials (since there are fewer terms to sum up that
* way). In this approach, the least significant bit of all the numbers in
* the state table will act as a linear feedback shift register, and will
* have period 2^deg - 1 (where deg is the degree of the polynomial being
* used, assuming that the polynomial is irreducible and primitive). The
* higher order bits will have longer periods, since their values are also
* influenced by pseudo-random carries out of the lower bits. The total
* period of the generator is approximately deg*(2**deg - 1); thus doubling
* the amount of state information has a vast influence on the period of the
* generator. Note: the deg*(2**deg - 1) is an approximation only good for
* large deg, when the period of the shift register is the dominant factor.
* With deg equal to seven, the period is actually much longer than the
* 7*(2**7 - 1) predicted by this formula.
*
* Modified 28 December 1994 by Jacob S. Rosenberg.
* The following changes have been made:
* All references to the type u_int have been changed to unsigned long.
* All references to type int have been changed to type long. Other
* cleanups have been made as well. A warning for both initstate and
* setstate has been inserted to the effect that on Sparc platforms
* the 'arg_state' variable must be forced to begin on word boundaries.
* This can be easily done by casting a long integer array to char *.
* The overall logic has been left STRICTLY alone. This software was
* tested on both a VAX and Sun SpacsStation with exactly the same
* results. The new version and the original give IDENTICAL results.
* The new version is somewhat faster than the original. As the
* documentation says: "By default, the package runs with 128 bytes of
* state information and generates far better random numbers than a linear
* congruential generator. If the amount of state information is less than
* 32 bytes, a simple linear congruential R.N.G. is used." For a buffer of
* 128 bytes, this new version runs about 19 percent faster and for a 16
* byte buffer it is about 5 percent faster.
*/
/*
* For each of the currently supported random number generators, we have a
* break value on the amount of state information (you need at least this
* many bytes of state info to support this random number generator), a degree
* for the polynomial (actually a trinomial) that the R.N.G. is based on, and
* the separation between the two lower order coefficients of the trinomial.
*/
#define TYPE_0 0 /* linear congruential */
#define BREAK_0 8
#define DEG_0 0
#define SEP_0 0
#define TYPE_1 1 /* x**7 + x**3 + 1 */
#define BREAK_1 32
#define DEG_1 7
#define SEP_1 3
#define TYPE_2 2 /* x**15 + x + 1 */
#define BREAK_2 64
#define DEG_2 15
#define SEP_2 1
#define TYPE_3 3 /* x**31 + x**3 + 1 */
#define BREAK_3 128
#define DEG_3 31
#define SEP_3 3
#define TYPE_4 4 /* x**63 + x + 1 */
#define BREAK_4 256
#define DEG_4 63
#define SEP_4 1
/*
* Array versions of the above information to make code run faster --
* relies on fact that TYPE_i == i.
*/
#define MAX_TYPES 5 /* max number of types above */
static const int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 };
static const int seps[MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 };
/*
* Initially, everything is set up as if from:
*
* initstate(1, &randtbl, 128);
*
* Note that this initialization takes advantage of the fact that srandom()
* advances the front and rear pointers 10*rand_deg times, and hence the
* rear pointer which starts at 0 will also end up at zero; thus the zeroeth
* element of the state information, which contains info about the current
* position of the rear pointer is just
*
* MAX_TYPES * (rptr - state) + TYPE_3 == TYPE_3.
*/
static long randtbl[DEG_3 + 1] = {
TYPE_3,
(long)0x9a319039L, (long)0x32d9c024L, (long)0x9b663182L,
(long)0x5da1f342L, (long)0xde3b81e0L, (long)0xdf0a6fb5L,
(long)0xf103bc02L, (long)0x48f340fbL, (long)0x7449e56bL,
(long)0xbeb1dbb0L, (long)0xab5c5918L, (long)0x946554fdL,
(long)0x8c2e680fL, (long)0xeb3d799fL, (long)0xb11ee0b7L,
(long)0x2d436b86L, (long)0xda672e2aL, (long)0x1588ca88L,
(long)0xe369735dL, (long)0x904f35f7L, (long)0xd7158fd6L,
(long)0x6fa6f051L, (long)0x616e6b96L, (long)0xac94efdcL,
(long)0x36413f93L, (long)0xc622c298L, (long)0xf5a42ab8L,
(long)0x8a88d77bL, (long)0xf5ad9d0eL, (long)0x8999220bL,
(long)0x27fb47b9L,
};
/*
* fptr and rptr are two pointers into the state info, a front and a rear
* pointer. These two pointers are always rand_sep places aparts, as they
* cycle cyclically through the state information. (Yes, this does mean we
* could get away with just one pointer, but the code for random() is more
* efficient this way). The pointers are left positioned as they would be
* from the call
*
* initstate(1, randtbl, 128);
*
* (The position of the rear pointer, rptr, is really 0 (as explained above
* in the initialization of randtbl) because the state table pointer is set
* to point to randtbl[1] (as explained below).
*/
static long *fptr = &randtbl[SEP_3 + 1];
static long *rptr = &randtbl[1];
/*
* The following things are the pointer to the state information table, the
* type of the current generator, the degree of the current polynomial being
* used, and the separation between the two pointers. Note that for efficiency
* of random(), we remember the first location of the state information, not
* the zeroeth. Hence it is valid to access state[-1], which is used to
* store the type of the R.N.G. Also, we remember the last location, since
* this is more efficient than indexing every time to find the address of
* the last element to see if the front and rear pointers have wrapped.
*/
static long *state = &randtbl[1];
static long rand_type = TYPE_3;
static int rand_deg = DEG_3;
static int rand_sep = SEP_3;
static long *end_ptr = &randtbl[DEG_3 + 1];
/*
* srandom:
*
* Initialize the random number generator based on the given seed. If the
* type is the trivial no-state-information type, just remember the seed.
* Otherwise, initializes state[] based on the given "seed" via a linear
* congruential generator. Then, the pointers are set to known locations
* that are exactly rand_sep places apart. Lastly, it cycles the state
* information a given number of times to get rid of any initial dependencies
* introduced by the L.C.R.N.G. Note that the initialization of randtbl[]
* for default usage relies on values produced by this routine.
*/
static
void
srandom_unlocked(unsigned long x)
{
int i;
if (rand_type == TYPE_0)
state[0] = x;
else {
state[0] = x;
for (i = 1; i < rand_deg; i++)
state[i] = 1103515245L * state[i - 1] + 12345L;
fptr = &state[rand_sep];
rptr = &state[0];
for (i = 0; i < 10 * rand_deg; i++)
(void)random_unlocked();
}
}
void
srandom(unsigned long x)
{
LOCKME();
srandom_unlocked(x);
UNLOCKME();
}
/*
* initstate:
*
* Initialize the state information in the given array of n bytes for future
* random number generation. Based on the number of bytes we are given, and
* the break values for the different R.N.G.'s, we choose the best (largest)
* one we can and set things up for it. srandom() is then called to
* initialize the state information.
*
* Note that on return from srandom(), we set state[-1] to be the type
* multiplexed with the current value of the rear pointer; this is so
* successive calls to initstate() won't lose this information and will be
* able to restart with setstate().
*
* Note: the first thing we do is save the current state, if any, just like
* setstate() so that it doesn't matter when initstate is called.
*
* Returns a pointer to the old state.
*
* Note: The Sparc platform requires that arg_state begin on a long
* word boundary; otherwise a bus error will occur. Even so, lint will
* complain about mis-alignment, but you should disregard these messages.
*/
char *
initstate(
unsigned long seed, /* seed for R.N.G. */
char *arg_state, /* pointer to state array */
size_t n) /* # bytes of state info */
{
void *ostate = (void *)(&state[-1]);
long *long_arg_state;
assert(arg_state != NULL);
long_arg_state = (long *)(void *)arg_state;
LOCKME();
if (rand_type == TYPE_0)
state[-1] = rand_type;
else
state[-1] = MAX_TYPES * (rptr - state) + rand_type;
if (n < BREAK_0) {
UNLOCKME();
return (NULL);
} else if (n < BREAK_1) {
rand_type = TYPE_0;
rand_deg = DEG_0;
rand_sep = SEP_0;
} else if (n < BREAK_2) {
rand_type = TYPE_1;
rand_deg = DEG_1;
rand_sep = SEP_1;
} else if (n < BREAK_3) {
rand_type = TYPE_2;
rand_deg = DEG_2;
rand_sep = SEP_2;
} else if (n < BREAK_4) {
rand_type = TYPE_3;
rand_deg = DEG_3;
rand_sep = SEP_3;
} else {
rand_type = TYPE_4;
rand_deg = DEG_4;
rand_sep = SEP_4;
}
state = (long *) (long_arg_state + 1); /* first location */
end_ptr = &state[rand_deg]; /* must set end_ptr before srandom */
srandom_unlocked(seed);
if (rand_type == TYPE_0)
long_arg_state[0] = rand_type;
else
long_arg_state[0] = MAX_TYPES * (rptr - state) + rand_type;
UNLOCKME();
return((char *)ostate);
}
/*
* setstate:
*
* Restore the state from the given state array.
*
* Note: it is important that we also remember the locations of the pointers
* in the current state information, and restore the locations of the pointers
* from the old state information. This is done by multiplexing the pointer
* location into the zeroeth word of the state information.
*
* Note that due to the order in which things are done, it is OK to call
* setstate() with the same state as the current state.
*
* Returns a pointer to the old state information.
*
* Note: The Sparc platform requires that arg_state begin on a long
* word boundary; otherwise a bus error will occur. Even so, lint will
* complain about mis-alignment, but you should disregard these messages.
*/
char *
setstate(char *arg_state) /* pointer to state array */
{
long *new_state;
int type;
int rear;
void *ostate = (void *)(&state[-1]);
assert(arg_state != NULL);
new_state = (long *)(void *)arg_state;
type = (int)(new_state[0] % MAX_TYPES);
rear = (int)(new_state[0] / MAX_TYPES);
LOCKME();
if (rand_type == TYPE_0)
state[-1] = rand_type;
else
state[-1] = MAX_TYPES * (rptr - state) + rand_type;
switch(type) {
case TYPE_0:
case TYPE_1:
case TYPE_2:
case TYPE_3:
case TYPE_4:
rand_type = type;
rand_deg = degrees[type];
rand_sep = seps[type];
break;
default:
UNLOCKME();
return (NULL);
}
state = (long *) (new_state + 1);
if (rand_type != TYPE_0) {
rptr = &state[rear];
fptr = &state[(rear + rand_sep) % rand_deg];
}
end_ptr = &state[rand_deg]; /* set end_ptr too */
UNLOCKME();
return((char *)ostate);
}
/*
* random:
*
* If we are using the trivial TYPE_0 R.N.G., just do the old linear
* congruential bit. Otherwise, we do our fancy trinomial stuff, which is
* the same in all the other cases due to all the global variables that have
* been set up. The basic operation is to add the number at the rear pointer
* into the one at the front pointer. Then both pointers are advanced to
* the next location cyclically in the table. The value returned is the sum
* generated, reduced to 31 bits by throwing away the "least random" low bit.
*
* Note: the code takes advantage of the fact that both the front and
* rear pointers can't wrap on the same call by not testing the rear
* pointer if the front one has wrapped.
*
* Returns a 31-bit random number.
*/
static
long
random_unlocked(void)
{
long i;
long *f, *r;
if (rand_type == TYPE_0) {
i = state[0];
state[0] = i = (i * 1103515245L + 12345L) & 0x7fffffff;
} else {
/*
* Use local variables rather than static variables for speed.
*/
f = fptr; r = rptr;
*f += *r;
/* chucking least random bit */
i = ((unsigned long)*f >> 1) & 0x7fffffff;
if (++f >= end_ptr) {
f = state;
++r;
}
else if (++r >= end_ptr) {
r = state;
}
fptr = f; rptr = r;
}
return(i);
}
long
random(void)
{
long r;
LOCKME();
r = random_unlocked();
UNLOCKME();
return (r);
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
/*
* system(): ANSI C
*
* Run a command.
*/
#define MAXCMDSIZE 2048
#define MAXARGS 128
int
system(const char *cmd)
{
/*
* Ordinarily, you call the shell to process the command.
* But we don't know that the shell can do that. So, do it
* ourselves.
*/
char tmp[MAXCMDSIZE];
char *argv[MAXARGS+1];
int nargs=0;
char *s;
int pid, status;
if (strlen(cmd) >= sizeof(tmp)) {
errno = E2BIG;
return -1;
}
strcpy(tmp, cmd);
for (s = strtok(tmp, " \t"); s; s = strtok(NULL, " \t")) {
if (nargs < MAXARGS) {
argv[nargs++] = s;
}
else {
errno = E2BIG;
return 1;
}
}
argv[nargs] = NULL;
pid = fork();
switch (pid) {
case -1:
return -1;
case 0:
/* child */
execv(argv[0], argv);
/* exec only returns if it fails */
_exit(255);
default:
/* parent */
waitpid(pid, &status, 0);
return status;
}
}