/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1991, 19934* The Regents of the University of California. All rights reserved.5*6* This code is derived from software contributed to Berkeley by7* Kenneth Almquist.8*9* Redistribution and use in source and binary forms, with or without10* modification, are permitted provided that the following conditions11* are met:12* 1. Redistributions of source code must retain the above copyright13* notice, this list of conditions and the following disclaimer.14* 2. Redistributions in binary form must reproduce the above copyright15* notice, this list of conditions and the following disclaimer in the16* documentation and/or other materials provided with the distribution.17* 3. Neither the name of the University nor the names of its contributors18* may be used to endorse or promote products derived from this software19* without specific prior written permission.20*21* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND22* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE23* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE24* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE25* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL26* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS27* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)28* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT29* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY30* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF31* SUCH DAMAGE.32*/3334#include <sys/param.h>35#include "shell.h"36#include "output.h"37#include "memalloc.h"38#include "error.h"39#include "mystring.h"40#include "expand.h"41#include <stdlib.h>42#include <unistd.h>4344static void45badalloc(const char *message)46{47write(2, message, strlen(message));48abort();49}5051/*52* Like malloc, but returns an error when out of space.53*/5455pointer56ckmalloc(size_t nbytes)57{58pointer p;5960if (!is_int_on())61badalloc("Unsafe ckmalloc() call\n");62p = malloc(nbytes);63if (p == NULL)64error("Out of space");65return p;66}676869/*70* Same for realloc.71*/7273pointer74ckrealloc(pointer p, int nbytes)75{76if (!is_int_on())77badalloc("Unsafe ckrealloc() call\n");78p = realloc(p, nbytes);79if (p == NULL)80error("Out of space");81return p;82}8384void85ckfree(pointer p)86{87if (!is_int_on())88badalloc("Unsafe ckfree() call\n");89free(p);90}919293/*94* Make a copy of a string in safe storage.95*/9697char *98savestr(const char *s)99{100char *p;101size_t len;102103len = strlen(s);104p = ckmalloc(len + 1);105memcpy(p, s, len + 1);106return p;107}108109110/*111* Parse trees for commands are allocated in lifo order, so we use a stack112* to make this more efficient, and also to avoid all sorts of exception113* handling code to handle interrupts in the middle of a parse.114*115* The size 496 was chosen because with 16-byte alignment the total size116* for the allocated block is 512.117*/118119#define MINSIZE 496 /* minimum size of a block. */120121122struct stack_block {123struct stack_block *prev;124/* Data follows */125};126#define SPACE(sp) ((char*)(sp) + ALIGN(sizeof(struct stack_block)))127128static struct stack_block *stackp;129char *stacknxt;130int stacknleft;131char *sstrend;132133134static void135stnewblock(int nbytes)136{137struct stack_block *sp;138int allocsize;139140if (nbytes < MINSIZE)141nbytes = MINSIZE;142143allocsize = ALIGN(sizeof(struct stack_block)) + ALIGN(nbytes);144145INTOFF;146sp = ckmalloc(allocsize);147sp->prev = stackp;148stacknxt = SPACE(sp);149stacknleft = allocsize - (stacknxt - (char*)sp);150sstrend = stacknxt + stacknleft;151stackp = sp;152INTON;153}154155156pointer157stalloc(int nbytes)158{159char *p;160161nbytes = ALIGN(nbytes);162if (nbytes > stacknleft)163stnewblock(nbytes);164p = stacknxt;165stacknxt += nbytes;166stacknleft -= nbytes;167return p;168}169170171void172stunalloc(pointer p)173{174if (p == NULL) { /*DEBUG */175write(STDERR_FILENO, "stunalloc\n", 10);176abort();177}178stacknleft += stacknxt - (char *)p;179stacknxt = p;180}181182183char *184stsavestr(const char *s)185{186char *p;187size_t len;188189len = strlen(s);190p = stalloc(len + 1);191memcpy(p, s, len + 1);192return p;193}194195196void197setstackmark(struct stackmark *mark)198{199mark->stackp = stackp;200mark->stacknxt = stacknxt;201mark->stacknleft = stacknleft;202/* Ensure this block stays in place. */203if (stackp != NULL && stacknxt == SPACE(stackp))204stalloc(1);205}206207208void209popstackmark(struct stackmark *mark)210{211struct stack_block *sp;212213INTOFF;214while (stackp != mark->stackp) {215sp = stackp;216stackp = sp->prev;217ckfree(sp);218}219stacknxt = mark->stacknxt;220stacknleft = mark->stacknleft;221if (stacknleft != 0)222sstrend = stacknxt + stacknleft;223else224sstrend = stacknxt;225INTON;226}227228229/*230* When the parser reads in a string, it wants to stick the string on the231* stack and only adjust the stack pointer when it knows how big the232* string is. Stackblock (defined in stack.h) returns a pointer to a block233* of space on top of the stack and stackblocklen returns the length of234* this block. Growstackblock will grow this space by at least one byte,235* possibly moving it (like realloc). Grabstackblock actually allocates the236* part of the block that has been used.237*/238239static void240growstackblock(int min)241{242char *p;243int newlen;244char *oldspace;245int oldlen;246struct stack_block *sp;247struct stack_block *oldstackp;248249if (min < stacknleft)250min = stacknleft;251if ((unsigned int)min >=252INT_MAX / 2 - ALIGN(sizeof(struct stack_block)))253error("Out of space");254min += stacknleft;255min += ALIGN(sizeof(struct stack_block));256newlen = 512;257while (newlen < min)258newlen <<= 1;259oldspace = stacknxt;260oldlen = stacknleft;261262if (stackp != NULL && stacknxt == SPACE(stackp)) {263INTOFF;264oldstackp = stackp;265stackp = oldstackp->prev;266sp = ckrealloc((pointer)oldstackp, newlen);267sp->prev = stackp;268stackp = sp;269stacknxt = SPACE(sp);270stacknleft = newlen - (stacknxt - (char*)sp);271sstrend = stacknxt + stacknleft;272INTON;273} else {274newlen -= ALIGN(sizeof(struct stack_block));275p = stalloc(newlen);276if (oldlen != 0)277memcpy(p, oldspace, oldlen);278stunalloc(p);279}280}281282283284/*285* The following routines are somewhat easier to use than the above.286* The user declares a variable of type STACKSTR, which may be declared287* to be a register. The macro STARTSTACKSTR initializes things. Then288* the user uses the macro STPUTC to add characters to the string. In289* effect, STPUTC(c, p) is the same as *p++ = c except that the stack is290* grown as necessary. When the user is done, she can just leave the291* string there and refer to it using stackblock(). Or she can allocate292* the space for it using grabstackstr(). If it is necessary to allow293* someone else to use the stack temporarily and then continue to grow294* the string, the user should use grabstack to allocate the space, and295* then call ungrabstr(p) to return to the previous mode of operation.296*297* USTPUTC is like STPUTC except that it doesn't check for overflow.298* CHECKSTACKSPACE can be called before USTPUTC to ensure that there299* is space for at least one character.300*/301302static char *303growstrstackblock(int n, int min)304{305growstackblock(min);306return stackblock() + n;307}308309char *310growstackstr(void)311{312int len;313314len = stackblocksize();315return (growstrstackblock(len, 0));316}317318319/*320* Called from CHECKSTRSPACE.321*/322323char *324makestrspace(int min, char *p)325{326int len;327328len = p - stackblock();329return (growstrstackblock(len, min));330}331332333char *334stputbin(const char *data, size_t len, char *p)335{336CHECKSTRSPACE(len, p);337memcpy(p, data, len);338return (p + len);339}340341char *342stputs(const char *data, char *p)343{344return (stputbin(data, strlen(data), p));345}346347348