bash-5.1 distribution sources and documentation

This commit is contained in:
Chet Ramey
2020-12-06 15:51:17 -05:00
parent 36f2c406ff
commit 8868edaf22
828 changed files with 94641 additions and 56509 deletions
+1 -1
View File
@@ -29,7 +29,7 @@ _aindex=0
#
# Declare a function ($1) to be autoloaded from a file ($2) when it is first
# called. This defines a `temporary' function that will `.' the file
# containg the real function definition, then execute that new definition with
# containing the real function definition, then execute that new definition with
# the arguments given to this `fake' function. The autoload function defined
# by the file and the file itself *must* be named identically.
#
+4 -4
View File
@@ -383,7 +383,7 @@ OPTIONS
'theCharCount=\$(wc -c \$theFuncFile)'
for each funcion and
for each function and
if \$theCharCount < \$AUTOLOAD_SHIM_OVERHEAD
@@ -416,7 +416,7 @@ NOTES
backticks or $(), or in a script that is not being sourced into the
current environment. If you have not previously called the function
in question at your command line or in a script that was sourced into
the current envirnoment, then the various subshells are going to
the current environment, then the various subshells are going to
encounter the shim and replace with the real code before executing.
Remember, however, that environment modifications that occur in a
@@ -490,9 +490,9 @@ NOTES
matter how hard you try, your autoloaded functions will be
unavailable to you, even if you run 'autoload -x -f'. The typical
condition for this is starting up not a subshell, but a brand new
DIFFERENT shell. And the typical example of this is git extentions.
DIFFERENT shell. And the typical example of this is git extensions.
At the time of this writing, git extentions work by taking a command
At the time of this writing, git extensions work by taking a command
'git foo' and looking for a file 'git-foo' on the path. 'git' then
executes 'git-foo' in a new shell - it executes your command in
/bin/sh. That's not a subshell of your process. It will not get your
+1 -1
View File
@@ -1,4 +1,4 @@
# C-shell compatabilty package.
# C-shell compatibilty package.
# setenv VAR VALUE
function setenv ()
{
+1 -1
View File
@@ -20,7 +20,7 @@
isnum2()
{
case "$1" in
'[-+]' | '') return 1;; # empty or bare `-' or `+'
[-+] | '') return 1;; # empty or bare `-' or `+'
[-+]*[!0-9]*) return 1;; # non-digit with leading sign
[-+]*) return 0;; # OK
*[!0-9]*) return 1;; # non-digit
+1 -1
View File
@@ -1,6 +1,6 @@
shcat()
{
while read -r line
while IFS= read -r line
do
echo "$line"
done
+2 -2
View File
@@ -1,8 +1,8 @@
shcat()
{
while read -r line
while read -r
do
echo "$line"
echo "$REPLY"
done
}
+1 -1
View File
@@ -17,7 +17,7 @@
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# Sort the positional paramters.
# Sort the positional parameters.
# Make sure the positional parameters are passed as arguments to the function.
# If -u is the first arg, remove duplicate array members.
sort_posparams()
+29 -5
View File
@@ -1,7 +1,7 @@
#
# Simple makefile for the sample loadable builtins
#
# Copyright (C) 1996-2015 Free Software Foundation, Inc.
# Copyright (C) 1996-2019 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -76,7 +76,7 @@ INTL_BUILDDIR = ${LIBBUILD}/intl
INTL_INC = @INTL_INC@
LIBINTL_H = @LIBINTL_H@
CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CFLAGS)
CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CPPFLAGS) $(CFLAGS)
#
# These values are generated for configure by ${topdir}/support/shobj-conf.
@@ -101,9 +101,10 @@ INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins -I${srcdir} \
ALLPROG = print truefalse sleep finfo logname basename dirname fdflags \
tty pathchk tee head mkdir rmdir printenv id whoami \
uname sync push ln unlink realpath strftime mypid setpgid seq
OTHERPROG = necho hello cat pushd stat rm
tty pathchk tee head mkdir rmdir mkfifo mktemp printenv id whoami \
uname sync push ln unlink realpath strftime mypid setpgid seq rm \
accept csv cut
OTHERPROG = necho hello cat pushd stat asort
all: $(SHOBJ_STATUS)
@@ -133,6 +134,9 @@ hello: hello.o
truefalse: truefalse.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ truefalse.o $(SHOBJ_LIBS)
accept: accept.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ accept.o $(SHOBJ_LIBS)
sleep: sleep.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sleep.o $(SHOBJ_LIBS)
@@ -175,6 +179,12 @@ mkdir: mkdir.o
rmdir: rmdir.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ rmdir.o $(SHOBJ_LIBS)
mkfifo: mkfifo.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mkfifo.o $(SHOBJ_LIBS)
mktemp: mktemp.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mktemp.o $(SHOBJ_LIBS)
head: head.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ head.o $(SHOBJ_LIBS)
@@ -205,6 +215,12 @@ unlink: unlink.o
realpath: realpath.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ realpath.o $(SHOBJ_LIBS)
csv: csv.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ csv.o $(SHOBJ_LIBS)
cut: cut.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cut.o $(SHOBJ_LIBS)
strftime: strftime.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ strftime.o $(SHOBJ_LIBS)
@@ -217,6 +233,9 @@ setpgid: setpgid.o
stat: stat.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ stat.o $(SHOBJ_LIBS)
asort: asort.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ asort.o $(SHOBJ_LIBS)
# pushd is a special case. We use the same source that the builtin version
# uses, with special compilation options.
#
@@ -272,6 +291,7 @@ uninstall: uninstall-$(SHOBJ_STATUS)
print.o: print.c
truefalse.o: truefalse.c
accept.o: accept.c
sleep.o: sleep.c
finfo.o: finfo.c
logname.o: logname.c
@@ -285,6 +305,8 @@ rmdir.o: rmdir.c
necho.o: necho.c
hello.o: hello.c
cat.o: cat.c
csv.o: csv.c
cut.o: cut.c
printenv.o: printenv.c
id.o: id.c
whoami.o: whoami.c
@@ -292,9 +314,11 @@ uname.o: uname.c
sync.o: sync.c
push.o: push.c
mkdir.o: mkdir.c
mktemp.o: mktemp.c
realpath.o: realpath.c
strftime.o: strftime.c
setpgid.o: setpgid.c
stat.o: stat.c
fdflags.o: fdflags.c
seq.o: seq.c
asort.o: asort.c
+1 -1
View File
@@ -41,7 +41,7 @@ without having to search for the right CFLAGS and LDFLAGS.
basename.c Return non-directory portion of pathname.
cat.c cat(1) replacement with no options - the way cat was intended.
dirname.c Return directory portion of pathname.
fdflags.c Change the flag associated with one of bash's open file desriptors.
fdflags.c Change the flag associated with one of bash's open file descriptors.
finfo.c Print file info.
head.c Copy first part of files.
hello.c Obligatory "Hello World" / sample loadable.
+234
View File
@@ -0,0 +1,234 @@
/* accept - listen for and accept a remote network connection on a given port */
/*
Copyright (C) 2020 Free Software Foundation, Inc.
This file is part of GNU Bash.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "bashtypes.h"
#include <errno.h>
#include <time.h>
#include "typemax.h"
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "loadables.h"
static int accept_bind_variable (char *, int);
int
accept_builtin (list)
WORD_LIST *list;
{
WORD_LIST *l;
SHELL_VAR *v;
intmax_t iport;
int opt;
char *tmoutarg, *fdvar, *rhostvar, *rhost;
unsigned short uport;
int servsock, clisock;
struct sockaddr_in server, client;
socklen_t clientlen;
struct timeval timeval;
struct linger linger = { 0, 0 };
rhostvar = tmoutarg = fdvar = rhost = (char *)NULL;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "r:t:v:")) != -1)
{
switch (opt)
{
case 'r':
rhostvar = list_optarg;
break;
case 't':
tmoutarg = list_optarg;
break;
case 'v':
fdvar = list_optarg;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
/* Validate input and variables */
if (tmoutarg)
{
long ival, uval;
opt = uconvert (tmoutarg, &ival, &uval, (char **)0);
if (opt == 0 || ival < 0 || uval < 0)
{
builtin_error ("%s: invalid timeout specification", tmoutarg);
return (EXECUTION_FAILURE);
}
timeval.tv_sec = ival;
timeval.tv_usec = uval;
/* XXX - should we warn if ival == uval == 0 ? */
}
if (list == 0)
{
builtin_usage ();
return (EX_USAGE);
}
if (legal_number (list->word->word, &iport) == 0 || iport < 0 || iport > TYPE_MAXIMUM (unsigned short))
{
builtin_error ("%s: invalid port number", list->word->word);
return (EXECUTION_FAILURE);
}
uport = (unsigned short)iport;
if (fdvar == 0)
fdvar = "ACCEPT_FD";
unbind_variable (fdvar);
if (rhostvar)
unbind_variable (rhostvar);
if ((servsock = socket (AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0)
{
builtin_error ("cannot create socket: %s", strerror (errno));
return (EXECUTION_FAILURE);
}
memset ((char *)&server, 0, sizeof (server));
server.sin_family = AF_INET;
server.sin_port = htons(uport);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind (servsock, (struct sockaddr *)&server, sizeof (server)) < 0)
{
builtin_error ("socket bind failure: %s", strerror (errno));
close (servsock);
return (EXECUTION_FAILURE);
}
opt = 1;
setsockopt (servsock, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof (opt));
setsockopt (servsock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof (linger));
if (listen (servsock, 1) < 0)
{
builtin_error ("listen failure: %s", strerror (errno));
close (servsock);
return (EXECUTION_FAILURE);
}
if (tmoutarg)
{
fd_set iofds;
FD_ZERO(&iofds);
FD_SET(servsock, &iofds);
opt = select (servsock+1, &iofds, 0, 0, &timeval);
if (opt < 0)
builtin_error ("select failure: %s", strerror (errno));
if (opt <= 0)
{
close (servsock);
return (EXECUTION_FAILURE);
}
}
clientlen = sizeof (client);
if ((clisock = accept (servsock, (struct sockaddr *)&client, &clientlen)) < 0)
{
builtin_error ("client accept failure: %s", strerror (errno));
close (servsock);
return (EXECUTION_FAILURE);
}
close (servsock);
accept_bind_variable (fdvar, clisock);
if (rhostvar)
{
rhost = inet_ntoa (client.sin_addr);
v = builtin_bind_variable (rhostvar, rhost, 0);
if (v == 0 || readonly_p (v) || noassign_p (v))
builtin_error ("%s: cannot set variable", rhostvar);
}
return (EXECUTION_SUCCESS);
}
static int
accept_bind_variable (varname, intval)
char *varname;
int intval;
{
SHELL_VAR *v;
char ibuf[INT_STRLEN_BOUND (int) + 1], *p;
p = fmtulong (intval, 10, ibuf, sizeof (ibuf), 0);
v = builtin_bind_variable (varname, p, 0);
if (v == 0 || readonly_p (v) || noassign_p (v))
builtin_error ("%s: cannot set variable", varname);
return (v != 0);
}
char *accept_doc[] = {
"Accept a network connection on a specified port.",
""
"This builtin allows a bash script to act as a TCP/IP server.",
"",
"Options, if supplied, have the following meanings:",
" -t timeout wait TIMEOUT seconds for a connection. TIMEOUT may",
" be a decimal number including a fractional portion",
" -v varname store the numeric file descriptor of the connected",
" socket into VARNAME. The default VARNAME is ACCEPT_FD",
" -r rhost store the IP address of the remote host into the shell",
" variable RHOST, in dotted-decimal notation",
"",
"If successful, the shell variable ACCEPT_FD, or the variable named by the",
"-v option, will be set to the fd of the connected socket, suitable for",
"use as 'read -u$ACCEPT_FD'. RHOST, if supplied, will hold the IP address",
"of the remote client. The return status is 0.",
"",
"On failure, the return status is 1 and ACCEPT_FD (or VARNAME) and RHOST,",
"if supplied, will be unset.",
"",
"The server socket fd will be closed before accept returns.",
(char *) NULL
};
struct builtin accept_struct = {
"accept", /* builtin name */
accept_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
accept_doc, /* array of long documentation strings. */
"accept [-t timeout] [-v varname] [-r addrvar ] port", /* usage synopsis; becomes short_doc */
0 /* reserved for internal use */
};
+279
View File
@@ -0,0 +1,279 @@
/*
Copyright (C) 2020 Free Software Foundation, Inc.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "bashtypes.h"
#include "shell.h"
#include "builtins.h"
#include "common.h"
#include "xmalloc.h"
#include "bashgetopt.h"
typedef struct sort_element {
ARRAY_ELEMENT *v; // used when sorting array in-place
char *key; // used when sorting assoc array
char *value; // points to value of array element or assoc entry
double num; // used for numeric sort
} sort_element;
static int reverse_flag;
static int numeric_flag;
static int
compare(const void *p1, const void *p2) {
const sort_element e1 = *(sort_element *) p1;
const sort_element e2 = *(sort_element *) p2;
if (numeric_flag) {
if (reverse_flag)
return (e2.num > e1.num) ? 1 : (e2.num < e1.num) ? -1 : 0;
else
return (e1.num > e2.num) ? 1 : (e1.num < e2.num) ? -1 : 0;
}
else {
if (reverse_flag)
return strcoll(e2.value, e1.value);
else
return strcoll(e1.value, e2.value);
}
}
static int
sort_index(SHELL_VAR *dest, SHELL_VAR *source) {
HASH_TABLE *hash;
BUCKET_CONTENTS *bucket;
sort_element *sa;
ARRAY *array, *dest_array;
ARRAY_ELEMENT *ae;
size_t i, j, n;
char ibuf[INT_STRLEN_BOUND (intmax_t) + 1]; // used by fmtulong
char *key;
dest_array = array_cell(dest);
if (assoc_p(source)) {
hash = assoc_cell(source);
n = hash->nentries;
sa = xmalloc(n * sizeof(sort_element));
i = 0;
for ( j = 0; j < hash->nbuckets; ++j ) {
bucket = hash->bucket_array[j];
while ( bucket ) {
sa[i].v = NULL;
sa[i].key = bucket->key;
if ( numeric_flag )
sa[i].num = strtod(bucket->data, NULL);
else
sa[i].value = bucket->data;
i++;
bucket = bucket->next;
}
}
}
else {
array = array_cell(source);
n = array_num_elements(array);
sa = xmalloc(n * sizeof(sort_element));
i = 0;
for (ae = element_forw(array->head); ae != array->head; ae = element_forw(ae)) {
sa[i].v = ae;
if (numeric_flag)
sa[i].num = strtod(element_value(ae), NULL);
else
sa[i].value = element_value(ae);
i++;
}
}
// sanity check
if ( i != n ) {
builtin_error("%s: corrupt array", source->name);
return EXECUTION_FAILURE;
}
qsort(sa, n, sizeof(sort_element), compare);
array_flush(dest_array);
for ( i = 0; i < n; ++i ) {
if ( assoc_p(source) )
key = sa[i].key;
else
key = fmtulong((long unsigned)sa[i].v->ind, 10, ibuf, sizeof(ibuf), 0);
array_insert(dest_array, i, key);
}
return EXECUTION_SUCCESS;
}
static int
sort_inplace(SHELL_VAR *var) {
size_t i, n;
ARRAY *a;
ARRAY_ELEMENT *ae;
sort_element *sa = 0;
a = array_cell(var);
n = array_num_elements(a);
if ( n == 0 )
return EXECUTION_SUCCESS;
sa = xmalloc(n * sizeof(sort_element));
i = 0;
for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) {
sa[i].v = ae;
if (numeric_flag)
sa[i].num = strtod(element_value(ae), NULL);
else
sa[i].value = element_value(ae);
i++;
}
// sanity check
if ( i != n ) {
builtin_error("%s: corrupt array", var->name);
return EXECUTION_FAILURE;
}
qsort(sa, n, sizeof(sort_element), compare);
// for in-place sort, simply "rewire" the array elements
sa[0].v->prev = sa[n-1].v->next = a->head;
a->head->next = sa[0].v;
a->head->prev = sa[n-1].v;
a->max_index = n - 1;
for (i = 0; i < n; i++) {
sa[i].v->ind = i;
if (i > 0)
sa[i].v->prev = sa[i-1].v;
if (i < n - 1)
sa[i].v->next = sa[i+1].v;
}
xfree(sa);
return EXECUTION_SUCCESS;
}
int
asort_builtin(WORD_LIST *list) {
SHELL_VAR *var, *var2;
char *word;
int opt, ret;
int index_flag = 0;
numeric_flag = 0;
reverse_flag = 0;
reset_internal_getopt();
while ((opt = internal_getopt(list, "inr")) != -1) {
switch (opt) {
case 'i': index_flag = 1; break;
case 'n': numeric_flag = 1; break;
case 'r': reverse_flag = 1; break;
CASE_HELPOPT;
default:
builtin_usage();
return (EX_USAGE);
}
}
list = loptend;
if (list == 0) {
builtin_usage();
return EX_USAGE;
}
if (legal_identifier (list->word->word) == 0) {
sh_invalidid (list->word->word);
return EXECUTION_FAILURE;
}
if ( index_flag ) {
if ( list->next == 0 || list->next->next ) {
builtin_usage();
return EX_USAGE;
}
if (legal_identifier (list->next->word->word) == 0) {
sh_invalidid (list->next->word->word);
return EXECUTION_FAILURE;
}
var = find_or_make_array_variable(list->word->word, 1);
if (var == 0)
return EXECUTION_FAILURE;
var2 = find_variable(list->next->word->word);
if ( !var2 || ( !array_p(var2) && !assoc_p(var2) ) ) {
builtin_error("%s: Not an array", list->next->word->word);
return EXECUTION_FAILURE;
}
return sort_index(var, var2);
}
while (list) {
word = list->word->word;
var = find_variable(word);
list = list->next;
if (var == 0 || array_p(var) == 0) {
builtin_error("%s: Not an array", word);
continue;
}
if (readonly_p(var) || noassign_p(var)) {
if (readonly_p(var))
err_readonly(word);
continue;
}
if ( (ret = sort_inplace(var)) != EXECUTION_SUCCESS )
return ret;
}
return EXECUTION_SUCCESS;
}
char *asort_doc[] = {
"Sort arrays in-place.",
"",
"Options:",
" -n compare according to string numerical value",
" -r reverse the result of comparisons",
" -i sort using indices/keys",
"",
"If -i is supplied, SOURCE is not sorted in-place, but the indices (or keys",
"if associative) of SOURCE, after sorting it by its values, are placed as",
"values in the indexed array DEST",
"",
"Associative arrays may not be sorted in-place.",
"",
"Exit status:",
"Return value is zero unless an error happened (like invalid variable name",
"or readonly array).",
(char *)NULL
};
struct builtin asort_struct = {
"asort",
asort_builtin,
BUILTIN_ENABLED,
asort_doc,
"asort [-nr] array ... or asort [-nr] -i dest source",
0
};
+5 -6
View File
@@ -3,7 +3,7 @@
/* See Makefile for compilation details. */
/*
Copyright (C) 1999-2009 Free Software Foundation, Inc.
Copyright (C) 1999-2020 Free Software Foundation, Inc.
This file is part of GNU Bash.
Bash is free software: you can redistribute it and/or modify
@@ -39,15 +39,14 @@ basename_builtin (list)
int slen, sufflen, off;
char *string, *suffix, *fn;
if (no_options (list))
return (EX_USAGE);
list = loptend;
if (list == 0)
{
builtin_usage ();
return (EX_USAGE);
}
if (no_options (list))
return (EX_USAGE);
list = loptend;
}
string = list->word->word;
suffix = (char *)NULL;
+206
View File
@@ -0,0 +1,206 @@
/* csv - process a line of csv data and populate an indexed array with the
fields */
/*
Copyright (C) 2020 Free Software Foundation, Inc.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
/* See Makefile for compilation details. */
#include <config.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "bashansi.h"
#include <stdio.h>
#include "loadables.h"
#define CSV_ARRAY_DEFAULT "CSV"
#define NQUOTE 0
#define DQUOTE 1
/* Split LINE into comma-separated fields, storing each field into a separate
element of array variable CSV, starting at index 0. The format of LINE is
as described in RFC 4180. */
static int
csvsplit (csv, line)
SHELL_VAR *csv;
char *line;
{
arrayind_t ind;
char *field, *prev, *buf, *xbuf;
int delim, qstate;
int b, rval;
xbuf = 0;
ind = 0;
field = prev = line;
do
{
if (*prev == '"')
{
if (xbuf == 0)
xbuf = xmalloc (strlen (prev) + 1);
buf = xbuf;
b = 0;
qstate = DQUOTE;
for (field = ++prev; *field; field++)
{
if (qstate == DQUOTE && *field == '"' && field[1] == '"')
buf[b++] = *field++; /* skip double quote */
else if (qstate == DQUOTE && *field == '"')
qstate = NQUOTE;
else if (qstate == NQUOTE && *field == ',')
break;
else
/* This copies any text between a closing double quote and the
delimiter. If you want to change that, make sure to do the
copy only if qstate == DQUOTE. */
buf[b++] = *field;
}
buf[b] = '\0';
}
else
{
buf = prev;
field = prev + strcspn (prev, ",");
}
delim = *field;
*field = '\0';
bind_array_element (csv, ind, buf, 0);
ind++;
*field = delim;
if (delim == ',')
prev = field + 1;
}
while (delim == ',');
if (xbuf)
free (xbuf);
return (rval = ind); /* number of fields */
}
int
csv_builtin (list)
WORD_LIST *list;
{
int opt, rval;
char *array_name, *csvstring;
SHELL_VAR *v;
array_name = 0;
rval = EXECUTION_SUCCESS;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "a:")) != -1)
{
switch (opt)
{
case 'a':
array_name = list_optarg;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (array_name == 0)
array_name = CSV_ARRAY_DEFAULT;
if (legal_identifier (array_name) == 0)
{
sh_invalidid (array_name);
return (EXECUTION_FAILURE);
}
if (list == 0)
{
builtin_error ("csv string argument required");
return (EX_USAGE);
}
v = find_or_make_array_variable (array_name, 1);
if (v == 0 || readonly_p (v) || noassign_p (v))
{
if (v && readonly_p (v))
err_readonly (array_name);
return (EXECUTION_FAILURE);
}
else if (array_p (v) == 0)
{
builtin_error ("%s: not an indexed array", array_name);
return (EXECUTION_FAILURE);
}
if (invisible_p (v))
VUNSETATTR (v, att_invisible);
array_flush (array_cell (v));
csvstring = list->word->word;
if (csvstring == 0 || *csvstring == 0)
return (EXECUTION_SUCCESS);
opt = csvsplit (v, csvstring);
/* Maybe do something with OPT here, it's the number of fields */
return (rval);
}
/* Called when builtin is enabled and loaded from the shared object. If this
function returns 0, the load fails. */
int
csv_builtin_load (name)
char *name;
{
return (1);
}
/* Called when builtin is disabled. */
void
csv_builtin_unload (name)
char *name;
{
}
char *csv_doc[] = {
"Read comma-separated fields from a string.",
"",
"Parse STRING, a line of comma-separated values, into individual fields,",
"and store them into the indexed array ARRAYNAME starting at index 0.",
"If ARRAYNAME is not supplied, \"CSV\" is the default array name.",
(char *)NULL
};
struct builtin csv_struct = {
"csv", /* builtin name */
csv_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
csv_doc, /* array of long documentation strings. */
"csv [-a ARRAY] string", /* usage synopsis; becomes short_doc */
0 /* reserved for internal use */
};
+625
View File
@@ -0,0 +1,625 @@
/* cut,lcut - extract specified fields from a line and assign them to an array
or print them to the standard output */
/*
Copyright (C) 2020 Free Software Foundation, Inc.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
/* See Makefile for compilation details. */
#include <config.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "bashansi.h"
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include "loadables.h"
#include "shmbutil.h"
#define CUT_ARRAY_DEFAULT "CUTFIELDS"
#define NOPOS -2 /* sentinel for unset startpos/endpos */
#define BOL 0
#define EOL INT_MAX
#define NORANGE -1 /* just a position, no range */
#define BFLAG (1 << 0)
#define CFLAG (1 << 1)
#define DFLAG (1 << 2)
#define FFLAG (1 << 3)
#define SFLAG (1 << 4)
struct cutpos
{
int startpos, endpos; /* zero-based, correction done in getlist() */
};
struct cutop
{
int flags;
int delim;
int npos;
struct cutpos *poslist;
};
static int
poscmp (a, b)
void *a, *b;
{
struct cutpos *p1, *p2;
p1 = (struct cutpos *)a;
p2 = (struct cutpos *)b;
return (p1->startpos - p2->startpos);
}
static int
getlist (arg, opp)
char *arg;
struct cutpos **opp;
{
char *ntok, *ltok, *larg;
int s, e;
intmax_t num;
struct cutpos *poslist;
int npos, nsize;
poslist = 0;
nsize = npos = 0;
s = e = 0;
larg = arg;
while (ltok = strsep (&larg, ","))
{
if (*ltok == 0)
continue;
ntok = strsep (&ltok, "-");
if (*ntok == 0)
s = BOL;
else
{
if (legal_number (ntok, &num) == 0 || (int)num != num || num <= 0)
{
builtin_error ("%s: invalid list value", ntok);
*opp = poslist;
return -1;
}
s = num;
s--; /* fields are 1-based */
}
if (ltok == 0)
e = NORANGE;
else if (*ltok == 0)
e = EOL;
else
{
if (legal_number (ltok, &num) == 0 || (int)num != num || num <= 0)
{
builtin_error ("%s: invalid list value", ltok);
*opp = poslist;
return -1;
}
e = num;
e--;
if (e == s)
e = NORANGE;
}
if (npos == nsize)
{
nsize += 4;
poslist = (struct cutpos *)xrealloc (poslist, nsize * sizeof (struct cutpos));
}
poslist[npos].startpos = s;
poslist[npos].endpos = e;
npos++;
}
if (npos == 0)
{
builtin_error ("missing list of positions");
*opp = poslist;
return -1;
}
qsort (poslist, npos, sizeof(poslist[0]), poscmp);
*opp = poslist;
return npos;
}
static int
cutbytes (v, line, ops)
SHELL_VAR *v;
char *line;
struct cutop *ops;
{
arrayind_t ind;
char *buf, *bmap;
size_t llen;
int i, b, n, s, e;
llen = strlen (line);
buf = xmalloc (llen + 1);
bmap = xmalloc (llen + 1);
memset (bmap, 0, llen);
for (n = 0; n < ops->npos; n++)
{
s = ops->poslist[n].startpos; /* no translation needed yet */
e = ops->poslist[n].endpos;
if (e == NORANGE)
e = s;
else if (e == EOL || e >= llen)
e = llen - 1;
/* even if a column is specified multiple times, it will only be printed
once */
for (i = s; i <= e; i++)
bmap[i] = 1;
}
b = 0;
for (i = 0; i < llen; i++)
if (bmap[i])
buf[b++] = line[i];
buf[b] = 0;
if (v)
{
ind = 0;
bind_array_element (v, ind, buf, 0);
ind++;
}
else
printf ("%s\n", buf);
free (buf);
free (bmap);
return ind;
}
static int
cutchars (v, line, ops)
SHELL_VAR *v;
char *line;
struct cutop *ops;
{
arrayind_t ind;
char *buf, *bmap;
wchar_t *wbuf, *wb2;
size_t llen, wlen;
int i, b, n, s, e;
if (MB_CUR_MAX == 1)
return (cutbytes (v, line, ops));
if (locale_utf8locale && utf8_mbsmbchar (line) == 0)
return (cutbytes (v, line, ops));
llen = strlen (line);
wbuf = (wchar_t *)xmalloc ((llen + 1) * sizeof (wchar_t));
wlen = mbstowcs (wbuf, line, llen);
if (MB_INVALIDCH (wlen))
{
free (wbuf);
return (cutbytes (v, line, ops));
}
bmap = xmalloc (llen + 1);
memset (bmap, 0, llen);
for (n = 0; n < ops->npos; n++)
{
s = ops->poslist[n].startpos; /* no translation needed yet */
e = ops->poslist[n].endpos;
if (e == NORANGE)
e = s;
else if (e == EOL || e >= wlen)
e = wlen - 1;
/* even if a column is specified multiple times, it will only be printed
once */
for (i = s; i <= e; i++)
bmap[i] = 1;
}
wb2 = (wchar_t *)xmalloc ((wlen + 1) * sizeof (wchar_t));
b = 0;
for (i = 0; i < wlen; i++)
if (bmap[i])
wb2[b++] = wbuf[i];
wb2[b] = 0;
free (wbuf);
buf = bmap;
n = wcstombs (buf, wb2, llen);
if (v)
{
ind = 0;
bind_array_element (v, ind, buf, 0);
ind++;
}
else
printf ("%s\n", buf);
free (buf);
free (wb2);
return ind;
}
/* The basic strategy is to cut the line into fields using strsep, populate
an array of fields from 0..nf, then select those fields using the same
bitmap approach as cut{bytes,chars} and assign them to the array variable
V or print them on stdout. This function obeys SFLAG. */
static int
cutfields (v, line, ops)
SHELL_VAR *v;
char *line;
struct cutop *ops;
{
arrayind_t ind;
char *buf, *bmap, *field, **fields, delim[2];
size_t llen, fsize;
int i, b, n, s, e, nf;
ind = 0;
delim[0] = ops->delim;
delim[1] = '\0';
fields = 0;
nf = 0;
fsize = 0;
field = buf = line;
do
{
field = strsep (&buf, delim); /* destructive */
if (nf == fsize)
{
fsize += 8;
fields = xrealloc (fields, fsize * sizeof (char *));
}
fields[nf] = field;
if (field)
nf++;
}
while (field);
if (nf == 1)
{
free (fields);
if (ops->flags & SFLAG)
return ind;
if (v)
{
bind_array_element (v, ind, line, 0);
ind++;
}
else
printf ("%s\n", line);
return ind;
}
bmap = xmalloc (nf + 1);
memset (bmap, 0, nf);
for (n = 0; n < ops->npos; n++)
{
s = ops->poslist[n].startpos; /* no translation needed yet */
e = ops->poslist[n].endpos;
if (e == NORANGE)
e = s;
else if (e == EOL || e >= nf)
e = nf - 1;
/* even if a column is specified multiple times, it will only be printed
once */
for (i = s; i <= e; i++)
bmap[i] = 1;
}
for (i = 1, b = 0; b < nf; b++)
{
if (bmap[b] == 0)
continue;
if (v)
{
bind_array_element (v, ind, fields[b], 0);
ind++;
}
else
{
if (i == 0)
putchar (ops->delim);
printf ("%s", fields[b]);
}
i = 0;
}
if (v == 0)
putchar ('\n');
return nf;
}
static int
cutline (v, line, ops)
SHELL_VAR *v;
char *line;
struct cutop *ops;
{
int rval;
if (ops->flags & BFLAG)
rval = cutbytes (v, line, ops);
else if (ops->flags & CFLAG)
rval = cutchars (v, line, ops);
else
rval = cutfields (v, line, ops);
return (rval >= 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
}
static int
cutfile (v, list, ops)
SHELL_VAR *v;
WORD_LIST *list;
struct cutop *ops;
{
int fd, unbuffered_read;
char *line, *b;
size_t llen;
WORD_LIST *l;
ssize_t n;
line = 0;
llen = 0;
l = list;
do
{
/* for each file */
if (l == 0 || (l->word->word[0] == '-' && l->word->word[1] == '\0'))
fd = 0;
else
fd = open (l->word->word, O_RDONLY);
if (fd < 0)
{
file_error (l->word->word);
return (EXECUTION_FAILURE);
}
#ifndef __CYGWIN__
unbuffered_read = (lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
#else
unbuffered_read = 1;
#endif
while ((n = zgetline (fd, &line, &llen, '\n', unbuffered_read)) != -1)
cutline (v, line, ops); /* can modify line */
if (fd > 0)
close (fd);
if (l)
l = l->next;
}
while (l);
free (line);
return EXECUTION_SUCCESS;
}
#define OPTSET(x) ((cutflags & (x)) ? 1 : 0)
static int
cut_internal (which, list)
int which; /* not used yet */
WORD_LIST *list;
{
int opt, rval, cutflags, delim, npos;
char *array_name, *cutstring, *list_arg;
SHELL_VAR *v;
struct cutop op;
struct cutpos *poslist;
v = 0;
rval = EXECUTION_SUCCESS;
cutflags = 0;
array_name = 0;
list_arg = 0;
delim = '\t';
reset_internal_getopt ();
while ((opt = internal_getopt (list, "a:b:c:d:f:sn")) != -1)
{
switch (opt)
{
case 'a':
array_name = list_optarg;
break;
case 'b':
cutflags |= BFLAG;
list_arg = list_optarg;
break;
case 'c':
cutflags |= CFLAG;
list_arg = list_optarg;
break;
case 'd':
cutflags |= DFLAG;
delim = list_optarg[0];
if (delim == 0 || list_optarg[1])
{
builtin_error ("delimiter must be a single non-null character");
return (EX_USAGE);
}
break;
case 'f':
cutflags |= FFLAG;
list_arg = list_optarg;
break;
case 'n':
break;
case 's':
cutflags |= SFLAG;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (array_name && (legal_identifier (array_name) == 0))
{
sh_invalidid (array_name);
return (EXECUTION_FAILURE);
}
if (list == 0 && which == 0)
{
builtin_error ("string argument required");
return (EX_USAGE);
}
/* options are mutually exclusive and one is required */
if ((OPTSET (BFLAG) + OPTSET (CFLAG) + OPTSET (FFLAG)) != 1)
{
builtin_usage ();
return (EX_USAGE);
}
if ((npos = getlist (list_arg, &poslist)) < 0)
{
free (poslist);
return (EXECUTION_FAILURE);
}
if (array_name)
{
v = find_or_make_array_variable (array_name, 1);
if (v == 0 || readonly_p (v) || noassign_p (v))
{
if (v && readonly_p (v))
err_readonly (array_name);
return (EXECUTION_FAILURE);
}
else if (array_p (v) == 0)
{
builtin_error ("%s: not an indexed array", array_name);
return (EXECUTION_FAILURE);
}
if (invisible_p (v))
VUNSETATTR (v, att_invisible);
array_flush (array_cell (v));
}
op.flags = cutflags;
op.delim = delim;
op.npos = npos;
op.poslist = poslist;
/* we implement cut as a builtin with a cutfile() function that opens each
filename in LIST as a filename (or `-' for stdin) and runs cutline on
every line in the file. */
if (which == 0)
{
cutstring = list->word->word;
if (cutstring == 0 || *cutstring == 0)
{
free (poslist);
return (EXECUTION_SUCCESS);
}
rval = cutline (v, cutstring, &op);
}
else
rval = cutfile (v, list, &op);
return (rval);
}
int
lcut_builtin (list)
WORD_LIST *list;
{
return (cut_internal (0, list));
}
int
cut_builtin (list)
WORD_LIST *list;
{
return (cut_internal (1, list));
}
char *lcut_doc[] = {
"Extract selected fields from a string.",
"",
"Select portions of LINE (as specified by LIST) and assign them to",
"elements of the indexed array ARRAY starting at index 0, or write",
"them to the standard output if -a is not specified.",
"",
"Items specified by LIST are either column positions or fields delimited",
"by a special character, and are described more completely in cut(1).",
"",
"Columns correspond to bytes (-b), characters (-c), or fields (-f). The",
"field delimiter is specified by -d (default TAB). Column numbering",
"starts at 1.",
(char *)NULL
};
struct builtin lcut_struct = {
"lcut", /* builtin name */
lcut_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
lcut_doc, /* array of long documentation strings. */
"lcut [-a ARRAY] [-b LIST] [-c LIST] [-f LIST] [-d CHAR] [-sn] line", /* usage synopsis; becomes short_doc */
0 /* reserved for internal use */
};
char *cut_doc[] = {
"Extract selected fields from each line of a file.",
"",
"Select portions of each line (as specified by LIST) from each FILE",
"and write them to the standard output. cut reads from the standard",
"input if no FILE arguments are specified or if a FILE argument is a",
"single hyphen.",
"",
"Items specified by LIST are either column positions or fields delimited",
"by a special character, and are described more completely in cut(1).",
"",
"Columns correspond to bytes (-b), characters (-c), or fields (-f). The",
"field delimiter is specified by -d (default TAB). Column numbering",
"starts at 1.",
(char *)NULL
};
struct builtin cut_struct = {
"cut", /* builtin name */
cut_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
cut_doc, /* array of long documentation strings. */
"cut [-a ARRAY] [-b LIST] [-c LIST] [-f LIST] [-d CHAR] [-sn] [file ...]", /* usage synopsis; becomes short_doc */
0 /* reserved for internal use */
};
+39 -1
View File
@@ -3,7 +3,7 @@
/* See Makefile for compilation details. */
/*
Copyright (C) 2017 Free Software Foundation, Inc.
Copyright (C) 2017,2018,2019 Free Software Foundation, Inc.
This file is part of GNU Bash.
Bash is free software: you can redistribute it and/or modify
@@ -32,6 +32,10 @@
#include "loadables.h"
#ifndef FD_CLOEXEC
# define FD_CLOEXEC 1
#endif
static const struct
{
const char *name;
@@ -40,37 +44,69 @@ static const struct
{
#ifdef O_APPEND
{ "append", O_APPEND },
#else
# define O_APPEND 0
#endif
#ifdef O_ASYNC
{ "async", O_ASYNC },
#else
# define O_ASYNC 0
#endif
#ifdef O_SYNC
{ "sync", O_SYNC },
#else
# define O_SYNC 0
#endif
#ifdef O_NONBLOCK
{ "nonblock", O_NONBLOCK },
#else
# define O_NONBLOCK 0
#endif
#ifdef O_FSYNC
{ "fsync", O_FSYNC },
#else
# define O_FSYNC 0
#endif
#ifdef O_DSYNC
{ "dsync", O_DSYNC },
#else
# define O_DSYNC 0
#endif
#ifdef O_RSYNC
{ "rsync", O_RSYNC },
#else
# define O_RSYNC 0
#endif
#ifdef O_ALT_IO
{ "altio", O_ALT_IO },
#else
# define O_ALT_IO 0
#endif
#ifdef O_DIRECT
{ "direct", O_DIRECT },
#else
# define O_DIRECT 0
#endif
#ifdef O_NOATIME
{ "noatime", O_NOATIME },
#else
# define O_NOATIME 0
#endif
#ifdef O_NOSIGPIPE
{ "nosigpipe", O_NOSIGPIPE },
#else
# define O_NOSIGPIPE 0
#endif
#ifndef O_CLOEXEC
# define ALLFLAGS (O_APPEND|O_ASYNC|O_SYNC|O_NONBLOCK|O_FSYNC|O_DSYNC|\
O_RSYNC|O_ALT_IO|O_DIRECT|O_NOATIME|O_NOSIGPIPE)
/* An unsed bit in the file status flags word we can use to pass around the
state of close-on-exec. */
# define O_CLOEXEC ((~ALLFLAGS) ^ ((~ALLFLAGS) & ((~ALLFLAGS) - 1)))
#endif
#ifdef O_CLOEXEC
{ "cloexec", O_CLOEXEC },
#endif
@@ -199,10 +235,12 @@ setone(int fd, char *v, int verbose)
parseflags(v, &pos, &neg);
cloexec = -1;
if ((pos & O_CLOEXEC) && (f & O_CLOEXEC) == 0)
cloexec = FD_CLOEXEC;
if ((neg & O_CLOEXEC) && (f & O_CLOEXEC))
cloexec = 0;
if (cloexec != -1 && fcntl(fd, F_SETFD, cloexec) == -1)
builtin_error("can't set status for fd %d: %s", fd, strerror(errno));
+9 -3
View File
@@ -28,6 +28,12 @@
#endif
#include <sys/types.h>
#ifdef MAJOR_IN_MKDEV
# include <sys/mkdev.h>
#endif
#ifdef MAJOR_IN_SYSMACROS
# include <sys/sysmacros.h>
#endif
#include "posixstat.h"
#include <stdio.h>
#include <pwd.h>
@@ -334,13 +340,13 @@ int flags;
else
printf("%ld\n", st->st_ctime);
} else if (flags & OPT_DEV)
printf("%d\n", st->st_dev);
printf("%lu\n", (unsigned long)st->st_dev);
else if (flags & OPT_INO)
printf("%lu\n", (unsigned long)st->st_ino);
else if (flags & OPT_FID)
printf("%d:%lu\n", st->st_dev, (unsigned long)st->st_ino);
printf("%lu:%lu\n", (unsigned long)st->st_dev, (unsigned long)st->st_ino);
else if (flags & OPT_NLINK)
printf("%d\n", st->st_nlink);
printf("%lu\n", (unsigned long)st->st_nlink);
else if (flags & OPT_LNKNAM) {
#ifdef S_ISLNK
b = xmalloc(4096);
+2 -2
View File
@@ -3,7 +3,7 @@
/* See Makefile for compilation details. */
/*
Copyright (C) 1999-2009 Free Software Foundation, Inc.
Copyright (C) 1999-2020 Free Software Foundation, Inc.
This file is part of GNU Bash.
Bash is free software: you can redistribute it and/or modify
@@ -42,7 +42,7 @@
extern int errno;
#endif
typedef int unix_link_syscall_t __P((const char *, const char *));
typedef int unix_link_syscall_t PARAMS((const char *, const char *));
#define LN_SYMLINK 0x01
#define LN_UNLINK 0x02
+1 -1
View File
@@ -93,7 +93,7 @@ mkdir_builtin (list)
return (EXECUTION_FAILURE);
}
}
else if (mode)
else /* symbolic mode */
{
/* initial bits are a=rwx; the mode argument modifies them */
omode = parse_symbolic_mode (mode, S_IRWXU | S_IRWXG | S_IRWXO);
+146
View File
@@ -0,0 +1,146 @@
/* mkfifo - make FIFOs */
/* See Makefile for compilation details. */
/*
Copyright (C) 1999-2020 Free Software Foundation, Inc.
This file is part of GNU Bash.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "bashtypes.h"
#include "posixstat.h"
#include <errno.h>
#include <stdio.h>
#include "bashansi.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "builtins.h"
#include "shell.h"
#include "bashgetopt.h"
#include "common.h"
#if !defined (errno)
extern int errno;
#endif
#define ISOCTAL(c) ((c) >= '0' && (c) <= '7')
extern int parse_symbolic_mode ();
static int original_umask;
int
mkfifo_builtin (list)
WORD_LIST *list;
{
int opt, mflag, omode, rval, nmode, basemode;
char *mode;
WORD_LIST *l;
mflag = 0;
mode = (char *)NULL;
reset_internal_getopt ();
while ((opt = internal_getopt(list, "m:")) != -1)
switch (opt)
{
case 'm':
mflag = 1;
mode = list_optarg;
break;
CASE_HELPOPT;
default:
builtin_usage();
return (EX_USAGE);
}
list = loptend;
if (list == 0)
{
builtin_usage ();
return (EX_USAGE);
}
basemode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
if (mode == NULL)
omode = basemode;
else if (ISOCTAL (*mode)) /* octal number */
{
omode = read_octal (mode);
if (omode < 0)
{
builtin_error ("invalid file mode: %s", mode);
return (EXECUTION_FAILURE);
}
}
else /* symbolic mode */
{
/* initial bits are a=rwx; the mode argument modifies them */
omode = parse_symbolic_mode (mode, basemode);
if (omode < 0)
{
builtin_error ("invalid file mode: %s", mode);
return (EXECUTION_FAILURE);
}
}
/* Make the new mode */
original_umask = umask (0);
umask (original_umask);
nmode = basemode & ~original_umask;
/* Adjust new mode based on mode argument */
nmode &= omode;
for (rval = EXECUTION_SUCCESS, l = list; l; l = l->next)
{
if (mkfifo (l->word->word, nmode) < 0)
{
builtin_error ("cannot create FIFO `%s': %s", l->word->word, strerror (errno));
rval = EXECUTION_FAILURE;
}
}
return rval;
}
char *mkfifo_doc[] = {
"Create FIFOs (named pipes).",
"",
"Make FIFOs. Create the FIFOs named as arguments, in",
"the order specified, using mode a=rw as modified by the current",
"umask (see `help umask'). The -m option causes the file permission",
"bits of the final FIFO to be MODE. The MODE argument may be",
"an octal number or a symbolic mode like that used by chmod(1). If",
"a symbolic mode is used, the operations are interpreted relative to",
"an initial mode of \"a=rw\". mkfifo returns 0 if the FIFOs are",
"umask, plus write and search permissions for the owner. mkdir",
"created successfully, and non-zero if an error occurs.",
(char *)NULL
};
struct builtin mkfifo_struct = {
"mkfifo",
mkfifo_builtin,
BUILTIN_ENABLED,
mkfifo_doc,
"mkfifo [-m mode] fifo_name [fifo_name ...]",
0
};
+212
View File
@@ -0,0 +1,212 @@
/* mktemp - create temporary file or directory */
/*
Copyright (C) 2019 Free Software Foundation, Inc.
This file is part of GNU Bash.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
#include "bashansi.h"
#include "loadables.h"
#define DEFAULT_PREFIX "shtmp"
int
mktemp_builtin (list)
WORD_LIST *list;
{
WORD_LIST *l;
int rval, opt, fd, mflags, base_mflags;
int dflag, qflag, tflag, uflag, onetime;
char *prefix, *varname, *filename, *template;
SHELL_VAR *v;
dflag = qflag = uflag = tflag = onetime = 0;
prefix = varname = 0;
rval = EXECUTION_SUCCESS;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "dqut:v:")) != -1)
{
switch (opt)
{
case 'd':
dflag = 1;
break;
case 'q':
qflag = 1;
break;
case 't':
tflag = 1;
prefix = list_optarg;
break;
case 'u':
uflag = 1;
break;
case 'v':
varname = list_optarg;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (varname) /* check for validity, not readonly */
{
if (legal_identifier (varname) == 0)
{
if (qflag == 0)
sh_invalidid (varname);
return (EXECUTION_FAILURE);
}
v = find_variable (varname);
if (v && readonly_p (v))
{
if (qflag == 0)
sh_readonly (varname);
return (EXECUTION_FAILURE);
}
}
onetime = (list == 0); /* once through the loop, $TMPDIR/prefix.XXXXXX */
if (prefix == 0)
prefix = DEFAULT_PREFIX;
base_mflags = MT_USETMPDIR|MT_USERANDOM; /* USERANDOM not strictly needed */
while (list || onetime)
{
mflags = base_mflags;
onetime = 0;
#if defined (USE_MKTEMP) && defined (USE_MKSTEMP)
if (list)
{
template = list->word->word;
mflags |= MT_TEMPLATE;
}
#else
/* This is sub-optimal. */
if (list)
{
/* Treat the basename as a prefix */
template = strrchr (list->word->word, '/');
if (template)
template++;
else
template = list->word->word;
}
#endif
else
template = prefix;
if (dflag)
{
filename = sh_mktmpdir (template, mflags);
if (filename == 0)
{
if (qflag == 0)
builtin_error ("%s: cannot create directory", template);
rval = EXECUTION_FAILURE;
}
else
{
if (uflag)
rmdir (filename);
printf ("%s\n", filename);
}
}
else /* filename */
{
fd = sh_mktmpfd (template, mflags, &filename);
if (fd < 0)
{
if (qflag == 0)
builtin_error ("%s: cannot create file", template);
rval = EXECUTION_FAILURE;
}
else
{
close (fd);
if (uflag)
unlink (filename);
printf ("%s\n", filename);
}
}
/* Assign variable if requested */
if (filename && varname)
{
v = builtin_bind_variable (varname, filename, 0);
if (v == 0 || readonly_p (v) || noassign_p (v))
{
builtin_error ("%s: cannot set variable", varname);
rval = EXECUTION_FAILURE;
}
}
FREE (filename);
if (list)
list = list->next;
}
return (rval);
}
char *mktemp_doc[] = {
"Make unique temporary file name",
"",
"Take each supplied filename template and overwrite a portion of it",
"to create a filename, which is unique and may be used by the calling",
"script. TEMPLATE is a string ending in some number of 'X's. If",
"TEMPLATE is not supplied, shtmp.XXXXXX is used and $TMPDIR is used as",
"the name of the containing directory. Files are created u+rw; directories",
"are created u+rwx.",
"",
"Options, if supplied, have the following meanings:",
"",
" -d Create a directory instead of a file",
" -q Do not print error messages about file creation failure",
" -t PREFIX Use PREFIX as the directory in which to create files",
" -u Do not create anything; simply print a name",
" -v VAR Store the generated name into shell variable VAR",
"",
"Any PREFIX supplied with -t is ignored if TEMPLATE is supplied.",
"",
"The return status is true if the file or directory was created successfully;",
"false if an error occurs or VAR is invalid or readonly.",
(char *)NULL
};
struct builtin mktemp_struct = {
"mktemp", /* builtin name */
mktemp_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
mktemp_doc, /* array of long documentation strings. */
"mktemp [-d] [-q] [-t prefix] [-u] [-v varname] [template] ...",
0 /* reserved for internal use */
};
+3 -3
View File
@@ -4,7 +4,7 @@
*/
/*
Copyright (C) 1999-2009 Free Software Foundation, Inc.
Copyright (C) 1999-2020 Free Software Foundation, Inc.
This file is part of GNU Bash.
Bash is free software: you can redistribute it and/or modify
@@ -35,7 +35,7 @@
extern int errno;
#endif
extern int dollar_dollar_pid;
extern pid_t dollar_dollar_pid;
extern int last_command_exit_value;
int
@@ -92,7 +92,7 @@ push_builtin (list)
else
{
stop_pipeline (0, (COMMAND *)NULL);
xstatus = wait_for (pid);
xstatus = wait_for (pid, 0);
return (xstatus);
}
}
+1 -1
View File
@@ -130,7 +130,7 @@ char *realpath_doc[] = {
"Display the canonicalized version of each PATHNAME argument, resolving",
"symbolic links. The -c option checks whether or not each resolved name",
"exists. The -s option produces no output; the exit status determines the",
"valididty of each PATHNAME. The -v option produces verbose output. The",
"validity of each PATHNAME. The -v option produces verbose output. The",
"exit status is 0 if each PATHNAME was resolved; non-zero otherwise.",
(char *)NULL
};
+6 -2
View File
@@ -145,8 +145,12 @@ rm_builtin (list)
if (list == 0)
{
builtin_usage ();
return (EXECUTION_FAILURE);
if (force == 0)
{
builtin_usage ();
return (EXECUTION_FAILURE);
}
return (EXECUTION_SUCCESS);
}
for (l = list; l; l = l->next)
+4 -4
View File
@@ -1,5 +1,5 @@
/* seq - print sequence of numbers to standard output.
Copyright (C) 2018 Free Software Foundation, Inc.
Copyright (C) 2018-2020 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -49,8 +49,8 @@ typedef double floatmax_t;
# define FLOATMAX_FMT "%g"
# define FLOATMAX_WFMT "%0.f"
#endif
static floatmax_t getfloatmax __P((const char *));
static char *genformat __P((floatmax_t, floatmax_t, floatmax_t));
static floatmax_t getfloatmax PARAMS((const char *));
static char *genformat PARAMS((floatmax_t, floatmax_t, floatmax_t));
#define MAX(a, b) (((a) < (b))? (b) : (a))
@@ -238,7 +238,7 @@ print_fltseq (fmt, first, last, incr)
floatmax_t next;
const char *s;
n = 0; /* interation counter */
n = 0; /* iteration counter */
s = "";
for (next = first; incr >= 0 ? (next <= last) : (next >= last); next = first + n * incr)
{
+1 -1
View File
@@ -105,7 +105,7 @@ const char *setpgid_doc[] = {
"invoke the setpgid(2) system call",
"",
"Arguments:",
" pid : numeric process identifer, >= 0",
" pid : numeric process identifier, >= 0",
" pgrpid: numeric process group identifier, >=0",
"See the setpgid(2) manual page.",
(const char *)NULL
+9 -2
View File
@@ -5,7 +5,7 @@
*/
/*
Copyright (C) 1999-2009 Free Software Foundation, Inc.
Copyright (C) 1999-2020 Free Software Foundation, Inc.
This file is part of GNU Bash.
Bash is free software: you can redistribute it and/or modify
@@ -53,6 +53,9 @@ sleep_builtin (list)
WORD_LIST *list;
{
long sec, usec;
char *ep;
int r, mul;
time_t t;
if (list == 0) {
builtin_usage();
@@ -68,8 +71,12 @@ WORD_LIST *list;
return (EX_USAGE);
}
if (uconvert(list->word->word, &sec, &usec)) {
r = uconvert(list->word->word, &sec, &usec, &ep);
/* Maybe postprocess conversion failures here based on EP */
if (r) {
fsleep(sec, usec);
QUIT;
return(EXECUTION_SUCCESS);
}
+8 -5
View File
@@ -34,6 +34,7 @@
#include "builtins.h"
#include "shell.h"
#include "common.h"
#include "bashgetopt.h"
int
strftime_builtin (list)
@@ -46,15 +47,16 @@ strftime_builtin (list)
int n;
intmax_t i;
if (no_options (list))
return (EX_USAGE);
list = loptend;
if (list == 0)
{
builtin_usage ();
return (EX_USAGE);
}
if (no_options (list))
return (EX_USAGE);
format = list->word->word;
if (format == 0 || *format == 0)
{
@@ -86,7 +88,7 @@ strftime_builtin (list)
/* Now try to figure out how big the buffer should really be. strftime(3)
will return the number of bytes placed in the buffer unless it's greater
than MAXSIZE, in which case it returns 0. */
for (n = 1; n < 4; n++)
for (n = 1; n <= 8; n++)
{
tbuf = xrealloc (tbuf, tbsize * n);
tsize = strftime (tbuf, tbsize * n, format, t);
@@ -94,7 +96,8 @@ strftime_builtin (list)
break;
}
printf ("%s\n", tbuf);
if (tsize)
printf ("%s\n", tbuf);
free (tbuf);
return (EXECUTION_SUCCESS);
+1 -1
View File
@@ -164,7 +164,7 @@ char *tee_doc[] = {
"Duplicate standard output.",
"",
"Copy standard input to standard output, making a copy in each",
"filename argument. If the `-a' option is gived, the specified",
"filename argument. If the `-a' option is given, the specified",
"files are appended to, otherwise they are overwritten. If the",
"`-i' option is supplied, tee ignores interrupts.",
(char *)NULL
+1 -1
View File
@@ -17,7 +17,7 @@ alias pu="pushd"
alias po="popd"
#
# Csh compatability:
# Csh compatibility:
#
alias unsetenv=unset
function setenv () {