Adding upstream version 5.2.37.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
This commit is contained in:
parent
cf91100bce
commit
fa1b3d3922
1435 changed files with 757174 additions and 0 deletions
335
examples/loadables/Makefile.in
Normal file
335
examples/loadables/Makefile.in
Normal file
|
@ -0,0 +1,335 @@
|
|||
#
|
||||
# Simple makefile for the sample loadable builtins
|
||||
#
|
||||
# Copyright (C) 1996-2022 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
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
PACKAGE = @PACKAGE_NAME@
|
||||
VERSION = @PACKAGE_VERSION@
|
||||
|
||||
# Include some boilerplate Gnu makefile definitions.
|
||||
prefix = @prefix@
|
||||
|
||||
exec_prefix = @exec_prefix@
|
||||
bindir = @bindir@
|
||||
libdir = @libdir@
|
||||
infodir = @infodir@
|
||||
includedir = @includedir@
|
||||
|
||||
datarootdir = @datarootdir@
|
||||
|
||||
loadablesdir = @loadablesdir@
|
||||
headersdir = @headersdir@
|
||||
|
||||
topdir = @top_srcdir@
|
||||
BUILD_DIR = @BUILD_DIR@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
# Support an alternate destination root directory for package building
|
||||
DESTDIR =
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALLMODE= -m 0755
|
||||
|
||||
@SET_MAKE@
|
||||
CC = @CC@
|
||||
RM = rm -f
|
||||
|
||||
SHELL = @MAKE_SHELL@
|
||||
|
||||
host_os = @host_os@
|
||||
host_cpu = @host_cpu@
|
||||
host_vendor = @host_vendor@
|
||||
|
||||
STYLE_CFLAGS = @STYLE_CFLAGS@
|
||||
CFLAGS = @CFLAGS@
|
||||
LOCAL_CFLAGS = @LOCAL_CFLAGS@
|
||||
DEFS = @DEFS@
|
||||
LOCAL_DEFS = @LOCAL_DEFS@
|
||||
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
|
||||
BASHINCDIR = ${topdir}/include
|
||||
|
||||
SUPPORT_SRC = $(topdir)/support/
|
||||
|
||||
LIBBUILD = ${BUILD_DIR}/lib
|
||||
|
||||
INTL_LIBSRC = ${topdir}/lib/intl
|
||||
INTL_BUILDDIR = ${LIBBUILD}/intl
|
||||
INTL_INC = @INTL_INC@
|
||||
LIBINTL_H = @LIBINTL_H@
|
||||
|
||||
CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CPPFLAGS) $(CFLAGS) $(STYLE_CFLAGS)
|
||||
|
||||
#
|
||||
# These values are generated for configure by ${topdir}/support/shobj-conf.
|
||||
# If your system is not supported by that script, but includes facilities for
|
||||
# dynamic loading of shared objects, please update the script and send the
|
||||
# changes to bash-maintainers@gnu.org.
|
||||
#
|
||||
SHOBJ_CC = @SHOBJ_CC@
|
||||
SHOBJ_CFLAGS = @SHOBJ_CFLAGS@
|
||||
SHOBJ_LD = @SHOBJ_LD@
|
||||
SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@ @LDFLAGS@
|
||||
SHOBJ_XLDFLAGS = @SHOBJ_XLDFLAGS@
|
||||
SHOBJ_LIBS = @SHOBJ_LIBS@
|
||||
SHOBJ_STATUS = @SHOBJ_STATUS@
|
||||
|
||||
INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins -I${srcdir} \
|
||||
-I$(BASHINCDIR) -I$(BUILD_DIR) -I$(LIBBUILD) \
|
||||
-I$(BUILD_DIR)/builtins $(INTL_INC)
|
||||
|
||||
.c.o:
|
||||
$(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CCFLAGS) $(INC) -c -o $@ $<
|
||||
|
||||
|
||||
ALLPROG = print truefalse sleep finfo logname basename dirname fdflags \
|
||||
tty pathchk tee head mkdir rmdir mkfifo mktemp printenv id whoami \
|
||||
uname sync push ln unlink realpath strftime mypid setpgid seq rm \
|
||||
accept csv dsv cut stat getconf
|
||||
OTHERPROG = necho hello cat pushd asort
|
||||
|
||||
all: $(SHOBJ_STATUS)
|
||||
|
||||
supported: $(ALLPROG)
|
||||
others: $(OTHERPROG)
|
||||
|
||||
unsupported:
|
||||
@echo "Your system (${host_os}) is not supported by the"
|
||||
@echo "${topdir}/support/shobj-conf script."
|
||||
@echo "If your operating system provides facilities for dynamic"
|
||||
@echo "loading of shared objects using the dlopen(3) interface,"
|
||||
@echo "please update the script and re-run configure."
|
||||
@echo "Please send the changes you made to bash-maintainers@gnu.org"
|
||||
@echo "for inclusion in future bash releases."
|
||||
|
||||
everything: supported others
|
||||
|
||||
print: print.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ print.o $(SHOBJ_LIBS)
|
||||
|
||||
necho: necho.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ necho.o $(SHOBJ_LIBS)
|
||||
|
||||
hello: hello.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ hello.o $(SHOBJ_LIBS)
|
||||
|
||||
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)
|
||||
|
||||
finfo: finfo.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ finfo.o $(SHOBJ_LIBS)
|
||||
|
||||
cat: cat.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cat.o $(SHOBJ_LIBS)
|
||||
|
||||
rm: rm.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ rm.o $(SHOBJ_LIBS)
|
||||
|
||||
fdflags: fdflags.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ fdflags.o $(SHOBJ_LIBS)
|
||||
|
||||
seq: seq.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ seq.o $(SHOBJ_LIBS)
|
||||
|
||||
logname: logname.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ logname.o $(SHOBJ_LIBS)
|
||||
|
||||
basename: basename.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ basename.o $(SHOBJ_LIBS)
|
||||
|
||||
dirname: dirname.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ dirname.o $(SHOBJ_LIBS)
|
||||
|
||||
tty: tty.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tty.o $(SHOBJ_LIBS)
|
||||
|
||||
pathchk: pathchk.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pathchk.o $(SHOBJ_LIBS)
|
||||
|
||||
tee: tee.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tee.o $(SHOBJ_LIBS)
|
||||
|
||||
mkdir: mkdir.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mkdir.o $(SHOBJ_LIBS)
|
||||
|
||||
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)
|
||||
|
||||
printenv: printenv.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ printenv.o $(SHOBJ_LIBS)
|
||||
|
||||
getconf: getconf.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ getconf.o $(SHOBJ_LIBS)
|
||||
|
||||
id: id.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ id.o $(SHOBJ_LIBS)
|
||||
|
||||
whoami: whoami.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ whoami.o $(SHOBJ_LIBS)
|
||||
|
||||
uname: uname.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ uname.o $(SHOBJ_LIBS)
|
||||
|
||||
sync: sync.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sync.o $(SHOBJ_LIBS)
|
||||
|
||||
push: push.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ push.o $(SHOBJ_LIBS)
|
||||
|
||||
ln: ln.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ ln.o $(SHOBJ_LIBS)
|
||||
|
||||
unlink: unlink.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ unlink.o $(SHOBJ_LIBS)
|
||||
|
||||
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)
|
||||
|
||||
dsv: dsv.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ dsv.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)
|
||||
|
||||
mypid: mypid.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mypid.o $(SHOBJ_LIBS)
|
||||
|
||||
setpgid: setpgid.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ setpgid.o $(SHOBJ_LIBS)
|
||||
|
||||
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.
|
||||
#
|
||||
pushd.c: ${topdir}/builtins/pushd.def
|
||||
$(RM) $@
|
||||
${BUILD_DIR}/builtins/mkbuiltins -D ${topdir}/builtins ${topdir}/builtins/pushd.def
|
||||
|
||||
pushd.o: pushd.c
|
||||
$(RM) $@
|
||||
$(SHOBJ_CC) -Wno-format-security -DHAVE_CONFIG_H -DPUSHD_AND_POPD -DLOADABLE_BUILTIN $(SHOBJ_CFLAGS) $(CFLAGS) $(CPPFLAGS) $(INC) -c -o $@ $<
|
||||
|
||||
pushd: pushd.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pushd.o $(SHOBJ_LIBS)
|
||||
|
||||
clean:
|
||||
$(RM) $(ALLPROG) $(OTHERPROG) *.o
|
||||
-( cd perl && ${MAKE} ${MFLAGS} $@ )
|
||||
|
||||
mostlyclean: clean
|
||||
-( cd perl && ${MAKE} ${MFLAGS} $@ )
|
||||
|
||||
distclean maintainer-clean: clean
|
||||
$(RM) Makefile Makefile.inc Makefile.sample pushd.c
|
||||
-( cd perl && ${MAKE} ${MFLAGS} $@ )
|
||||
|
||||
installdirs:
|
||||
@${SHELL} $(SUPPORT_SRC)mkinstalldirs $(DESTDIR)$(loadablesdir)
|
||||
|
||||
install-dev: installdirs
|
||||
@$(INSTALL_DATA) Makefile.inc $(DESTDIR)$(loadablesdir)/Makefile.inc
|
||||
@$(INSTALL_DATA) Makefile.sample $(DESTDIR)$(loadablesdir)/Makefile.sample
|
||||
@$(INSTALL_DATA) $(srcdir)/loadables.h $(DESTDIR)$(loadablesdir)/loadables.h
|
||||
@( cd $(BUILD_DIR) && ${MAKE} ${MFLAGS} DESTDIR="$(DESTDIR)" install-headers)
|
||||
|
||||
install-supported: all installdirs install-dev
|
||||
@echo installing example loadable builtins in $(DESTDIR)${loadablesdir}
|
||||
@for prog in ${ALLPROG}; do \
|
||||
echo $$prog ; \
|
||||
$(INSTALL_PROGRAM) $(INSTALLMODE) $$prog $(DESTDIR)$(loadablesdir)/$$prog ;\
|
||||
done
|
||||
|
||||
uninstall-dev:
|
||||
-$(RM) $(DESTDIR)$(loadablesdir)/Makefile.inc $(DESTDIR)$(loadablesdir)/Makefile.sample
|
||||
-$(RM) $(DESTDIR)$(loadablesdir)/loadables.h
|
||||
-( cd $(BUILD_DIR) && ${MAKE} ${MFLAGS} DESTDIR="$(DESTDIR)" uninstall-headers)
|
||||
|
||||
uninstall-supported: uninstall-dev
|
||||
-( cd $(DESTDIR)${loadablesdir} && $(RM) ${ALLPROG} )
|
||||
|
||||
install-unsupported:
|
||||
uninstall-unsupported:
|
||||
|
||||
install: install-$(SHOBJ_STATUS)
|
||||
uninstall: uninstall-$(SHOBJ_STATUS)
|
||||
|
||||
print.o: print.c
|
||||
truefalse.o: truefalse.c
|
||||
accept.o: accept.c
|
||||
sleep.o: sleep.c
|
||||
finfo.o: finfo.c
|
||||
getconf.o: getconf.c getconf.h
|
||||
logname.o: logname.c
|
||||
basename.o: basename.c
|
||||
dirname.o: dirname.c
|
||||
tty.o: tty.c
|
||||
pathchk.o: pathchk.c
|
||||
tee.o: tee.c
|
||||
head.o: head.c
|
||||
rmdir.o: rmdir.c
|
||||
necho.o: necho.c
|
||||
hello.o: hello.c
|
||||
cat.o: cat.c
|
||||
csv.o: csv.c
|
||||
dsv.o: dsv.c
|
||||
cut.o: cut.c
|
||||
printenv.o: printenv.c
|
||||
id.o: id.c
|
||||
whoami.o: whoami.c
|
||||
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
|
101
examples/loadables/Makefile.inc.in
Normal file
101
examples/loadables/Makefile.inc.in
Normal file
|
@ -0,0 +1,101 @@
|
|||
#
|
||||
# Sample makefile for bash loadable builtin development
|
||||
#
|
||||
# Copyright (C) 2015-2022 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
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
PACKAGE = @PACKAGE_NAME@
|
||||
VERSION = @PACKAGE_VERSION@
|
||||
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
|
||||
# Include some boilerplate Gnu makefile definitions.
|
||||
prefix = @prefix@
|
||||
|
||||
exec_prefix = @exec_prefix@
|
||||
bindir = @bindir@
|
||||
libdir = @libdir@
|
||||
infodir = @infodir@
|
||||
includedir = @includedir@
|
||||
|
||||
datarootdir = @datarootdir@
|
||||
|
||||
loadablesdir = @loadablesdir@
|
||||
headersdir = @headersdir@
|
||||
|
||||
topdir = @top_srcdir@
|
||||
BUILD_DIR = @BUILD_DIR@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
# Support an alternate destination root directory for package building
|
||||
DESTDIR =
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALLMODE= -m 0755
|
||||
|
||||
@SET_MAKE@
|
||||
CC = @CC@
|
||||
RM = rm -f
|
||||
|
||||
SHELL = @MAKE_SHELL@
|
||||
|
||||
host_os = @host_os@
|
||||
host_cpu = @host_cpu@
|
||||
host_vendor = @host_vendor@
|
||||
|
||||
CFLAGS = @CFLAGS@
|
||||
LOCAL_CFLAGS = @LOCAL_CFLAGS@
|
||||
DEFS = @DEFS@
|
||||
LOCAL_DEFS = @LOCAL_DEFS@
|
||||
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
|
||||
BASHINCDIR = ${topdir}/include
|
||||
|
||||
SUPPORT_SRC = $(topdir)/support/
|
||||
|
||||
LIBBUILD = ${BUILD_DIR}/lib
|
||||
|
||||
INTL_LIBSRC = ${topdir}/lib/intl
|
||||
INTL_BUILDDIR = ${LIBBUILD}/intl
|
||||
INTL_INC = @INTL_INC@
|
||||
LIBINTL_H = @LIBINTL_H@
|
||||
|
||||
CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CFLAGS)
|
||||
|
||||
#
|
||||
# These values are generated for configure by ${topdir}/support/shobj-conf.
|
||||
# If your system is not supported by that script, but includes facilities for
|
||||
# dynamic loading of shared objects, please update the script and send the
|
||||
# changes to bash-maintainers@gnu.org.
|
||||
#
|
||||
SHOBJ_CC = @SHOBJ_CC@
|
||||
SHOBJ_CFLAGS = @SHOBJ_CFLAGS@
|
||||
SHOBJ_LD = @SHOBJ_LD@
|
||||
SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@ @LDFLAGS@
|
||||
SHOBJ_XLDFLAGS = @SHOBJ_XLDFLAGS@
|
||||
SHOBJ_LIBS = @SHOBJ_LIBS@
|
||||
SHOBJ_STATUS = @SHOBJ_STATUS@
|
||||
|
||||
INC = -I$(headersdir) -I$(headersdir)/include -I$(headersdir)/builtins
|
||||
|
||||
.c.o:
|
||||
$(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CCFLAGS) $(INC) -c -o $@ $<
|
44
examples/loadables/Makefile.sample.in
Normal file
44
examples/loadables/Makefile.sample.in
Normal file
|
@ -0,0 +1,44 @@
|
|||
#
|
||||
# Sample makefile for bash loadable builtin development
|
||||
#
|
||||
# Copyright (C) 2022 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
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# these should match the ones in Makefile.in (for the make install target)
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
libdir = @libdir@
|
||||
|
||||
# ${loadablesdir} is where the example loadable builtins and data files
|
||||
# are installed (make install target in Makefile.in)
|
||||
|
||||
loadablesdir = @loadablesdir@
|
||||
DESTDIR =
|
||||
|
||||
# include Makefile.inc for all boilerplate definitions
|
||||
|
||||
include $(DESTDIR)$(loadablesdir)/Makefile.inc
|
||||
|
||||
# here, `example' is the name of the shared object
|
||||
# replace `example' with the appropriate filename
|
||||
|
||||
all: example
|
||||
|
||||
example: example.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ example.o $(SHOBJ_LIBS)
|
||||
|
||||
example.o: example.c
|
82
examples/loadables/README
Normal file
82
examples/loadables/README
Normal file
|
@ -0,0 +1,82 @@
|
|||
Some examples of ready-to-dynamic-load builtins. Most of the
|
||||
examples given are reimplementations of standard commands whose
|
||||
execution time is dominated by process startup time. Some
|
||||
exceptions are sleep, which allows you to sleep for fractions
|
||||
of a second, finfo, which provides access to the rest of the
|
||||
elements of the `stat' structure that `test' doesn't let you
|
||||
see, csv, which allows you to manipulate data from comma-separated
|
||||
values files, fdflags, which lets you change the flags associated
|
||||
with one of the shell's file descriptors, and pushd/popd/dirs, which
|
||||
allows you to compile them out of the shell.
|
||||
|
||||
All of the new builtins in ksh93 that bash didn't already have
|
||||
are included here, as is the ksh `print' builtin.
|
||||
|
||||
The configure script in the top-level source directory uses the
|
||||
support/shobj-conf script to set the right values in the Makefile,
|
||||
so you should not need to change the Makefile. If your system
|
||||
is not supported by support/shobj-conf, and it has the necessary
|
||||
facilities for building shared objects and support for the
|
||||
dlopen/dlsyn/dlclose/dlerror family of functions, please make
|
||||
the necessary changes to support/shobj-conf and send the changes
|
||||
to bash-maintainers@gnu.org.
|
||||
|
||||
Loadable builtins are loaded into a running shell with
|
||||
|
||||
enable -f filename builtin-name
|
||||
|
||||
enable uses a simple reference-counting scheme to avoid unloading a
|
||||
shared object that implements more than one loadable builtin before
|
||||
all loadable builtins implemented in the object are removed.
|
||||
|
||||
Many of the details needed by builtin writers are found in hello.c,
|
||||
the canonical example. There is no real `builtin writers' programming
|
||||
guide'. The file template.c provides a template to use for creating
|
||||
new loadable builtins.
|
||||
|
||||
The file "Makefile.inc" is created using the same values that configure
|
||||
writes into Makefile.in, and is installed in the same directory as the
|
||||
rest of the example builtins. It's intended to be a start at something
|
||||
that can be modified or included to help you build your own loadables
|
||||
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.
|
||||
csv.c Process a line of csv data and store it in an indexed array.
|
||||
cut.c Cut out selected portions of each line of a file.
|
||||
dirname.c Return directory portion of pathname.
|
||||
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.
|
||||
id.c POSIX.2 user identity.
|
||||
ln.c Make links.
|
||||
loadables.h File loadable builtins can include for shell definitions.
|
||||
logname.c Print login name of current user.
|
||||
Makefile.in Simple makefile for the sample loadable builtins.
|
||||
Makefile.inc.in Sample makefile to use for loadable builtin development.
|
||||
mkdir.c Make directories.
|
||||
mkfifo.c Create named pipes.
|
||||
mktemp.c Make unique temporary file name.
|
||||
mypid.c Add $MYPID variable, demonstrate use of unload hook function.
|
||||
necho.c echo without options or argument interpretation.
|
||||
pathchk.c Check pathnames for validity and portability.
|
||||
print.c Loadable ksh-93 style print builtin.
|
||||
printenv.c Minimal builtin clone of BSD printenv(1).
|
||||
push.c Anyone remember TOPS-20?
|
||||
realpath.c Canonicalize pathnames, resolving symlinks.
|
||||
rm.c Remove files and directories.
|
||||
rmdir.c Remove directory.
|
||||
seq.c Print a sequence of decimal or floating point numbers.
|
||||
setpgid.c Set a process's pgrp; example of how to wrap a system call.
|
||||
sleep.c sleep for fractions of a second.
|
||||
stat.c populate an associative array with information about a file
|
||||
strftime.c Loadable builtin interface to strftime(3).
|
||||
sync.c Sync the disks by forcing pending filesystem writes to complete.
|
||||
tee.c Duplicate standard input.
|
||||
template.c Example template for loadable builtin.
|
||||
truefalse.c True and false builtins.
|
||||
tty.c Return terminal name.
|
||||
uname.c Print system information.
|
||||
unlink.c Remove a directory entry.
|
||||
whoami.c Print out username of current user.
|
245
examples/loadables/accept.c
Normal file
245
examples/loadables/accept.c
Normal file
|
@ -0,0 +1,245 @@
|
|||
/* 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 <limits.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;
|
||||
{
|
||||
SHELL_VAR *v;
|
||||
intmax_t iport;
|
||||
int opt;
|
||||
char *tmoutarg, *fdvar, *rhostvar, *rhost, *bindaddr;
|
||||
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 = bindaddr = (char *)NULL;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "b:r:t:v:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'b':
|
||||
bindaddr = list_optarg;
|
||||
break;
|
||||
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 = bindaddr ? inet_addr (bindaddr) : htonl(INADDR_ANY);
|
||||
|
||||
if (server.sin_addr.s_addr == INADDR_NONE)
|
||||
{
|
||||
builtin_error ("invalid address: %s", strerror (errno));
|
||||
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 (bind (servsock, (struct sockaddr *)&server, sizeof (server)) < 0)
|
||||
{
|
||||
builtin_error ("socket bind failure: %s", strerror (errno));
|
||||
close (servsock);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
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); /* XXX */
|
||||
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:",
|
||||
" -b address use ADDRESS as the IP address to listen on; the",
|
||||
" default is INADDR_ANY",
|
||||
" -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 [-b address] [-t timeout] [-v varname] [-r addrvar ] port", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
279
examples/loadables/asort.c
Normal file
279
examples/loadables/asort.c
Normal 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
|
||||
};
|
131
examples/loadables/basename.c
Normal file
131
examples/loadables/basename.c
Normal file
|
@ -0,0 +1,131 @@
|
|||
/* basename - return nondirectory portion of pathname */
|
||||
|
||||
/* 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"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
int
|
||||
basename_builtin (list)
|
||||
WORD_LIST *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);
|
||||
}
|
||||
|
||||
string = list->word->word;
|
||||
suffix = (char *)NULL;
|
||||
if (list->next)
|
||||
{
|
||||
list = list->next;
|
||||
suffix = list->word->word;
|
||||
}
|
||||
|
||||
if (list->next)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
slen = strlen (string);
|
||||
|
||||
/* Strip trailing slashes */
|
||||
while (slen > 0 && string[slen - 1] == '/')
|
||||
slen--;
|
||||
|
||||
/* (2) If string consists entirely of slash characters, string shall be
|
||||
set to a single slash character. In this case, skip steps (3)
|
||||
through (5). */
|
||||
if (slen == 0)
|
||||
{
|
||||
fputs ("/\n", stdout);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* (3) If there are any trailing slash characters in string, they
|
||||
shall be removed. */
|
||||
string[slen] = '\0';
|
||||
|
||||
/* (4) If there are any slash characters remaining in string, the prefix
|
||||
of string up to an including the last slash character in string
|
||||
shall be removed. */
|
||||
while (--slen >= 0)
|
||||
if (string[slen] == '/')
|
||||
break;
|
||||
|
||||
fn = string + slen + 1;
|
||||
|
||||
/* (5) If the suffix operand is present, is not identical to the
|
||||
characters remaining in string, and is identical to a suffix
|
||||
of the characters remaining in string, the suffix suffix
|
||||
shall be removed from string. Otherwise, string shall not be
|
||||
modified by this step. */
|
||||
if (suffix)
|
||||
{
|
||||
sufflen = strlen (suffix);
|
||||
slen = strlen (fn);
|
||||
if (sufflen < slen)
|
||||
{
|
||||
off = slen - sufflen;
|
||||
if (strcmp (fn + off, suffix) == 0)
|
||||
fn[off] = '\0';
|
||||
}
|
||||
}
|
||||
printf ("%s\n", fn);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *basename_doc[] = {
|
||||
"Return non-directory portion of pathname.",
|
||||
"",
|
||||
"The STRING is converted to a filename corresponding to the last",
|
||||
"pathname component in STRING. If the suffix string SUFFIX is",
|
||||
"supplied, it is removed.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
/* The standard structure describing a builtin command. bash keeps an array
|
||||
of these structures. */
|
||||
struct builtin basename_struct = {
|
||||
"basename", /* builtin name */
|
||||
basename_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
basename_doc, /* array of long documentation strings. */
|
||||
"basename string [suffix]", /* usage synopsis */
|
||||
0 /* reserved for internal use */
|
||||
};
|
138
examples/loadables/cat.c
Normal file
138
examples/loadables/cat.c
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* cat replacement
|
||||
*
|
||||
* no options - the way cat was intended
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009,2022 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 <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
extern char *strerror ();
|
||||
extern char **make_builtin_argv ();
|
||||
|
||||
static int
|
||||
fcopy(fd, fn)
|
||||
int fd;
|
||||
char *fn;
|
||||
{
|
||||
char buf[4096], *s;
|
||||
int n, w, e;
|
||||
|
||||
while (n = read(fd, buf, sizeof (buf))) {
|
||||
if (n < 0) {
|
||||
e = errno;
|
||||
write(2, "cat: read error: ", 18);
|
||||
write(2, fn, strlen(fn));
|
||||
write(2, ": ", 2);
|
||||
s = strerror(e);
|
||||
write(2, s, strlen(s));
|
||||
write(2, "\n", 1);
|
||||
return 1;
|
||||
}
|
||||
QUIT;
|
||||
w = write(1, buf, n);
|
||||
if (w != n) {
|
||||
e = errno;
|
||||
write(2, "cat: write error: ", 18);
|
||||
s = strerror(e);
|
||||
write(2, s, strlen(s));
|
||||
write(2, "\n", 1);
|
||||
return 1;
|
||||
}
|
||||
QUIT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
cat_main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int i, fd, r;
|
||||
char *s;
|
||||
|
||||
if (argc == 1)
|
||||
return (fcopy(0, "standard input"));
|
||||
|
||||
for (i = r = 1; i < argc; i++) {
|
||||
QUIT;
|
||||
if (argv[i][0] == '-' && argv[i][1] == '\0')
|
||||
fd = 0;
|
||||
else {
|
||||
fd = open(argv[i], O_RDONLY, 0666);
|
||||
if (fd < 0) {
|
||||
s = strerror(errno);
|
||||
write(2, "cat: cannot open ", 17);
|
||||
write(2, argv[i], strlen(argv[i]));
|
||||
write(2, ": ", 2);
|
||||
write(2, s, strlen(s));
|
||||
write(2, "\n", 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
r = fcopy(fd, argv[i]);
|
||||
if (fd != 0)
|
||||
close(fd);
|
||||
}
|
||||
QUIT;
|
||||
return (r);
|
||||
}
|
||||
|
||||
int
|
||||
cat_builtin(list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char **v;
|
||||
int c, r;
|
||||
|
||||
v = make_builtin_argv(list, &c);
|
||||
QUIT;
|
||||
r = cat_main(c, v);
|
||||
free(v);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *cat_doc[] = {
|
||||
"Display files.",
|
||||
"",
|
||||
"Read each FILE and display it on the standard output. If any",
|
||||
"FILE is `-' or if no FILE argument is given, the standard input",
|
||||
"is read.",
|
||||
(char *)0
|
||||
};
|
||||
|
||||
struct builtin cat_struct = {
|
||||
"cat",
|
||||
cat_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
cat_doc,
|
||||
"cat [-] [file ...]",
|
||||
0
|
||||
};
|
206
examples/loadables/csv.c
Normal file
206
examples/loadables/csv.c
Normal 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, dstring)
|
||||
SHELL_VAR *csv;
|
||||
char *line, *dstring;
|
||||
{
|
||||
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 == *dstring)
|
||||
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, dstring);
|
||||
}
|
||||
|
||||
delim = *field;
|
||||
*field = '\0';
|
||||
|
||||
bind_array_element (csv, ind, buf, 0);
|
||||
ind++;
|
||||
|
||||
*field = delim;
|
||||
|
||||
if (delim == *dstring)
|
||||
prev = field + 1;
|
||||
}
|
||||
while (delim == *dstring);
|
||||
|
||||
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 */
|
||||
};
|
631
examples/loadables/cut.c
Normal file
631
examples/loadables/cut.c
Normal file
|
@ -0,0 +1,631 @@
|
|||
/* 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 (<ok, "-");
|
||||
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)
|
||||
{
|
||||
QUIT;
|
||||
if (line[n] == '\n')
|
||||
line[n] = '\0'; /* cutline expects no newline terminator */
|
||||
cutline (v, line, ops); /* can modify line */
|
||||
}
|
||||
if (fd > 0)
|
||||
close (fd);
|
||||
|
||||
QUIT;
|
||||
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 */
|
||||
};
|
119
examples/loadables/dirname.c
Normal file
119
examples/loadables/dirname.c
Normal file
|
@ -0,0 +1,119 @@
|
|||
/* dirname - return directory portion of pathname */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
int
|
||||
dirname_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int slen;
|
||||
char *string;
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
list = loptend;
|
||||
|
||||
if (list == 0 || list->next)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
string = list->word->word;
|
||||
slen = strlen (string);
|
||||
|
||||
/* Strip trailing slashes */
|
||||
while (slen > 0 && string[slen - 1] == '/')
|
||||
slen--;
|
||||
|
||||
/* (2) If string consists entirely of slash characters, string shall be
|
||||
set to a single slash character. In this case, skip steps (3)
|
||||
through (8). */
|
||||
if (slen == 0)
|
||||
{
|
||||
fputs ("/\n", stdout);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* (3) If there are any trailing slash characters in string, they
|
||||
shall be removed. */
|
||||
string[slen] = '\0';
|
||||
|
||||
/* (4) If there are no slash characters remaining in string, string
|
||||
shall be set to a single period character. In this case, skip
|
||||
steps (5) through (8).
|
||||
|
||||
(5) If there are any trailing nonslash characters in string,
|
||||
they shall be removed. */
|
||||
|
||||
while (--slen >= 0)
|
||||
if (string[slen] == '/')
|
||||
break;
|
||||
|
||||
if (slen < 0)
|
||||
{
|
||||
fputs (".\n", stdout);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* (7) If there are any trailing slash characters in string, they
|
||||
shall be removed. */
|
||||
while (--slen >= 0)
|
||||
if (string[slen] != '/')
|
||||
break;
|
||||
string[++slen] = '\0';
|
||||
|
||||
/* (8) If the remaining string is empty, string shall be set to a single
|
||||
slash character. */
|
||||
printf ("%s\n", (slen == 0) ? "/" : string);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *dirname_doc[] = {
|
||||
"Display directory portion of pathname.",
|
||||
"",
|
||||
"The STRING is converted to the name of the directory containing",
|
||||
"the filename corresponding to the last pathname component in STRING.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
/* The standard structure describing a builtin command. bash keeps an array
|
||||
of these structures. */
|
||||
struct builtin dirname_struct = {
|
||||
"dirname", /* builtin name */
|
||||
dirname_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
dirname_doc, /* array of long documentation strings. */
|
||||
"dirname string", /* usage synopsis */
|
||||
0 /* reserved for internal use */
|
||||
};
|
300
examples/loadables/dsv.c
Normal file
300
examples/loadables/dsv.c
Normal file
|
@ -0,0 +1,300 @@
|
|||
/* dsv - process a line of delimiter-separated data and populate an indexed
|
||||
array with the fields */
|
||||
|
||||
/*
|
||||
Copyright (C) 2022 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 DSV_ARRAY_DEFAULT "DSV"
|
||||
|
||||
#define NQUOTE 0
|
||||
#define DQUOTE 1
|
||||
#define SQUOTE 2
|
||||
|
||||
#define F_SHELLQUOTE 0x01
|
||||
#define F_GREEDY 0x02
|
||||
#define F_PRESERVE 0x04
|
||||
|
||||
/* Split LINE into delimiter-separated fields, storing each field into a
|
||||
separate element of array variable DSV, starting at index 0. The format
|
||||
of LINE is delimiter-separated values. By default, this splits lines of
|
||||
CSV data as described in RFC 4180. If *DSTRING is any other value than
|
||||
',', this uses that character as a field delimiter. Pass F_SHELLQUOTE in
|
||||
FLAGS to understand shell-like double-quoting and backslash-escaping in
|
||||
double quotes instead of the "" CSV behavior, and shell-like single quotes.
|
||||
Pass F_GREEDY in FLAGS to consume multiple leading and trailing instances
|
||||
of *DSTRING and consecutive instances of *DSTRING in LINE without creating
|
||||
null fields. If you want to preserve the quote characters in the generated
|
||||
fields, pass F_PRESERVE; by default, this removes them. */
|
||||
static int
|
||||
dsvsplit (dsv, line, dstring, flags)
|
||||
SHELL_VAR *dsv;
|
||||
char *line, *dstring;
|
||||
int flags;
|
||||
{
|
||||
arrayind_t ind;
|
||||
char *field, *prev, *buf, *xbuf;
|
||||
int delim, qstate;
|
||||
int b, rval;
|
||||
|
||||
xbuf = 0;
|
||||
ind = 0;
|
||||
field = prev = line;
|
||||
|
||||
/* If we want a greedy split, consume leading instances of *DSTRING */
|
||||
if (flags & F_GREEDY)
|
||||
{
|
||||
while (*prev == *dstring)
|
||||
prev++;
|
||||
field = prev;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (*prev == '"')
|
||||
{
|
||||
if (xbuf == 0)
|
||||
xbuf = xmalloc (strlen (prev) + 1);
|
||||
buf = xbuf;
|
||||
b = 0;
|
||||
if (flags & F_PRESERVE)
|
||||
buf[b++] = *prev;
|
||||
qstate = DQUOTE;
|
||||
for (field = ++prev; *field; field++)
|
||||
{
|
||||
if (qstate == DQUOTE && *field == '"' && field[1] == '"' && (flags & F_SHELLQUOTE) == 0)
|
||||
buf[b++] = *field++; /* skip double quote */
|
||||
else if (qstate == DQUOTE && (flags & F_SHELLQUOTE) && *field == '\\' && strchr (slashify_in_quotes, field[1]) != 0)
|
||||
buf[b++] = *++field; /* backslash quoted double quote */
|
||||
else if (qstate == DQUOTE && *field == '"')
|
||||
{
|
||||
qstate = NQUOTE;
|
||||
if (flags & F_PRESERVE)
|
||||
buf[b++] = *field;
|
||||
}
|
||||
else if (qstate == NQUOTE && *field == *dstring)
|
||||
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 if ((flags & F_SHELLQUOTE) && *prev == '\'')
|
||||
{
|
||||
if (xbuf == 0)
|
||||
xbuf = xmalloc (strlen (prev) + 1);
|
||||
buf = xbuf;
|
||||
b = 0;
|
||||
if (flags & F_PRESERVE)
|
||||
buf[b++] = *prev;
|
||||
qstate = SQUOTE;
|
||||
for (field = ++prev; *field; field++)
|
||||
{
|
||||
if (qstate == SQUOTE && *field == '\'')
|
||||
{
|
||||
qstate = NQUOTE;
|
||||
if (flags & F_PRESERVE)
|
||||
buf[b++] = *field;
|
||||
}
|
||||
else if (qstate == NQUOTE && *field == *dstring)
|
||||
break;
|
||||
else
|
||||
/* This copies any text between a closing single quote and the
|
||||
delimiter. If you want to change that, make sure to do the
|
||||
copy only if qstate == SQUOTE. */
|
||||
buf[b++] = *field;
|
||||
}
|
||||
buf[b] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
buf = prev;
|
||||
field = prev + strcspn (prev, dstring);
|
||||
}
|
||||
|
||||
delim = *field;
|
||||
*field = '\0';
|
||||
|
||||
if ((flags & F_GREEDY) == 0 || buf[0])
|
||||
{
|
||||
bind_array_element (dsv, ind, buf, 0);
|
||||
ind++;
|
||||
}
|
||||
|
||||
*field = delim;
|
||||
|
||||
if (delim == *dstring)
|
||||
prev = field + 1;
|
||||
}
|
||||
while (delim == *dstring);
|
||||
|
||||
if (xbuf)
|
||||
free (xbuf);
|
||||
|
||||
return (rval = ind); /* number of fields */
|
||||
}
|
||||
|
||||
int
|
||||
dsv_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt, rval, flags;
|
||||
char *array_name, *dsvstring, *delims;
|
||||
SHELL_VAR *v;
|
||||
|
||||
array_name = 0;
|
||||
rval = EXECUTION_SUCCESS;
|
||||
|
||||
delims = ",";
|
||||
flags = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "a:d:Sgp")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
array_name = list_optarg;
|
||||
break;
|
||||
case 'd':
|
||||
delims = list_optarg;
|
||||
break;
|
||||
case 'S':
|
||||
flags |= F_SHELLQUOTE;
|
||||
break;
|
||||
case 'g':
|
||||
flags |= F_GREEDY;
|
||||
break;
|
||||
case 'p':
|
||||
flags |= F_PRESERVE;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (array_name == 0)
|
||||
array_name = DSV_ARRAY_DEFAULT;
|
||||
|
||||
if (legal_identifier (array_name) == 0)
|
||||
{
|
||||
sh_invalidid (array_name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_error ("dsv 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));
|
||||
|
||||
dsvstring = list->word->word;
|
||||
|
||||
if (dsvstring == 0 || *dsvstring == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
opt = dsvsplit (v, dsvstring, delims, flags);
|
||||
/* 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
|
||||
dsv_builtin_load (name)
|
||||
char *name;
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Called when builtin is disabled. */
|
||||
void
|
||||
dsv_builtin_unload (name)
|
||||
char *name;
|
||||
{
|
||||
}
|
||||
|
||||
char *dsv_doc[] = {
|
||||
"Read delimiter-separated fields from STRING.",
|
||||
"",
|
||||
"Parse STRING, a line of delimiter-separated values, into individual",
|
||||
"fields, and store them into the indexed array ARRAYNAME starting at",
|
||||
"index 0. The parsing understands and skips over double-quoted strings. ",
|
||||
"If ARRAYNAME is not supplied, \"DSV\" is the default array name.",
|
||||
"If the delimiter is a comma, the default, this parses comma-",
|
||||
"separated values as specified in RFC 4180.",
|
||||
"",
|
||||
"The -d option specifies the delimiter. The delimiter is the first",
|
||||
"character of the DELIMS argument. Specifying a DELIMS argument that",
|
||||
"contains more than one character is not supported and will produce",
|
||||
"unexpected results. The -S option enables shell-like quoting: double-",
|
||||
"quoted strings can contain backslashes preceding special characters,",
|
||||
"and the backslash will be removed; and single-quoted strings are",
|
||||
"processed as the shell would process them. The -g option enables a",
|
||||
"greedy split: sequences of the delimiter are skipped at the beginning",
|
||||
"and end of STRING, and consecutive instances of the delimiter in STRING",
|
||||
"do not generate empty fields. If the -p option is supplied, dsv leaves",
|
||||
"quote characters as part of the generated field; otherwise they are",
|
||||
"removed.",
|
||||
"",
|
||||
"The return value is 0 unless an invalid option is supplied or the ARRAYNAME",
|
||||
"argument is invalid or readonly.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin dsv_struct = {
|
||||
"dsv", /* builtin name */
|
||||
dsv_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
dsv_doc, /* array of long documentation strings. */
|
||||
"dsv [-a ARRAYNAME] [-d DELIMS] [-Sgp] string", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
374
examples/loadables/fdflags.c
Normal file
374
examples/loadables/fdflags.c
Normal file
|
@ -0,0 +1,374 @@
|
|||
/* Loadable builtin to get and set file descriptor flags. */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 2017-2022 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 <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include "bashansi.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "loadables.h"
|
||||
|
||||
#ifndef FD_CLOEXEC
|
||||
# define FD_CLOEXEC 1
|
||||
#endif
|
||||
|
||||
static const struct
|
||||
{
|
||||
const char *name;
|
||||
int value;
|
||||
} file_flags[] =
|
||||
{
|
||||
#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 unused 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
|
||||
};
|
||||
|
||||
#define N_FLAGS (sizeof (file_flags) / sizeof (file_flags[0]))
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
/* FIX THIS */
|
||||
static int
|
||||
getallflags ()
|
||||
{
|
||||
int i, allflags;
|
||||
|
||||
for (i = allflags = 0; i < N_FLAGS; i++)
|
||||
allflags |= file_flags[i].value;
|
||||
return allflags;
|
||||
}
|
||||
|
||||
static int
|
||||
getflags(int fd, int p)
|
||||
{
|
||||
int c, f;
|
||||
int allflags;
|
||||
|
||||
if ((c = fcntl(fd, F_GETFD)) == -1)
|
||||
{
|
||||
if (p)
|
||||
builtin_error("can't get status for fd %d: %s", fd, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((f = fcntl(fd, F_GETFL)) == -1)
|
||||
{
|
||||
if (p)
|
||||
builtin_error("Can't get flags for fd %d: %s", fd, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (c)
|
||||
f |= O_CLOEXEC;
|
||||
|
||||
return f & getallflags();
|
||||
}
|
||||
|
||||
static void
|
||||
printone(int fd, int p, int verbose)
|
||||
{
|
||||
int f;
|
||||
size_t i;
|
||||
|
||||
if ((f = getflags(fd, p)) == -1)
|
||||
return;
|
||||
|
||||
printf ("%d:", fd);
|
||||
|
||||
for (i = 0; i < N_FLAGS; i++)
|
||||
{
|
||||
if (f & file_flags[i].value)
|
||||
{
|
||||
printf ("%s%s", verbose ? "+" : "", file_flags[i].name);
|
||||
f &= ~file_flags[i].value;
|
||||
}
|
||||
else if (verbose)
|
||||
printf ( "-%s", file_flags[i].name);
|
||||
else
|
||||
continue;
|
||||
|
||||
if (f || (verbose && i != N_FLAGS - 1))
|
||||
putchar (',');
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
static int
|
||||
parseflags(char *s, int *p, int *n)
|
||||
{
|
||||
int f, *v;
|
||||
size_t i;
|
||||
|
||||
f = 0;
|
||||
*p = *n = 0;
|
||||
|
||||
for (s = strtok(s, ","); s; s = strtok(NULL, ","))
|
||||
{
|
||||
switch (*s)
|
||||
{
|
||||
case '+':
|
||||
v = p;
|
||||
s++;
|
||||
break;
|
||||
case '-':
|
||||
v = n;
|
||||
s++;
|
||||
break;
|
||||
default:
|
||||
v = &f;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < N_FLAGS; i++)
|
||||
if (strcmp(s, file_flags[i].name) == 0)
|
||||
{
|
||||
*v |= file_flags[i].value;
|
||||
break;
|
||||
}
|
||||
if (i == N_FLAGS)
|
||||
builtin_error("invalid flag `%s'", s);
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static void
|
||||
setone(int fd, char *v, int verbose)
|
||||
{
|
||||
int f, n, pos, neg, cloexec;
|
||||
|
||||
f = getflags(fd, 1);
|
||||
if (f == -1)
|
||||
return;
|
||||
|
||||
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));
|
||||
|
||||
pos &= ~O_CLOEXEC;
|
||||
neg &= ~O_CLOEXEC;
|
||||
f &= ~O_CLOEXEC;
|
||||
|
||||
n = f;
|
||||
n |= pos;
|
||||
n &= ~neg;
|
||||
|
||||
if (n != f && fcntl(fd, F_SETFL, n) == -1)
|
||||
builtin_error("can't set flags for fd %d: %s", fd, strerror(errno));
|
||||
}
|
||||
|
||||
static int
|
||||
getmaxfd ()
|
||||
{
|
||||
int maxfd, ignore;
|
||||
|
||||
#ifdef F_MAXFD
|
||||
maxfd = fcntl (0, F_MAXFD);
|
||||
if (maxfd > 0)
|
||||
return maxfd;
|
||||
#endif
|
||||
|
||||
maxfd = getdtablesize ();
|
||||
if (maxfd <= 0)
|
||||
maxfd = HIGH_FD_MAX;
|
||||
for (maxfd--; maxfd > 0; maxfd--)
|
||||
if (fcntl (maxfd, F_GETFD, &ignore) != -1)
|
||||
break;
|
||||
|
||||
return maxfd;
|
||||
}
|
||||
|
||||
int
|
||||
fdflags_builtin (WORD_LIST *list)
|
||||
{
|
||||
int opt, maxfd, i, num, verbose, setflag;
|
||||
char *setspec;
|
||||
WORD_LIST *l;
|
||||
intmax_t inum;
|
||||
|
||||
setflag = verbose = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "s:v")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 's':
|
||||
setflag = 1;
|
||||
setspec = list_optarg;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
/* Maybe we could provide some default here, but we don't yet. */
|
||||
if (list == 0 && setflag)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
maxfd = getmaxfd ();
|
||||
if (maxfd < 0)
|
||||
{
|
||||
builtin_error ("can't get max fd: %s", strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
for (i = 0; i < maxfd; i++)
|
||||
printone (i, 0, verbose);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
opt = EXECUTION_SUCCESS;
|
||||
for (l = list; l; l = l->next)
|
||||
{
|
||||
if (legal_number (l->word->word, &inum) == 0 || inum < 0)
|
||||
{
|
||||
builtin_error ("%s: invalid file descriptor", l->word->word);
|
||||
opt = EXECUTION_FAILURE;
|
||||
continue;
|
||||
}
|
||||
num = inum; /* truncate to int */
|
||||
if (setflag)
|
||||
setone (num, setspec, verbose);
|
||||
else
|
||||
printone (num, 1, verbose);
|
||||
}
|
||||
|
||||
return (opt);
|
||||
}
|
||||
|
||||
char *fdflags_doc[] =
|
||||
{
|
||||
"Display and modify file descriptor flags.",
|
||||
"",
|
||||
"Display or, if the -s option is supplied, set flags for each file",
|
||||
"descriptor supplied as an argument. If the -v option is supplied,",
|
||||
"the display is verbose, including each settable option name in the",
|
||||
"form of a string such as that accepted by the -s option.",
|
||||
"",
|
||||
"The -s option accepts a string with a list of flag names, each preceded",
|
||||
"by a `+' (set) or `-' (unset). Those changes are applied to each file",
|
||||
"descriptor supplied as an argument.",
|
||||
"",
|
||||
"If no file descriptor arguments are supplied, the displayed information",
|
||||
"consists of the status of flags for each of the shell's open files.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
/* The standard structure describing a builtin command. bash keeps an array
|
||||
of these structures. The flags must include BUILTIN_ENABLED so the
|
||||
builtin can be used. */
|
||||
struct builtin fdflags_struct = {
|
||||
"fdflags", /* builtin name */
|
||||
fdflags_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
fdflags_doc, /* array of long documentation strings. */
|
||||
"fdflags [-v] [-s flags_string] [fd ...]", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
629
examples/loadables/finfo.c
Normal file
629
examples/loadables/finfo.c
Normal file
|
@ -0,0 +1,629 @@
|
|||
/*
|
||||
* finfo - print file info
|
||||
*
|
||||
* Chet Ramey
|
||||
* chet@po.cwru.edu
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#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>
|
||||
#include <grp.h>
|
||||
#include <errno.h>
|
||||
#include "posixtime.h"
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "shell.h"
|
||||
#include "builtins.h"
|
||||
#include "common.h"
|
||||
#include "getopt.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
extern char **make_builtin_argv ();
|
||||
|
||||
static void perms();
|
||||
static int printst();
|
||||
static int printsome();
|
||||
static void printmode();
|
||||
static int printfinfo();
|
||||
static int finfo_main();
|
||||
|
||||
extern int sh_optind;
|
||||
extern char *sh_optarg;
|
||||
extern char *this_command_name;
|
||||
|
||||
static char *prog;
|
||||
static int pmask;
|
||||
|
||||
#define OPT_UID 0x00001
|
||||
#define OPT_GID 0x00002
|
||||
#define OPT_DEV 0x00004
|
||||
#define OPT_INO 0x00008
|
||||
#define OPT_PERM 0x00010
|
||||
#define OPT_LNKNAM 0x00020
|
||||
#define OPT_FID 0x00040
|
||||
#define OPT_NLINK 0x00080
|
||||
#define OPT_RDEV 0x00100
|
||||
#define OPT_SIZE 0x00200
|
||||
#define OPT_ATIME 0x00400
|
||||
#define OPT_MTIME 0x00800
|
||||
#define OPT_CTIME 0x01000
|
||||
#define OPT_BLKSIZE 0x02000
|
||||
#define OPT_BLKS 0x04000
|
||||
#define OPT_FTYPE 0x08000
|
||||
#define OPT_PMASK 0x10000
|
||||
#define OPT_OPERM 0x20000
|
||||
|
||||
#define OPT_ASCII 0x1000000
|
||||
|
||||
#define OPTIONS "acdgiflmnopsuACGMP:U"
|
||||
|
||||
static int
|
||||
octal(s)
|
||||
char *s;
|
||||
{
|
||||
int r;
|
||||
|
||||
r = *s - '0';
|
||||
while (*++s >= '0' && *s <= '7')
|
||||
r = (r * 8) + (*s - '0');
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
finfo_main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
register int i;
|
||||
int mode, flags, opt;
|
||||
|
||||
sh_optind = 0; /* XXX */
|
||||
prog = base_pathname(argv[0]);
|
||||
if (argc == 1) {
|
||||
builtin_usage();
|
||||
return(1);
|
||||
}
|
||||
flags = 0;
|
||||
while ((opt = sh_getopt(argc, argv, OPTIONS)) != EOF) {
|
||||
switch(opt) {
|
||||
case 'a': flags |= OPT_ATIME; break;
|
||||
case 'A': flags |= OPT_ATIME|OPT_ASCII; break;
|
||||
case 'c': flags |= OPT_CTIME; break;
|
||||
case 'C': flags |= OPT_CTIME|OPT_ASCII; break;
|
||||
case 'd': flags |= OPT_DEV; break;
|
||||
case 'i': flags |= OPT_INO; break;
|
||||
case 'f': flags |= OPT_FID; break;
|
||||
case 'g': flags |= OPT_GID; break;
|
||||
case 'G': flags |= OPT_GID|OPT_ASCII; break;
|
||||
case 'l': flags |= OPT_LNKNAM; break;
|
||||
case 'm': flags |= OPT_MTIME; break;
|
||||
case 'M': flags |= OPT_MTIME|OPT_ASCII; break;
|
||||
case 'n': flags |= OPT_NLINK; break;
|
||||
case 'o': flags |= OPT_OPERM; break;
|
||||
case 'p': flags |= OPT_PERM; break;
|
||||
case 'P': flags |= OPT_PMASK; pmask = octal(sh_optarg); break;
|
||||
case 's': flags |= OPT_SIZE; break;
|
||||
case 'u': flags |= OPT_UID; break;
|
||||
case 'U': flags |= OPT_UID|OPT_ASCII; break;
|
||||
default: builtin_usage (); return(1);
|
||||
}
|
||||
}
|
||||
|
||||
argc -= sh_optind;
|
||||
argv += sh_optind;
|
||||
|
||||
if (argc == 0) {
|
||||
builtin_usage();
|
||||
return(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < argc; i++)
|
||||
opt = flags ? printsome (argv[i], flags) : printfinfo(argv[i]);
|
||||
|
||||
return(opt);
|
||||
}
|
||||
|
||||
static struct stat *
|
||||
getstat(f)
|
||||
char *f;
|
||||
{
|
||||
static struct stat st;
|
||||
int fd, r;
|
||||
intmax_t lfd;
|
||||
|
||||
if (strncmp(f, "/dev/fd/", 8) == 0) {
|
||||
if ((legal_number(f + 8, &lfd) == 0) || (int)lfd != lfd) {
|
||||
builtin_error("%s: invalid fd", f + 8);
|
||||
return ((struct stat *)0);
|
||||
}
|
||||
fd = lfd;
|
||||
r = fstat(fd, &st);
|
||||
} else
|
||||
#ifdef HAVE_LSTAT
|
||||
r = lstat(f, &st);
|
||||
#else
|
||||
r = stat(f, &st);
|
||||
#endif
|
||||
if (r < 0) {
|
||||
builtin_error("%s: cannot stat: %s", f, strerror(errno));
|
||||
return ((struct stat *)0);
|
||||
}
|
||||
return (&st);
|
||||
}
|
||||
|
||||
static int
|
||||
printfinfo(f)
|
||||
char *f;
|
||||
{
|
||||
struct stat *st;
|
||||
|
||||
st = getstat(f);
|
||||
return (st ? printst(st) : 1);
|
||||
}
|
||||
|
||||
static int
|
||||
getperm(m)
|
||||
int m;
|
||||
{
|
||||
return (m & (S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID));
|
||||
}
|
||||
|
||||
static void
|
||||
perms(m)
|
||||
int m;
|
||||
{
|
||||
char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
if (m & S_IRUSR)
|
||||
ubits[i++] = 'r';
|
||||
if (m & S_IWUSR)
|
||||
ubits[i++] = 'w';
|
||||
if (m & S_IXUSR)
|
||||
ubits[i++] = 'x';
|
||||
ubits[i] = '\0';
|
||||
|
||||
i = 0;
|
||||
if (m & S_IRGRP)
|
||||
gbits[i++] = 'r';
|
||||
if (m & S_IWGRP)
|
||||
gbits[i++] = 'w';
|
||||
if (m & S_IXGRP)
|
||||
gbits[i++] = 'x';
|
||||
gbits[i] = '\0';
|
||||
|
||||
i = 0;
|
||||
if (m & S_IROTH)
|
||||
obits[i++] = 'r';
|
||||
if (m & S_IWOTH)
|
||||
obits[i++] = 'w';
|
||||
if (m & S_IXOTH)
|
||||
obits[i++] = 'x';
|
||||
obits[i] = '\0';
|
||||
|
||||
if (m & S_ISUID)
|
||||
ubits[2] = (m & S_IXUSR) ? 's' : 'S';
|
||||
if (m & S_ISGID)
|
||||
gbits[2] = (m & S_IXGRP) ? 's' : 'S';
|
||||
if (m & S_ISVTX)
|
||||
obits[2] = (m & S_IXOTH) ? 't' : 'T';
|
||||
|
||||
printf ("u=%s,g=%s,o=%s", ubits, gbits, obits);
|
||||
}
|
||||
|
||||
static void
|
||||
printmode(mode)
|
||||
int mode;
|
||||
{
|
||||
if (S_ISBLK(mode))
|
||||
printf("S_IFBLK ");
|
||||
if (S_ISCHR(mode))
|
||||
printf("S_IFCHR ");
|
||||
if (S_ISDIR(mode))
|
||||
printf("S_IFDIR ");
|
||||
if (S_ISREG(mode))
|
||||
printf("S_IFREG ");
|
||||
if (S_ISFIFO(mode))
|
||||
printf("S_IFIFO ");
|
||||
if (S_ISLNK(mode))
|
||||
printf("S_IFLNK ");
|
||||
if (S_ISSOCK(mode))
|
||||
printf("S_IFSOCK ");
|
||||
#ifdef S_ISWHT
|
||||
if (S_ISWHT(mode))
|
||||
printf("S_ISWHT ");
|
||||
#endif
|
||||
perms(getperm(mode));
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int
|
||||
printst(st)
|
||||
struct stat *st;
|
||||
{
|
||||
struct passwd *pw;
|
||||
struct group *gr;
|
||||
char *owner;
|
||||
int ma, mi, d;
|
||||
|
||||
ma = major (st->st_rdev);
|
||||
mi = minor (st->st_rdev);
|
||||
#if defined (makedev)
|
||||
d = makedev (ma, mi);
|
||||
#else
|
||||
d = st->st_rdev & 0xFF;
|
||||
#endif
|
||||
printf("Device (major/minor): %d (%d/%d)\n", d, ma, mi);
|
||||
|
||||
printf("Inode: %d\n", (int) st->st_ino);
|
||||
printf("Mode: (%o) ", (int) st->st_mode);
|
||||
printmode((int) st->st_mode);
|
||||
printf("Link count: %d\n", (int) st->st_nlink);
|
||||
pw = getpwuid(st->st_uid);
|
||||
owner = pw ? pw->pw_name : "unknown";
|
||||
printf("Uid of owner: %d (%s)\n", (int) st->st_uid, owner);
|
||||
gr = getgrgid(st->st_gid);
|
||||
owner = gr ? gr->gr_name : "unknown";
|
||||
printf("Gid of owner: %d (%s)\n", (int) st->st_gid, owner);
|
||||
printf("Device type: %d\n", (int) st->st_rdev);
|
||||
printf("File size: %ld\n", (long) st->st_size);
|
||||
printf("File last access time: %s", ctime (&st->st_atime));
|
||||
printf("File last modify time: %s", ctime (&st->st_mtime));
|
||||
printf("File last status change time: %s", ctime (&st->st_ctime));
|
||||
fflush(stdout);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
printsome(f, flags)
|
||||
char *f;
|
||||
int flags;
|
||||
{
|
||||
struct stat *st;
|
||||
struct passwd *pw;
|
||||
struct group *gr;
|
||||
int p;
|
||||
char *b;
|
||||
|
||||
st = getstat(f);
|
||||
if (st == NULL)
|
||||
return (1);
|
||||
|
||||
/* Print requested info */
|
||||
if (flags & OPT_ATIME) {
|
||||
if (flags & OPT_ASCII)
|
||||
printf("%s", ctime(&st->st_atime));
|
||||
else
|
||||
printf("%ld\n", st->st_atime);
|
||||
} else if (flags & OPT_MTIME) {
|
||||
if (flags & OPT_ASCII)
|
||||
printf("%s", ctime(&st->st_mtime));
|
||||
else
|
||||
printf("%ld\n", st->st_mtime);
|
||||
} else if (flags & OPT_CTIME) {
|
||||
if (flags & OPT_ASCII)
|
||||
printf("%s", ctime(&st->st_ctime));
|
||||
else
|
||||
printf("%ld\n", st->st_ctime);
|
||||
} else if (flags & OPT_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("%lu:%lu\n", (unsigned long)st->st_dev, (unsigned long)st->st_ino);
|
||||
else if (flags & OPT_NLINK)
|
||||
printf("%lu\n", (unsigned long)st->st_nlink);
|
||||
else if (flags & OPT_LNKNAM) {
|
||||
#ifdef S_ISLNK
|
||||
b = xmalloc(4096);
|
||||
p = readlink(f, b, 4096);
|
||||
if (p >= 0 && p < 4096)
|
||||
b[p] = '\0';
|
||||
else {
|
||||
p = errno;
|
||||
strcpy(b, prog);
|
||||
strcat(b, ": ");
|
||||
strcat(b, strerror(p));
|
||||
}
|
||||
printf("%s\n", b);
|
||||
free(b);
|
||||
#else
|
||||
printf("%s\n", f);
|
||||
#endif
|
||||
} else if (flags & OPT_PERM) {
|
||||
perms(st->st_mode);
|
||||
printf("\n");
|
||||
} else if (flags & OPT_OPERM)
|
||||
printf("%o\n", getperm(st->st_mode));
|
||||
else if (flags & OPT_PMASK)
|
||||
printf("%o\n", getperm(st->st_mode) & pmask);
|
||||
else if (flags & OPT_UID) {
|
||||
pw = getpwuid(st->st_uid);
|
||||
if (flags & OPT_ASCII)
|
||||
printf("%s\n", pw ? pw->pw_name : "unknown");
|
||||
else
|
||||
printf("%d\n", st->st_uid);
|
||||
} else if (flags & OPT_GID) {
|
||||
gr = getgrgid(st->st_gid);
|
||||
if (flags & OPT_ASCII)
|
||||
printf("%s\n", gr ? gr->gr_name : "unknown");
|
||||
else
|
||||
printf("%d\n", st->st_gid);
|
||||
} else if (flags & OPT_SIZE)
|
||||
printf("%ld\n", (long) st->st_size);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifndef NOBUILTIN
|
||||
int
|
||||
finfo_builtin(list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int c, r;
|
||||
char **v;
|
||||
WORD_LIST *l;
|
||||
|
||||
v = make_builtin_argv (list, &c);
|
||||
r = finfo_main (c, v);
|
||||
free (v);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static char *finfo_doc[] = {
|
||||
"Display information about file attributes.",
|
||||
"",
|
||||
"Display information about each FILE. Only single operators should",
|
||||
"be supplied. If no options are supplied, a summary of the info",
|
||||
"available about each FILE is printed. If FILE is of the form",
|
||||
"/dev/fd/XX, file descriptor XX is described. Operators, if supplied,",
|
||||
"have the following meanings:",
|
||||
"",
|
||||
" -a last file access time",
|
||||
" -A last file access time in ctime format",
|
||||
" -c last file status change time",
|
||||
" -C last file status change time in ctime format",
|
||||
" -m last file modification time",
|
||||
" -M last file modification time in ctime format",
|
||||
" -d device",
|
||||
" -i inode",
|
||||
" -f composite file identifier (device:inode)",
|
||||
" -g gid of owner",
|
||||
" -G group name of owner",
|
||||
" -l name of file pointed to by symlink",
|
||||
" -n link count",
|
||||
" -o permissions in octal",
|
||||
" -p permissions in ascii",
|
||||
" -P mask permissions ANDed with MASK (like with umask)",
|
||||
" -s file size in bytes",
|
||||
" -u uid of owner",
|
||||
" -U user name of owner",
|
||||
(char *)0
|
||||
};
|
||||
|
||||
struct builtin finfo_struct = {
|
||||
"finfo",
|
||||
finfo_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
finfo_doc,
|
||||
"finfo [-acdgiflmnopsuACGMPU] file [file...]",
|
||||
0
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef NOBUILTIN
|
||||
#if defined (PREFER_STDARG)
|
||||
# include <stdarg.h>
|
||||
#else
|
||||
# if defined (PREFER_VARARGS)
|
||||
# include <varargs.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
char *this_command_name;
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
this_command_name = argv[0];
|
||||
exit(finfo_main(argc, argv));
|
||||
}
|
||||
|
||||
void
|
||||
builtin_usage()
|
||||
{
|
||||
fprintf(stderr, "%s: usage: %s [-%s] [file ...]\n", prog, prog, OPTIONS);
|
||||
}
|
||||
|
||||
#ifndef HAVE_STRERROR
|
||||
char *
|
||||
strerror(e)
|
||||
int e;
|
||||
{
|
||||
static char ebuf[40];
|
||||
extern int sys_nerr;
|
||||
extern char *sys_errlist[];
|
||||
|
||||
if (e < 0 || e > sys_nerr) {
|
||||
sprintf(ebuf,"Unknown error code %d", e);
|
||||
return (&ebuf[0]);
|
||||
}
|
||||
return (sys_errlist[e]);
|
||||
}
|
||||
#endif
|
||||
|
||||
char *
|
||||
xmalloc(s)
|
||||
size_t s;
|
||||
{
|
||||
char *ret;
|
||||
extern char *malloc();
|
||||
|
||||
ret = malloc(s);
|
||||
if (ret)
|
||||
return (ret);
|
||||
fprintf(stderr, "%s: cannot malloc %d bytes\n", prog, s);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *
|
||||
base_pathname(p)
|
||||
char *p;
|
||||
{
|
||||
char *t;
|
||||
|
||||
if (t = strrchr(p, '/'))
|
||||
return(++t);
|
||||
return(p);
|
||||
}
|
||||
|
||||
int
|
||||
legal_number (string, result)
|
||||
char *string;
|
||||
long *result;
|
||||
{
|
||||
int sign;
|
||||
long value;
|
||||
|
||||
sign = 1;
|
||||
value = 0;
|
||||
|
||||
if (result)
|
||||
*result = 0;
|
||||
|
||||
/* Skip leading whitespace characters. */
|
||||
while (whitespace (*string))
|
||||
string++;
|
||||
|
||||
if (!*string)
|
||||
return (0);
|
||||
|
||||
/* We allow leading `-' or `+'. */
|
||||
if (*string == '-' || *string == '+')
|
||||
{
|
||||
if (!digit (string[1]))
|
||||
return (0);
|
||||
|
||||
if (*string == '-')
|
||||
sign = -1;
|
||||
|
||||
string++;
|
||||
}
|
||||
|
||||
while (digit (*string))
|
||||
{
|
||||
if (result)
|
||||
value = (value * 10) + digit_value (*string);
|
||||
string++;
|
||||
}
|
||||
|
||||
/* Skip trailing whitespace, if any. */
|
||||
while (whitespace (*string))
|
||||
string++;
|
||||
|
||||
/* Error if not at end of string. */
|
||||
if (*string)
|
||||
return (0);
|
||||
|
||||
if (result)
|
||||
*result = value * sign;
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
int sh_optind;
|
||||
char *sh_optarg;
|
||||
int sh_opterr;
|
||||
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
|
||||
int
|
||||
sh_getopt(c, v, o)
|
||||
int c;
|
||||
char **v, *o;
|
||||
{
|
||||
int r;
|
||||
|
||||
r = getopt(c, v, o);
|
||||
sh_optind = optind;
|
||||
sh_optarg = optarg;
|
||||
return r;
|
||||
}
|
||||
|
||||
#if defined (USE_VARARGS)
|
||||
void
|
||||
#if defined (PREFER_STDARG)
|
||||
builtin_error (const char *format, ...)
|
||||
#else
|
||||
builtin_error (format, va_alist)
|
||||
const char *format;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (this_command_name && *this_command_name)
|
||||
fprintf (stderr, "%s: ", this_command_name);
|
||||
|
||||
#if defined (PREFER_STDARG)
|
||||
va_start (args, format);
|
||||
#else
|
||||
va_start (args);
|
||||
#endif
|
||||
|
||||
vfprintf (stderr, format, args);
|
||||
va_end (args);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
#else
|
||||
void
|
||||
builtin_error (format, arg1, arg2, arg3, arg4, arg5)
|
||||
char *format, *arg1, *arg2, *arg3, *arg4, *arg5;
|
||||
{
|
||||
if (this_command_name && *this_command_name)
|
||||
fprintf (stderr, "%s: ", this_command_name);
|
||||
|
||||
fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
|
||||
fprintf (stderr, "\n");
|
||||
fflush (stderr);
|
||||
}
|
||||
#endif /* !USE_VARARGS */
|
||||
|
||||
#endif
|
1163
examples/loadables/getconf.c
Normal file
1163
examples/loadables/getconf.c
Normal file
File diff suppressed because it is too large
Load diff
136
examples/loadables/getconf.h
Normal file
136
examples/loadables/getconf.h
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
Copyright (C) 2021 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/>.
|
||||
*/
|
||||
/* getconf.h -- replacement definitions for ones the system doesn't provide
|
||||
and don't appear in <typemax.h> */
|
||||
|
||||
#ifndef _GETCONF_H
|
||||
#define _GETCONF_H
|
||||
|
||||
/* Some systems do not define these; use POSIX.2 minimum recommended values. */
|
||||
#ifndef _POSIX2_COLL_WEIGHTS_MAX
|
||||
# define _POSIX2_COLL_WEIGHTS_MAX 2
|
||||
#endif
|
||||
|
||||
/* If we're on a posix system, but the system doesn't define the necessary
|
||||
constants, use posix.1 minimum values. */
|
||||
#if defined (_POSIX_VERSION)
|
||||
|
||||
#ifndef _POSIX_ARG_MAX
|
||||
# define _POSIX_ARG_MAX 4096
|
||||
#endif
|
||||
#ifndef _POSIX_CHILD_MAX
|
||||
# define _POSIX_CHILD_MAX 6
|
||||
#endif
|
||||
#ifndef _POSIX_LINK_MAX
|
||||
# define _POSIX_LINK_MAX 8
|
||||
#endif
|
||||
#ifndef _POSIX_MAX_CANON
|
||||
# define _POSIX_MAX_CANON 255
|
||||
#endif
|
||||
#ifndef _POSIX_MAX_INPUT
|
||||
# define _POSIX_MAX_INPUT 255
|
||||
#endif
|
||||
#ifndef _POSIX_NAME_MAX
|
||||
# define _POSIX_NAME_MAX 14
|
||||
#endif
|
||||
#ifndef _POSIX_NGROUPS_MAX
|
||||
# define _POSIX_NGROUPS_MAX 0
|
||||
#endif
|
||||
#ifndef _POSIX_OPEN_MAX
|
||||
# define _POSIX_OPEN_MAX 16
|
||||
#endif
|
||||
#ifndef _POSIX_PATH_MAX
|
||||
# define _POSIX_PATH_MAX 255
|
||||
#endif
|
||||
#ifndef _POSIX_PIPE_BUF
|
||||
# define _POSIX_PIPE_BUF 512
|
||||
#endif
|
||||
#ifndef _POSIX_SSIZE_MAX
|
||||
# define _POSIX_SSIZE_MAX 32767
|
||||
#endif
|
||||
#ifndef _POSIX_STREAM_MAX
|
||||
# define _POSIX_STREAM_MAX 8
|
||||
#endif
|
||||
#ifndef _POSIX_TZNAME_MAX
|
||||
# define _POSIX_TZNAME_MAX 3
|
||||
#endif
|
||||
|
||||
#ifndef _POSIX2_BC_BASE_MAX
|
||||
# define _POSIX2_BC_BASE_MAX 99
|
||||
#endif
|
||||
#ifndef _POSIX2_BC_DIM_MAX
|
||||
# define _POSIX2_BC_DIM_MAX 2048
|
||||
#endif
|
||||
#ifndef _POSIX2_BC_SCALE_MAX
|
||||
# define _POSIX2_BC_SCALE_MAX 99
|
||||
#endif
|
||||
#ifndef _POSIX2_BC_STRING_MAX
|
||||
# define _POSIX2_BC_STRING_MAX 1000
|
||||
#endif
|
||||
#ifndef _POSIX2_EQUIV_CLASS_MAX
|
||||
# define _POSIX2_EQUIV_CLASS_MAX 2
|
||||
#endif
|
||||
#ifndef _POSIX2_EXPR_NEST_MAX
|
||||
# define _POSIX2_EXPR_NEST_MAX 32
|
||||
#endif
|
||||
#ifndef _POSIX2_LINE_MAX
|
||||
# define _POSIX2_LINE_MAX 2048
|
||||
#endif
|
||||
#ifndef _POSIX2_RE_DUP_MAX
|
||||
# define _POSIX2_RE_DUP_MAX 255
|
||||
#endif
|
||||
|
||||
#endif /* _POSIX_VERSION */
|
||||
|
||||
/* ANSI/ISO C, POSIX.1-200x, XPG 4.2, and C language type limits.
|
||||
Defined only if the system include files and <typemax.h> don't. */
|
||||
|
||||
#ifndef CHAR_MAX
|
||||
# define CHAR_MAX 127
|
||||
#endif
|
||||
#ifndef CHAR_MIN
|
||||
# define CHAR_MIN -128
|
||||
#endif
|
||||
#ifndef SCHAR_MAX
|
||||
# define SCHAR_MAX 127
|
||||
#endif
|
||||
#ifndef SCHAR_MIN
|
||||
# define SCHAR_MIN -128
|
||||
#endif
|
||||
|
||||
#ifndef INT_BIT
|
||||
# define INT_BIT (sizeof (int) * CHAR_BIT)
|
||||
#endif
|
||||
|
||||
#ifndef LONG_BIT
|
||||
# define LONG_BIT (sizeof (long int) * CHAR_BIT)
|
||||
#endif
|
||||
|
||||
#ifndef WORD_BIT
|
||||
# define WORD_BIT (sizeof (int) * CHAR_BIT)
|
||||
#endif
|
||||
|
||||
#if !defined (PRIdMAX)
|
||||
# if HAVE_LONG_LONG
|
||||
# define PRIdMAX "lld"
|
||||
# else
|
||||
# define PRIdMAX "ld"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* _GETCONF_H */
|
170
examples/loadables/head.c
Normal file
170
examples/loadables/head.c
Normal file
|
@ -0,0 +1,170 @@
|
|||
/* head - copy first part of files. */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 "filecntl.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "chartypes.h"
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
static void
|
||||
munge_list (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
WORD_LIST *l, *nl;
|
||||
WORD_DESC *wd;
|
||||
char *arg;
|
||||
|
||||
for (l = list; l; l = l->next)
|
||||
{
|
||||
arg = l->word->word;
|
||||
if (arg[0] != '-' || arg[1] == '-' || (DIGIT(arg[1]) == 0))
|
||||
return;
|
||||
/* We have -[0-9]* */
|
||||
wd = make_bare_word (arg+1);
|
||||
nl = make_word_list (wd, l->next);
|
||||
l->word->word[1] = 'n';
|
||||
l->word->word[2] = '\0';
|
||||
l->next = nl;
|
||||
l = nl; /* skip over new argument */
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
file_head (fp, cnt)
|
||||
FILE *fp;
|
||||
int cnt;
|
||||
{
|
||||
int ch;
|
||||
|
||||
while (cnt--)
|
||||
{
|
||||
while ((ch = getc (fp)) != EOF)
|
||||
{
|
||||
QUIT;
|
||||
if (putchar (ch) == EOF)
|
||||
{
|
||||
builtin_error ("write error: %s", strerror (errno));
|
||||
return EXECUTION_FAILURE;
|
||||
}
|
||||
QUIT;
|
||||
if (ch == '\n')
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
head_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int nline, opt, rval;
|
||||
WORD_LIST *l;
|
||||
FILE *fp;
|
||||
|
||||
char *t;
|
||||
|
||||
munge_list (list); /* change -num into -n num */
|
||||
|
||||
reset_internal_getopt ();
|
||||
nline = 10;
|
||||
while ((opt = internal_getopt (list, "n:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'n':
|
||||
nline = atoi (list_optarg);
|
||||
if (nline <= 0)
|
||||
{
|
||||
builtin_error ("bad line count: %s", list_optarg);
|
||||
return (EX_USAGE);
|
||||
}
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list == 0)
|
||||
return (file_head (stdin, nline));
|
||||
|
||||
for (rval = EXECUTION_SUCCESS, opt = 1, l = list; l; l = l->next)
|
||||
{
|
||||
fp = fopen (l->word->word, "r");
|
||||
if (fp == NULL)
|
||||
{
|
||||
builtin_error ("%s: %s", l->word->word, strerror (errno));
|
||||
continue;
|
||||
}
|
||||
if (list->next) /* more than one file */
|
||||
{
|
||||
printf ("%s==> %s <==\n", opt ? "" : "\n", l->word->word);
|
||||
opt = 0;
|
||||
}
|
||||
QUIT;
|
||||
rval = file_head (fp, nline);
|
||||
fclose (fp);
|
||||
}
|
||||
|
||||
return (rval);
|
||||
}
|
||||
|
||||
char *head_doc[] = {
|
||||
"Display lines from beginning of file.",
|
||||
"",
|
||||
"Copy the first N lines from the input files to the standard output.",
|
||||
"N is supplied as an argument to the `-n' option. If N is not given,",
|
||||
"the first ten lines are copied.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin head_struct = {
|
||||
"head", /* builtin name */
|
||||
head_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
head_doc, /* array of long documentation strings. */
|
||||
"head [-n num] [file ...]", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
96
examples/loadables/hello.c
Normal file
96
examples/loadables/hello.c
Normal file
|
@ -0,0 +1,96 @@
|
|||
/* Sample builtin to be dynamically loaded with enable -f and create a new
|
||||
builtin. */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 "loadables.h"
|
||||
|
||||
/* A builtin `xxx' is normally implemented with an `xxx_builtin' function.
|
||||
If you're converting a command that uses the normal Unix argc/argv
|
||||
calling convention, use argv = make_builtin_argv (list, &argc) and call
|
||||
the original `main' something like `xxx_main'. Look at cat.c for an
|
||||
example.
|
||||
|
||||
Builtins should use internal_getopt to parse options. It is the same as
|
||||
getopt(3), but it takes a WORD_LIST *. Look at print.c for an example
|
||||
of its use.
|
||||
|
||||
If the builtin takes no options, call no_options(list) before doing
|
||||
anything else. If it returns a non-zero value, your builtin should
|
||||
immediately return EX_USAGE. Look at logname.c for an example.
|
||||
|
||||
A builtin command returns EXECUTION_SUCCESS for success and
|
||||
EXECUTION_FAILURE to indicate failure. */
|
||||
int
|
||||
hello_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
printf("hello world\n");
|
||||
fflush (stdout);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
hello_builtin_load (s)
|
||||
char *s;
|
||||
{
|
||||
printf ("hello builtin loaded\n");
|
||||
fflush (stdout);
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
hello_builtin_unload (s)
|
||||
char *s;
|
||||
{
|
||||
printf ("hello builtin unloaded\n");
|
||||
fflush (stdout);
|
||||
}
|
||||
|
||||
/* An array of strings forming the `long' documentation for a builtin xxx,
|
||||
which is printed by `help xxx'. It must end with a NULL. By convention,
|
||||
the first line is a short description. */
|
||||
char *hello_doc[] = {
|
||||
"Sample builtin.",
|
||||
"",
|
||||
"this is the long doc for the sample hello builtin",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
/* The standard structure describing a builtin command. bash keeps an array
|
||||
of these structures. The flags must include BUILTIN_ENABLED so the
|
||||
builtin can be used. */
|
||||
struct builtin hello_struct = {
|
||||
"hello", /* builtin name */
|
||||
hello_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
hello_doc, /* array of long documentation strings. */
|
||||
"hello", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
329
examples/loadables/id.c
Normal file
329
examples/loadables/id.c
Normal file
|
@ -0,0 +1,329 @@
|
|||
/*
|
||||
* id - POSIX.2 user identity
|
||||
*
|
||||
* (INCOMPLETE -- supplementary groups for other users not yet done)
|
||||
*
|
||||
* usage: id [-Ggu] [-nr] [user]
|
||||
*
|
||||
* The default output format looks something like:
|
||||
* uid=xxx(chet) gid=xx groups=aa(aname), bb(bname), cc(cname)
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 <stdio.h>
|
||||
#include "bashtypes.h"
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include "bashansi.h"
|
||||
|
||||
#ifdef HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
#else
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#if !defined (HAVE_GETPW_DECLS)
|
||||
extern struct passwd *getpwuid ();
|
||||
#endif
|
||||
extern struct group *getgrgid ();
|
||||
|
||||
#include "shell.h"
|
||||
#include "builtins.h"
|
||||
#include "stdc.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#define ID_ALLGROUPS 0x001 /* -G */
|
||||
#define ID_GIDONLY 0x002 /* -g */
|
||||
#define ID_USENAME 0x004 /* -n */
|
||||
#define ID_USEREAL 0x008 /* -r */
|
||||
#define ID_USERONLY 0x010 /* -u */
|
||||
|
||||
#define ID_FLAGSET(s) ((id_flags & (s)) != 0)
|
||||
|
||||
static int id_flags;
|
||||
|
||||
static uid_t ruid, euid;
|
||||
static gid_t rgid, egid;
|
||||
|
||||
static char *id_user;
|
||||
|
||||
static int inituser ();
|
||||
|
||||
static int id_pruser ();
|
||||
static int id_prgrp ();
|
||||
static int id_prgroups ();
|
||||
static int id_prall ();
|
||||
|
||||
int
|
||||
id_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt;
|
||||
char *user;
|
||||
|
||||
id_flags = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "Ggnru")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'G': id_flags |= ID_ALLGROUPS; break;
|
||||
case 'g': id_flags |= ID_GIDONLY; break;
|
||||
case 'n': id_flags |= ID_USENAME; break;
|
||||
case 'r': id_flags |= ID_USEREAL; break;
|
||||
case 'u': id_flags |= ID_USERONLY; break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
user = list ? list->word->word : (char *)NULL;
|
||||
|
||||
/* Check for some invalid option combinations */
|
||||
opt = ID_FLAGSET (ID_ALLGROUPS) + ID_FLAGSET (ID_GIDONLY) + ID_FLAGSET (ID_USERONLY);
|
||||
if (opt > 1 || (opt == 0 && ((id_flags & (ID_USEREAL|ID_USENAME)) != 0)))
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
if (list && list->next)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
if (inituser (user) < 0)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
opt = 0;
|
||||
if (id_flags & ID_USERONLY)
|
||||
opt += id_pruser ((id_flags & ID_USEREAL) ? ruid : euid);
|
||||
else if (id_flags & ID_GIDONLY)
|
||||
opt += id_prgrp ((id_flags & ID_USEREAL) ? rgid : egid);
|
||||
else if (id_flags & ID_ALLGROUPS)
|
||||
opt += id_prgroups (user);
|
||||
else
|
||||
opt += id_prall (user);
|
||||
putchar ('\n');
|
||||
fflush (stdout);
|
||||
|
||||
return (opt == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
static int
|
||||
inituser (uname)
|
||||
char *uname;
|
||||
{
|
||||
struct passwd *pwd;
|
||||
|
||||
if (uname)
|
||||
{
|
||||
pwd = getpwnam (uname);
|
||||
if (pwd == 0)
|
||||
{
|
||||
builtin_error ("%s: no such user", uname);
|
||||
return -1;
|
||||
}
|
||||
ruid = euid = pwd->pw_uid;
|
||||
rgid = egid = pwd->pw_gid;
|
||||
}
|
||||
else
|
||||
{
|
||||
ruid = current_user.uid;
|
||||
euid = current_user.euid;
|
||||
rgid = current_user.gid;
|
||||
egid = current_user.egid;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Print the name or value of user ID UID. */
|
||||
static int
|
||||
id_pruser (uid)
|
||||
int uid;
|
||||
{
|
||||
struct passwd *pwd = NULL;
|
||||
int r;
|
||||
|
||||
r = 0;
|
||||
if (id_flags & ID_USENAME)
|
||||
{
|
||||
pwd = getpwuid (uid);
|
||||
if (pwd == NULL)
|
||||
r = 1;
|
||||
}
|
||||
if (pwd)
|
||||
printf ("%s", pwd->pw_name);
|
||||
else
|
||||
printf ("%u", (unsigned) uid);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Print the name or value of group ID GID. */
|
||||
|
||||
static int
|
||||
id_prgrp (gid)
|
||||
int gid;
|
||||
{
|
||||
struct group *grp = NULL;
|
||||
int r;
|
||||
|
||||
r = 0;
|
||||
if (id_flags & ID_USENAME)
|
||||
{
|
||||
grp = getgrgid (gid);
|
||||
if (grp == NULL)
|
||||
r = 1;
|
||||
}
|
||||
|
||||
if (grp)
|
||||
printf ("%s", grp->gr_name);
|
||||
else
|
||||
printf ("%u", (unsigned) gid);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
id_prgroups (uname)
|
||||
char *uname;
|
||||
{
|
||||
int *glist, ng, i, r;
|
||||
|
||||
r = 0;
|
||||
id_prgrp (rgid);
|
||||
if (egid != rgid)
|
||||
{
|
||||
putchar (' ');
|
||||
id_prgrp (egid);
|
||||
}
|
||||
|
||||
if (uname)
|
||||
{
|
||||
builtin_error ("supplementary groups for other users not yet implemented");
|
||||
glist = (int *)NULL;
|
||||
ng = 0;
|
||||
r = 1;
|
||||
}
|
||||
else
|
||||
glist = get_group_array (&ng);
|
||||
|
||||
for (i = 0; i < ng; i++)
|
||||
if (glist[i] != rgid && glist[i] != egid)
|
||||
{
|
||||
putchar (' ');
|
||||
id_prgrp (glist[i]);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
id_prall (uname)
|
||||
char *uname;
|
||||
{
|
||||
int r, i, ng, *glist;
|
||||
struct passwd *pwd;
|
||||
struct group *grp;
|
||||
|
||||
r = 0;
|
||||
printf ("uid=%u", (unsigned) ruid);
|
||||
pwd = getpwuid (ruid);
|
||||
if (pwd == NULL)
|
||||
r = 1;
|
||||
else
|
||||
printf ("(%s)", pwd->pw_name);
|
||||
|
||||
printf (" gid=%u", (unsigned) rgid);
|
||||
grp = getgrgid (rgid);
|
||||
if (grp == NULL)
|
||||
r = 1;
|
||||
else
|
||||
printf ("(%s)", grp->gr_name);
|
||||
|
||||
if (euid != ruid)
|
||||
{
|
||||
printf (" euid=%u", (unsigned) euid);
|
||||
pwd = getpwuid (euid);
|
||||
if (pwd == NULL)
|
||||
r = 1;
|
||||
else
|
||||
printf ("(%s)", pwd->pw_name);
|
||||
}
|
||||
|
||||
if (egid != rgid)
|
||||
{
|
||||
printf (" egid=%u", (unsigned) egid);
|
||||
grp = getgrgid (egid);
|
||||
if (grp == NULL)
|
||||
r = 1;
|
||||
else
|
||||
printf ("(%s)", grp->gr_name);
|
||||
}
|
||||
|
||||
if (uname)
|
||||
{
|
||||
builtin_error ("supplementary groups for other users not yet implemented");
|
||||
glist = (int *)NULL;
|
||||
ng = 0;
|
||||
r = 1;
|
||||
}
|
||||
else
|
||||
glist = get_group_array (&ng);
|
||||
|
||||
if (ng > 0)
|
||||
printf (" groups=");
|
||||
for (i = 0; i < ng; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
printf (", ");
|
||||
printf ("%u", (unsigned) glist[i]);
|
||||
grp = getgrgid (glist[i]);
|
||||
if (grp == NULL)
|
||||
r = 1;
|
||||
else
|
||||
printf ("(%s)", grp->gr_name);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
char *id_doc[] = {
|
||||
"Display information about user."
|
||||
"",
|
||||
"Return information about user identity",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin id_struct = {
|
||||
"id",
|
||||
id_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
id_doc,
|
||||
"id [user]\n\tid -G [-n] [user]\n\tid -g [-nr] [user]\n\tid -u [-nr] [user]",
|
||||
0
|
||||
};
|
236
examples/loadables/ln.c
Normal file
236
examples/loadables/ln.c
Normal file
|
@ -0,0 +1,236 @@
|
|||
/* ln - make links */
|
||||
|
||||
/* 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"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "posixstat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
typedef int unix_link_syscall_t PARAMS((const char *, const char *));
|
||||
|
||||
#define LN_SYMLINK 0x01
|
||||
#define LN_UNLINK 0x02
|
||||
#define LN_NOFOLLOW 0x04
|
||||
|
||||
static unix_link_syscall_t *linkfn;
|
||||
static int dolink ();
|
||||
|
||||
int
|
||||
ln_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int rval, opt, flags;
|
||||
WORD_LIST *l;
|
||||
char *sdir;
|
||||
struct stat sb;
|
||||
|
||||
flags = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "fs")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'f':
|
||||
flags |= LN_UNLINK;
|
||||
break;
|
||||
case 's':
|
||||
flags |= LN_SYMLINK;
|
||||
break;
|
||||
case 'h':
|
||||
case 'n':
|
||||
flags |= LN_NOFOLLOW;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
linkfn = (flags & LN_SYMLINK) ? symlink : link;
|
||||
|
||||
if (list->next == 0) /* ln target, equivalent to ln target . */
|
||||
return (dolink (list->word->word, ".", flags));
|
||||
|
||||
if (list->next->next == 0) /* ln target source */
|
||||
return (dolink (list->word->word, list->next->word->word, flags));
|
||||
|
||||
/* ln target1 target2 ... directory */
|
||||
|
||||
/* find last argument: target directory, and make sure it's an existing
|
||||
directory. */
|
||||
for (l = list; l->next; l = l->next)
|
||||
;
|
||||
sdir = l->word->word;
|
||||
|
||||
if (stat(sdir, &sb) < 0)
|
||||
{
|
||||
builtin_error ("%s", sdir);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (S_ISDIR (sb.st_mode) == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
for (rval = EXECUTION_SUCCESS; list != l; list = list->next)
|
||||
rval += dolink (list->word->word, sdir, flags);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
static char *
|
||||
mkdirpath (dir, file)
|
||||
char *dir, *file;
|
||||
{
|
||||
int dlen, flen;
|
||||
char *ret;
|
||||
|
||||
dlen = strlen (dir);
|
||||
flen = strlen (file);
|
||||
|
||||
ret = xmalloc (2 + dlen + flen);
|
||||
|
||||
strcpy (ret, dir);
|
||||
if (ret[dlen - 1] != '/')
|
||||
ret[dlen++] = '/';
|
||||
strcpy (ret + dlen, file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined (HAVE_LSTAT)
|
||||
# define LSTAT lstat
|
||||
# define LSTAT_OR_STAT_IF(c, f, b) ((c) ? lstat((f), (b)) : stat((f), (b)))
|
||||
#else
|
||||
# define LSTAT stat
|
||||
# define LSTAT_OR_STAT_IF(c, f, b) (stat((f), (b)))
|
||||
#endif
|
||||
|
||||
static int
|
||||
dolink (src, dst, flags)
|
||||
char *src, *dst;
|
||||
int flags;
|
||||
{
|
||||
struct stat ssb, dsb;
|
||||
int exists;
|
||||
char *dst_path, *p;
|
||||
|
||||
/* If we're not doing symlinks, the source must exist and not be a
|
||||
directory. */
|
||||
if ((flags & LN_SYMLINK) == 0)
|
||||
{
|
||||
if (stat (src, &ssb) != 0)
|
||||
{
|
||||
builtin_error ("%s: %s", src, strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
if (S_ISDIR (ssb.st_mode))
|
||||
{
|
||||
errno = EISDIR;
|
||||
builtin_error ("%s: %s", src, strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the destination is a directory, create the final filename by appending
|
||||
the basename of the source to the destination. */
|
||||
dst_path = 0;
|
||||
if ((LSTAT_OR_STAT_IF((flags & LN_NOFOLLOW), dst, &dsb) == 0) && S_ISDIR (dsb.st_mode))
|
||||
{
|
||||
if ((p = strrchr (src, '/')) == 0)
|
||||
p = src;
|
||||
else
|
||||
p++;
|
||||
|
||||
dst_path = mkdirpath (dst, p);
|
||||
dst = dst_path;
|
||||
}
|
||||
|
||||
exists = LSTAT (dst, &dsb) == 0;
|
||||
|
||||
/* If -f was specified, and the destination exists, unlink it. */
|
||||
if ((flags & LN_UNLINK) && exists && unlink (dst) != 0)
|
||||
{
|
||||
builtin_error ("%s: cannot unlink: %s", dst, strerror (errno));
|
||||
FREE (dst_path);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* Perform the link. */
|
||||
if ((*linkfn) (src, dst) != 0)
|
||||
{
|
||||
builtin_error ("cannot link %s to %s: %s", dst, src, strerror (errno));
|
||||
FREE (dst_path);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
FREE (dst_path);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *ln_doc[] = {
|
||||
"Link files.",
|
||||
"",
|
||||
"Create a new directory entry with the same modes as the original",
|
||||
"file. The -f option means to unlink any existing file, permitting",
|
||||
"the link to occur. The -s option means to create a symbolic link.",
|
||||
"By default, ln makes hard links. Specifying -n or its synonym -h",
|
||||
"causes ln to not resolve symlinks in the target file or directory.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
/* The standard structure describing a builtin command. bash keeps an array
|
||||
of these structures. */
|
||||
struct builtin ln_struct = {
|
||||
"ln", /* builtin name */
|
||||
ln_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
ln_doc, /* array of long documentation strings. */
|
||||
"ln [-fhns] file1 [file2] OR ln [-fhns] file ... directory", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
34
examples/loadables/loadables.h
Normal file
34
examples/loadables/loadables.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* loadables.h -- Include files needed by all loadable builtins */
|
||||
|
||||
/* Copyright (C) 2015 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __LOADABLES_H_
|
||||
#define __LOADABLES_H_
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#endif
|
74
examples/loadables/logname.c
Normal file
74
examples/loadables/logname.c
Normal file
|
@ -0,0 +1,74 @@
|
|||
/* logname - print login name of current user */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
int
|
||||
logname_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *np;
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
|
||||
np = getlogin ();
|
||||
if (np == 0)
|
||||
{
|
||||
builtin_error ("cannot find username: %s", strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
printf ("%s\n", np);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *logname_doc[] = {
|
||||
"Display user login name.",
|
||||
"",
|
||||
"Write the current user's login name to the standard output",
|
||||
"and exit. logname ignores the LOGNAME and USER variables.",
|
||||
"logname ignores any non-option arguments.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin logname_struct = {
|
||||
"logname",
|
||||
logname_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
logname_doc,
|
||||
"logname",
|
||||
0
|
||||
};
|
||||
|
245
examples/loadables/mkdir.c
Normal file
245
examples/loadables/mkdir.c
Normal file
|
@ -0,0 +1,245 @@
|
|||
/* mkdir - make directories */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 make_path ();
|
||||
|
||||
static int original_umask;
|
||||
|
||||
int
|
||||
mkdir_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt, pflag, mflag, omode, rval, nmode, parent_mode;
|
||||
char *mode;
|
||||
WORD_LIST *l;
|
||||
|
||||
reset_internal_getopt ();
|
||||
pflag = mflag = 0;
|
||||
mode = (char *)NULL;
|
||||
while ((opt = internal_getopt(list, "m:p")) != -1)
|
||||
switch (opt)
|
||||
{
|
||||
case 'p':
|
||||
pflag = 1;
|
||||
break;
|
||||
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);
|
||||
}
|
||||
|
||||
if (mode == NULL)
|
||||
omode = S_IRWXU | S_IRWXG | S_IRWXO; /* a=rwx */
|
||||
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, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
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 = (S_IRWXU | S_IRWXG | S_IRWXO) & ~original_umask;
|
||||
parent_mode = nmode | (S_IWUSR|S_IXUSR); /* u+wx */
|
||||
|
||||
/* Adjust new mode based on mode argument */
|
||||
nmode &= omode;
|
||||
|
||||
for (rval = EXECUTION_SUCCESS, l = list; l; l = l->next)
|
||||
{
|
||||
if (pflag && make_path (l->word->word, mflag, nmode, parent_mode))
|
||||
{
|
||||
rval = EXECUTION_FAILURE;
|
||||
continue;
|
||||
}
|
||||
else if (pflag == 0 && mkdir (l->word->word, nmode) < 0)
|
||||
{
|
||||
builtin_error ("cannot create directory `%s': %s", l->word->word, strerror (errno));
|
||||
rval = EXECUTION_FAILURE;
|
||||
}
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/* Make all the directories leading up to PATH, then create PATH. Note that
|
||||
this changes the process's umask; make sure that all paths leading to a
|
||||
return reset it to ORIGINAL_UMASK */
|
||||
static int
|
||||
make_path (path, user_mode, nmode, parent_mode)
|
||||
char *path;
|
||||
int user_mode;
|
||||
int nmode, parent_mode;
|
||||
{
|
||||
int oumask;
|
||||
struct stat sb;
|
||||
char *p, *npath;
|
||||
|
||||
if (stat (path, &sb) == 0)
|
||||
{
|
||||
if (S_ISDIR (sb.st_mode) == 0)
|
||||
{
|
||||
builtin_error ("`%s': file exists but is not a directory", path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (user_mode && chmod (path, nmode))
|
||||
{
|
||||
builtin_error ("%s: %s", path, strerror (errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
oumask = umask (0);
|
||||
npath = savestring (path); /* So we can write to it. */
|
||||
|
||||
/* Check whether or not we need to do anything with intermediate dirs. */
|
||||
|
||||
/* Skip leading slashes. */
|
||||
p = npath;
|
||||
while (*p == '/')
|
||||
p++;
|
||||
|
||||
while (p = strchr (p, '/'))
|
||||
{
|
||||
*p = '\0';
|
||||
if (stat (npath, &sb) != 0)
|
||||
{
|
||||
if (mkdir (npath, 0))
|
||||
{
|
||||
builtin_error ("cannot create directory `%s': %s", npath, strerror (errno));
|
||||
umask (original_umask);
|
||||
free (npath);
|
||||
return 1;
|
||||
}
|
||||
if (chmod (npath, parent_mode) != 0)
|
||||
{
|
||||
builtin_error ("cannot chmod directory `%s': %s", npath, strerror (errno));
|
||||
umask (original_umask);
|
||||
free (npath);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (S_ISDIR (sb.st_mode) == 0)
|
||||
{
|
||||
builtin_error ("`%s': file exists but is not a directory", npath);
|
||||
umask (original_umask);
|
||||
free (npath);
|
||||
return 1;
|
||||
}
|
||||
|
||||
*p++ = '/'; /* restore slash */
|
||||
while (*p == '/')
|
||||
p++;
|
||||
}
|
||||
|
||||
/* Create the final directory component. */
|
||||
if (stat (npath, &sb) && mkdir (npath, nmode))
|
||||
{
|
||||
builtin_error ("cannot create directory `%s': %s", npath, strerror (errno));
|
||||
umask (original_umask);
|
||||
free (npath);
|
||||
return 1;
|
||||
}
|
||||
|
||||
umask (original_umask);
|
||||
free (npath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *mkdir_doc[] = {
|
||||
"Create directories.",
|
||||
"",
|
||||
"Make directories. Create the directories named as arguments, in",
|
||||
"the order specified, using mode rwxrwxrwx as modified by the current",
|
||||
"umask (see `help umask'). The -m option causes the file permission",
|
||||
"bits of the final directory 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=rwx\". The -p option causes any required",
|
||||
"intermediate directories in PATH to be created. The directories",
|
||||
"are created with permission bits of rwxrwxrwx as modified by the current",
|
||||
"umask, plus write and search permissions for the owner. mkdir",
|
||||
"returns 0 if the directories are created successfully, and non-zero",
|
||||
"if an error occurs.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin mkdir_struct = {
|
||||
"mkdir",
|
||||
mkdir_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
mkdir_doc,
|
||||
"mkdir [-p] [-m mode] directory [directory ...]",
|
||||
0
|
||||
};
|
146
examples/loadables/mkfifo.c
Normal file
146
examples/loadables/mkfifo.c
Normal 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
examples/loadables/mktemp.c
Normal file
212
examples/loadables/mktemp.c
Normal 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 */
|
||||
};
|
89
examples/loadables/mypid.c
Normal file
89
examples/loadables/mypid.c
Normal file
|
@ -0,0 +1,89 @@
|
|||
/* This module should be dynamically loaded with enable -f
|
||||
* which would create a new builtin named mypid. You'll need
|
||||
* the source code for GNU bash to recompile this module.
|
||||
*
|
||||
* Then, from within bash, enable -f ./mypid enable_mypid, where ./mypid
|
||||
* is the binary obtained from running make. Hereafter, `${MYPID}'
|
||||
* is a shell builtin variable.
|
||||
*
|
||||
* This defines an unload hook function that is called when the builtin is
|
||||
* deleted with enable -d that will unbind the MYPID variable so future
|
||||
* references to it do not attempt to access memory that is no longer part
|
||||
* of this process's address space.
|
||||
*/
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
|
||||
#define INIT_DYNAMIC_VAR(var, val, gfunc, afunc) \
|
||||
do \
|
||||
{ SHELL_VAR *v = bind_variable (var, (val), 0); \
|
||||
if (v) \
|
||||
{ \
|
||||
v->dynamic_value = gfunc; \
|
||||
v->assign_func = afunc; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
static SHELL_VAR *
|
||||
assign_mypid (
|
||||
SHELL_VAR *self,
|
||||
char *value,
|
||||
arrayind_t unused,
|
||||
char *key )
|
||||
{
|
||||
return (self);
|
||||
}
|
||||
|
||||
static SHELL_VAR *
|
||||
get_mypid (SHELL_VAR *var)
|
||||
{
|
||||
int rv;
|
||||
char *p;
|
||||
|
||||
rv = getpid();
|
||||
p = itos (rv);
|
||||
|
||||
FREE (value_cell (var));
|
||||
|
||||
VSETATTR (var, att_integer);
|
||||
var_setvalue (var, p);
|
||||
return (var);
|
||||
}
|
||||
|
||||
int
|
||||
enable_mypid_builtin(WORD_LIST *list)
|
||||
{
|
||||
INIT_DYNAMIC_VAR ("MYPID", (char *)NULL, get_mypid, assign_mypid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
enable_mypid_builtin_unload (char *s)
|
||||
{
|
||||
unbind_variable ("MYPID");
|
||||
}
|
||||
|
||||
char const *enable_mypid_doc[] = {
|
||||
"Enable $MYPID.",
|
||||
"",
|
||||
"Enables use of the ${MYPID} dynamic variable. ",
|
||||
"It will yield the current pid of a subshell.",
|
||||
(char *)0
|
||||
};
|
||||
|
||||
struct builtin enable_mypid_struct = {
|
||||
"enable_mypid",
|
||||
enable_mypid_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
(char**)(void*)enable_mypid_doc,
|
||||
"enable_mypid N",
|
||||
0
|
||||
};
|
54
examples/loadables/necho.c
Normal file
54
examples/loadables/necho.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
/* necho - echo without options or argument interpretation */
|
||||
|
||||
/* Sample builtin to be dynamically loaded with enable -f and replace an
|
||||
existing builtin. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 <stdio.h>
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
|
||||
int
|
||||
necho_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
print_word_list (list, " ");
|
||||
printf("\n");
|
||||
fflush (stdout);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *necho_doc[] = {
|
||||
"Display arguments.",
|
||||
"",
|
||||
"Print the arguments to the standard output separated",
|
||||
"by space characters and terminated with a newline.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin necho_struct = {
|
||||
"echo",
|
||||
necho_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
necho_doc,
|
||||
"echo [args]",
|
||||
0
|
||||
};
|
||||
|
381
examples/loadables/pathchk.c
Normal file
381
examples/loadables/pathchk.c
Normal file
|
@ -0,0 +1,381 @@
|
|||
/* pathchk - check pathnames for validity and portability */
|
||||
|
||||
/* Usage: pathchk [-p] path ...
|
||||
|
||||
For each PATH, print a message if any of these conditions are false:
|
||||
* all existing leading directories in PATH have search (execute) permission
|
||||
* strlen (PATH) <= PATH_MAX
|
||||
* strlen (each_directory_in_PATH) <= NAME_MAX
|
||||
|
||||
Exit status:
|
||||
0 All PATH names passed all of the tests.
|
||||
1 An error occurred.
|
||||
|
||||
Options:
|
||||
-p Instead of performing length checks on the
|
||||
underlying filesystem, test the length of the
|
||||
pathname and its components against the POSIX.1
|
||||
minimum limits for portability, _POSIX_NAME_MAX
|
||||
and _POSIX_PATH_MAX in 2.9.2. Also check that
|
||||
the pathname contains no character not in the
|
||||
portable filename character set. */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 <sys/types.h>
|
||||
#include "posixstat.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_LIMITS_H)
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "stdc.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "maxpath.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#if !defined (_POSIX_PATH_MAX)
|
||||
# define _POSIX_PATH_MAX 255
|
||||
#endif
|
||||
#if !defined (_POSIX_NAME_MAX)
|
||||
# define _POSIX_NAME_MAX 14
|
||||
#endif
|
||||
|
||||
/* How do we get PATH_MAX? */
|
||||
#if defined (_POSIX_VERSION) && !defined (PATH_MAX)
|
||||
# define PATH_MAX_FOR(p) pathconf ((p), _PC_PATH_MAX)
|
||||
#endif
|
||||
|
||||
/* How do we get NAME_MAX? */
|
||||
#if defined (_POSIX_VERSION) && !defined (NAME_MAX)
|
||||
# define NAME_MAX_FOR(p) pathconf ((p), _PC_NAME_MAX)
|
||||
#endif
|
||||
|
||||
#if !defined (PATH_MAX_FOR)
|
||||
# define PATH_MAX_FOR(p) PATH_MAX
|
||||
#endif
|
||||
|
||||
#if !defined (NAME_MAX_FOR)
|
||||
# define NAME_MAX_FOR(p) NAME_MAX
|
||||
#endif
|
||||
|
||||
extern char *strerror ();
|
||||
|
||||
static int validate_path ();
|
||||
|
||||
int
|
||||
pathchk_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int retval, pflag, opt;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "p")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'p':
|
||||
pflag = 1;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
for (retval = 0; list; list = list->next)
|
||||
retval |= validate_path (list->word->word, pflag);
|
||||
|
||||
return (retval ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *pathchk_doc[] = {
|
||||
"Check pathnames for validity.",
|
||||
"",
|
||||
"Check each pathname argument for validity (i.e., it may be used to",
|
||||
"create or access a file without causing syntax errors) and portability",
|
||||
"(i.e., no filename truncation will result). If the `-p' option is",
|
||||
"supplied, more extensive portability checks are performed.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
/* The standard structure describing a builtin command. bash keeps an array
|
||||
of these structures. */
|
||||
struct builtin pathchk_struct = {
|
||||
"pathchk", /* builtin name */
|
||||
pathchk_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
pathchk_doc, /* array of long documentation strings. */
|
||||
"pathchk [-p] pathname ...", /* usage synopsis */
|
||||
0 /* reserved for internal use */
|
||||
};
|
||||
|
||||
/* The remainder of this file is stolen shamelessly from `pathchk.c' in
|
||||
the sh-utils-1.12 distribution, by
|
||||
|
||||
David MacKenzie <djm@gnu.ai.mit.edu>
|
||||
and Jim Meyering <meyering@cs.utexas.edu> */
|
||||
|
||||
/* Each element is nonzero if the corresponding ASCII character is
|
||||
in the POSIX portable character set, and zero if it is not.
|
||||
In addition, the entry for `/' is nonzero to simplify checking. */
|
||||
static char const portable_chars[256] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-15 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16-31 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, /* 32-47 */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 48-63 */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64-79 */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 80-95 */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 96-111 */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 112-127 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/* If PATH contains only portable characters, return 1, else 0. */
|
||||
|
||||
static int
|
||||
portable_chars_only (path)
|
||||
const char *path;
|
||||
{
|
||||
const char *p;
|
||||
|
||||
for (p = path; *p; ++p)
|
||||
if (portable_chars[(const unsigned char) *p] == 0)
|
||||
{
|
||||
builtin_error ("path `%s' contains nonportable character `%c'", path, *p);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* On some systems, stat can return EINTR. */
|
||||
|
||||
#ifndef EINTR
|
||||
# define SAFE_STAT(name, buf) stat (name, buf)
|
||||
#else
|
||||
# define SAFE_STAT(name, buf) safe_stat (name, buf)
|
||||
static inline int
|
||||
safe_stat (name, buf)
|
||||
const char *name;
|
||||
struct stat *buf;
|
||||
{
|
||||
int ret;
|
||||
|
||||
do
|
||||
ret = stat (name, buf);
|
||||
while (ret < 0 && errno == EINTR);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return 1 if PATH is a usable leading directory, 0 if not,
|
||||
2 if it doesn't exist. */
|
||||
|
||||
static int
|
||||
dir_ok (path)
|
||||
const char *path;
|
||||
{
|
||||
struct stat stats;
|
||||
|
||||
if (SAFE_STAT (path, &stats))
|
||||
return 2;
|
||||
|
||||
if (!S_ISDIR (stats.st_mode))
|
||||
{
|
||||
builtin_error ("`%s' is not a directory", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Use access to test for search permission because
|
||||
testing permission bits of st_mode can lose with new
|
||||
access control mechanisms. Of course, access loses if you're
|
||||
running setuid. */
|
||||
if (access (path, X_OK) != 0)
|
||||
{
|
||||
if (errno == EACCES)
|
||||
builtin_error ("directory `%s' is not searchable", path);
|
||||
else
|
||||
builtin_error ("%s: %s", path, strerror (errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char *
|
||||
xstrdup (s)
|
||||
char *s;
|
||||
{
|
||||
return (savestring (s));
|
||||
}
|
||||
|
||||
/* Make sure that
|
||||
strlen (PATH) <= PATH_MAX
|
||||
&& strlen (each-existing-directory-in-PATH) <= NAME_MAX
|
||||
|
||||
If PORTABILITY is nonzero, compare against _POSIX_PATH_MAX and
|
||||
_POSIX_NAME_MAX instead, and make sure that PATH contains no
|
||||
characters not in the POSIX portable filename character set, which
|
||||
consists of A-Z, a-z, 0-9, ., _, -.
|
||||
|
||||
Make sure that all leading directories along PATH that exist have
|
||||
`x' permission.
|
||||
|
||||
Return 0 if all of these tests are successful, 1 if any fail. */
|
||||
|
||||
static int
|
||||
validate_path (path, portability)
|
||||
char *path;
|
||||
int portability;
|
||||
{
|
||||
int path_max;
|
||||
int last_elem; /* Nonzero if checking last element of path. */
|
||||
int exists; /* 2 if the path element exists. */
|
||||
char *slash;
|
||||
char *parent; /* Last existing leading directory so far. */
|
||||
|
||||
if (portability && !portable_chars_only (path))
|
||||
return 1;
|
||||
|
||||
if (*path == '\0')
|
||||
return 0;
|
||||
|
||||
#ifdef lint
|
||||
/* Suppress `used before initialized' warning. */
|
||||
exists = 0;
|
||||
#endif
|
||||
|
||||
/* Figure out the parent of the first element in PATH. */
|
||||
parent = xstrdup (*path == '/' ? "/" : ".");
|
||||
|
||||
slash = path;
|
||||
last_elem = 0;
|
||||
while (1)
|
||||
{
|
||||
int name_max;
|
||||
int length; /* Length of partial path being checked. */
|
||||
char *start; /* Start of path element being checked. */
|
||||
|
||||
/* Find the end of this element of the path.
|
||||
Then chop off the rest of the path after this element. */
|
||||
while (*slash == '/')
|
||||
slash++;
|
||||
start = slash;
|
||||
slash = strchr (slash, '/');
|
||||
if (slash != NULL)
|
||||
*slash = '\0';
|
||||
else
|
||||
{
|
||||
last_elem = 1;
|
||||
slash = strchr (start, '\0');
|
||||
}
|
||||
|
||||
if (!last_elem)
|
||||
{
|
||||
exists = dir_ok (path);
|
||||
if (exists == 0)
|
||||
{
|
||||
free (parent);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
length = slash - start;
|
||||
/* Since we know that `parent' is a directory, it's ok to call
|
||||
pathconf with it as the argument. (If `parent' isn't a directory
|
||||
or doesn't exist, the behavior of pathconf is undefined.)
|
||||
But if `parent' is a directory and is on a remote file system,
|
||||
it's likely that pathconf can't give us a reasonable value
|
||||
and will return -1. (NFS and tempfs are not POSIX . . .)
|
||||
In that case, we have no choice but to assume the pessimal
|
||||
POSIX minimums. */
|
||||
name_max = portability ? _POSIX_NAME_MAX : NAME_MAX_FOR (parent);
|
||||
if (name_max < 0)
|
||||
name_max = _POSIX_NAME_MAX;
|
||||
if (length > name_max)
|
||||
{
|
||||
builtin_error ("name `%s' has length %d; exceeds limit of %d",
|
||||
start, length, name_max);
|
||||
free (parent);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (last_elem)
|
||||
break;
|
||||
|
||||
if (exists == 1)
|
||||
{
|
||||
free (parent);
|
||||
parent = xstrdup (path);
|
||||
}
|
||||
|
||||
*slash++ = '/';
|
||||
}
|
||||
|
||||
/* `parent' is now the last existing leading directory in the whole path,
|
||||
so it's ok to call pathconf with it as the argument. */
|
||||
path_max = portability ? _POSIX_PATH_MAX : PATH_MAX_FOR (parent);
|
||||
if (path_max < 0)
|
||||
path_max = _POSIX_PATH_MAX;
|
||||
free (parent);
|
||||
if (strlen (path) > path_max)
|
||||
{
|
||||
builtin_error ("path `%s' has length %lu; exceeds limit of %d",
|
||||
path, (unsigned long)strlen (path), path_max);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
99
examples/loadables/perl/Makefile.in
Normal file
99
examples/loadables/perl/Makefile.in
Normal file
|
@ -0,0 +1,99 @@
|
|||
#
|
||||
# Makefile for builtin perl interpreter
|
||||
#
|
||||
#
|
||||
# Copyright (C) 1998 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
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# Include some boilerplate Gnu makefile definitions.
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
|
||||
bindir = @bindir@
|
||||
libdir = @libdir@
|
||||
infodir = @infodir@
|
||||
includedir = @includedir@
|
||||
|
||||
datarootdir = @datarootdir@
|
||||
|
||||
topdir = @top_srcdir@
|
||||
BUILD_DIR = @BUILD_DIR@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
@SET_MAKE@
|
||||
CC = @CC@
|
||||
RM = rm -f
|
||||
|
||||
SHELL = @MAKE_SHELL@
|
||||
|
||||
PERL5 = perl5
|
||||
|
||||
CFLAGS = @CFLAGS@
|
||||
|
||||
#
|
||||
# These values are generated for configure by ${topdir}/support/shobj-conf.
|
||||
# If your system is not supported by that script, but includes facilities for
|
||||
# dynamic loading of shared objects, please update the script and send the
|
||||
# changes to bash-maintainers@gnu.org.
|
||||
#
|
||||
SHOBJ_CC = @SHOBJ_CC@
|
||||
SHOBJ_CFLAGS = @SHOBJ_CFLAGS@
|
||||
SHOBJ_LD = @SHOBJ_LD@
|
||||
SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@
|
||||
SHOBJ_XLDFLAGS = @SHOBJ_XLDFLAGS@
|
||||
SHOBJ_LIBS = @SHOBJ_LIBS@
|
||||
SHOBJ_STATUS = @SHOBJ_STATUS@
|
||||
|
||||
# Values used for compiling the perl files
|
||||
PERL_LDOPTS = `${PERL5} -MExtUtils::Embed -e ldopts`
|
||||
PERL_CFLAGS = ${CCFLAGS} `${PERL5} -MExtUtils::Embed -e ccopts`
|
||||
|
||||
SRC = bperl.c iperl.c perlxsi.c
|
||||
OBJ = bperl.o iperl.o perlxsi.o
|
||||
|
||||
BUILTIN = bperl5
|
||||
|
||||
INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins \
|
||||
-I$(topdir)/include -I$(BUILD_DIR) -I$(BUILD_DIR)/lib \
|
||||
-I$(BUILD_DIR)/builtins
|
||||
|
||||
|
||||
${BUILTIN}: ${OBJ}
|
||||
${RM} $@
|
||||
${SHOBJ_LD} ${SHOBJ_LDFLAGS} ${SHOBJ_XLDFLAGS} -o $@ ${OBJ} ${PERL_LDOPTS} ${SHOBJ_LIBS}
|
||||
|
||||
bperl.o: bperl.c
|
||||
${RM} $@
|
||||
$(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CFLAGS) $(INC) -c -o $@ ${srcdir}/bperl.c
|
||||
|
||||
iperl.o: iperl.c
|
||||
${RM} $@
|
||||
$(SHOBJ_CC) ${SHOBJ_CFLAGS} $(PERL_CFLAGS) -c -o $@ ${srcdir}/iperl.c
|
||||
|
||||
perlxsi.c:
|
||||
${PERL5} -MExtUtils::Embed -e xsinit -- -o $@
|
||||
|
||||
perlxsi.o: perlxsi.c
|
||||
${RM} $@
|
||||
${SHOBJ_CC} ${SHOBJ_CFLAGS} $(PERL_CFLAGS) -c -o $@ perlxsi.c
|
||||
|
||||
clean mostlyclean:
|
||||
${RM} ${OBJ}
|
||||
${RM} ${BUILTIN}
|
||||
|
||||
distclean maintainer-clean: clean
|
||||
${RM} perlxsi.c
|
6
examples/loadables/perl/README
Normal file
6
examples/loadables/perl/README
Normal file
|
@ -0,0 +1,6 @@
|
|||
This illustrates how to build a perl interpreter into bash. It's not
|
||||
especially useful; more a proof of concept (it provides none of the
|
||||
bash internals to the perl interpreter, for example).
|
||||
|
||||
This *may* require adding "-rpath /path/to/perl/CORE" and -lperl options
|
||||
when compiling bash itself.
|
53
examples/loadables/perl/bperl.c
Normal file
53
examples/loadables/perl/bperl.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* perl builtin
|
||||
*/
|
||||
#include <config.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
extern char **make_builtin_argv (WORD_LIST *, int *);
|
||||
extern char **export_env;
|
||||
|
||||
extern void perl_close(void);
|
||||
extern int perl_main(int, char **, char **);
|
||||
|
||||
int
|
||||
bperl_builtin(WORD_LIST *list)
|
||||
{
|
||||
char **v;
|
||||
int c, r;
|
||||
|
||||
v = make_builtin_argv(list, &c);
|
||||
r = perl_main(c, v, export_env);
|
||||
free(v);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
bperl_builtin_unload (char *s)
|
||||
{
|
||||
perl_close();
|
||||
}
|
||||
|
||||
char *bperl_doc[] = {
|
||||
"An interface to a perl5 interpreter.",
|
||||
(char *)0
|
||||
};
|
||||
|
||||
struct builtin bperl_struct = {
|
||||
"bperl",
|
||||
bperl_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
bperl_doc,
|
||||
"bperl [perl options] [file ...]",
|
||||
0
|
||||
};
|
38
examples/loadables/perl/iperl.c
Normal file
38
examples/loadables/perl/iperl.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
#include <EXTERN.h> /* from the Perl distribution */
|
||||
#include <perl.h> /* from the Perl distribution */
|
||||
|
||||
#define iperl my_perl /* I guess the name `my_perl' is required */
|
||||
|
||||
extern void xs_init (pTHX);
|
||||
|
||||
static PerlInterpreter *iperl; /*** The Perl interpreter ***/
|
||||
|
||||
static int first = 1;
|
||||
|
||||
void
|
||||
perl_close (void)
|
||||
{
|
||||
PERL_SYS_TERM();
|
||||
}
|
||||
|
||||
int
|
||||
perl_main(int argc, char **argv, char **env)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (first) {
|
||||
first = 0;
|
||||
PERL_SYS_INIT3(&argc, &argv, &env);
|
||||
}
|
||||
iperl = perl_alloc();
|
||||
perl_construct(iperl);
|
||||
perl_parse(iperl, xs_init, argc, argv, (char **)NULL);
|
||||
r = perl_run(iperl);
|
||||
|
||||
PerlIO_flush(PerlIO_stdout());
|
||||
PerlIO_flush(PerlIO_stderr());
|
||||
|
||||
perl_destruct(iperl);
|
||||
perl_free(iperl);
|
||||
return (r);
|
||||
}
|
193
examples/loadables/print.c
Normal file
193
examples/loadables/print.c
Normal file
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* print -- loadable ksh-93 style print builtin
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "bashtypes.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "shell.h"
|
||||
#include "builtins.h"
|
||||
#include "stdc.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "builtext.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
int print_builtin ();
|
||||
static int printargs ();
|
||||
|
||||
static FILE *ofp;
|
||||
|
||||
extern char *this_command_name;
|
||||
|
||||
static char *print_doc[] = {
|
||||
"Display arguments.",
|
||||
"",
|
||||
"Output the arguments. The -f option means to use the argument as a",
|
||||
"format string as would be supplied to printf(1). The rest of the",
|
||||
"options are as in ksh.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin print_struct = {
|
||||
"print",
|
||||
print_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
print_doc,
|
||||
"print [-Rnprs] [-u unit] [-f format] [arguments]",
|
||||
(char *)0
|
||||
};
|
||||
|
||||
#ifndef ISOPTION
|
||||
#define ISOPTION(s, c) (s[0] == '-' && s[2] == '\0' && s[1] == c)
|
||||
#endif
|
||||
|
||||
int
|
||||
print_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int c, r, nflag, raw, ofd, sflag;
|
||||
intmax_t lfd;
|
||||
char **v, *pfmt, *arg;
|
||||
WORD_LIST *l;
|
||||
|
||||
nflag = raw = sflag = 0;
|
||||
ofd = 1;
|
||||
pfmt = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((c = internal_getopt (list, "Rnprsu:f:")) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'R':
|
||||
raw = 2;
|
||||
loptend = lcurrent;
|
||||
if (loptend && ISOPTION (loptend->word->word, 'n'))
|
||||
{
|
||||
loptend = loptend->next;
|
||||
nflag = 1;
|
||||
}
|
||||
goto opt_end;
|
||||
case 'r':
|
||||
raw = 1;
|
||||
break;
|
||||
case 'n':
|
||||
nflag = 1;
|
||||
break;
|
||||
case 's':
|
||||
sflag = 1;
|
||||
break;
|
||||
case 'p':
|
||||
break; /* NOP */
|
||||
case 'u':
|
||||
if (all_digits (list_optarg) && legal_number (list_optarg, &lfd) && lfd == (int)lfd)
|
||||
ofd = lfd;
|
||||
else
|
||||
{
|
||||
for (l = list; l->next && l->next != lcurrent; l = l->next);
|
||||
lcurrent = loptend = l;
|
||||
goto opt_end;
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
pfmt = list_optarg;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
opt_end:
|
||||
list = loptend;
|
||||
|
||||
ofp = (ofd == 1) ? stdout : fdopen (dup (ofd), "w");
|
||||
|
||||
if (pfmt)
|
||||
{
|
||||
WORD_DESC *w;
|
||||
WORD_LIST *nlist;
|
||||
|
||||
w = make_word (pfmt);
|
||||
nlist = make_word_list (w, list);
|
||||
r = printf_builtin (nlist);
|
||||
nlist->next = (WORD_LIST *)NULL;
|
||||
dispose_words (nlist);
|
||||
return (r);
|
||||
}
|
||||
|
||||
if (raw)
|
||||
{
|
||||
for (l = list; l; l = l->next)
|
||||
{
|
||||
fprintf (ofp, "%s", l->word->word);
|
||||
if (l->next)
|
||||
fprintf (ofp, " ");
|
||||
}
|
||||
if (nflag == 0)
|
||||
fprintf (ofp, "\n");
|
||||
fflush (ofp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
r = printargs (list, ofp);
|
||||
if (r && nflag == 0)
|
||||
fprintf (ofp, "\n");
|
||||
if (ofd != 1)
|
||||
fclose (ofp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
printargs (list, ofp)
|
||||
WORD_LIST *list;
|
||||
FILE *ofp;
|
||||
{
|
||||
WORD_LIST *l;
|
||||
char *ostr;
|
||||
int sawc;
|
||||
|
||||
for (sawc = 0, l = list; l; l = l->next)
|
||||
{
|
||||
ostr = ansicstr (l->word->word, strlen (l->word->word), 0, &sawc, (int *)0);
|
||||
if (ostr)
|
||||
fprintf (ofp, "%s", ostr);
|
||||
free (ostr);
|
||||
if (sawc)
|
||||
return (0);
|
||||
if (l->next)
|
||||
fprintf (ofp, " ");
|
||||
}
|
||||
return (1);
|
||||
}
|
94
examples/loadables/printenv.c
Normal file
94
examples/loadables/printenv.c
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* printenv -- minimal builtin clone of BSD printenv(1).
|
||||
*
|
||||
* usage: printenv [varname]
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 <stdio.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
extern char **export_env;
|
||||
|
||||
int
|
||||
printenv_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register char **envp;
|
||||
int opt;
|
||||
SHELL_VAR *var;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
/* printenv */
|
||||
if (list == 0)
|
||||
{
|
||||
maybe_make_export_env (); /* this allows minimal code */
|
||||
for (envp = export_env; *envp; envp++)
|
||||
printf ("%s\n", *envp);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* printenv varname */
|
||||
var = find_variable (list->word->word);
|
||||
if (var == 0 || (exported_p (var) == 0))
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
if (function_p (var))
|
||||
print_var_function (var);
|
||||
else
|
||||
print_var_value (var, 0);
|
||||
|
||||
printf("\n");
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *printenv_doc[] = {
|
||||
"Display environment.",
|
||||
"",
|
||||
"Print names and values of environment variables",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin printenv_struct = {
|
||||
"printenv",
|
||||
printenv_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
printenv_doc,
|
||||
"printenv [varname]",
|
||||
0
|
||||
};
|
117
examples/loadables/push.c
Normal file
117
examples/loadables/push.c
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* push - anyone remember TOPS-20?
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
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 <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "jobs.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
extern pid_t dollar_dollar_pid;
|
||||
extern int last_command_exit_value;
|
||||
|
||||
int
|
||||
push_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
pid_t pid;
|
||||
int xstatus, opt;
|
||||
|
||||
xstatus = EXECUTION_SUCCESS;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
pid = make_child (savestring ("push"), 0);
|
||||
if (pid == -1)
|
||||
{
|
||||
builtin_error ("cannot fork: %s", strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
/* Shell variable adjustments: $SHLVL, $$, $PPID, $! */
|
||||
adjust_shell_level (1);
|
||||
dollar_dollar_pid = getpid ();
|
||||
set_ppid ();
|
||||
|
||||
/* Clean up job control stuff. */
|
||||
stop_making_children ();
|
||||
cleanup_the_pipeline ();
|
||||
delete_all_jobs (0);
|
||||
|
||||
last_asynchronous_pid = NO_PID;
|
||||
|
||||
/* Make sure the job control code has the right values for
|
||||
the shell's process group and tty process group, and that
|
||||
the signals are set correctly for job control. */
|
||||
initialize_job_control (0);
|
||||
initialize_job_signals ();
|
||||
|
||||
/* And read commands until exit. */
|
||||
reader_loop ();
|
||||
exit_shell (last_command_exit_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
stop_pipeline (0, (COMMAND *)NULL);
|
||||
xstatus = wait_for (pid, 0);
|
||||
return (xstatus);
|
||||
}
|
||||
}
|
||||
|
||||
char *push_doc[] = {
|
||||
"Create child shell.",
|
||||
"",
|
||||
"Create a child that is an exact duplicate of the running shell",
|
||||
"and wait for it to exit. The $SHLVL, $!, $$, and $PPID variables",
|
||||
"are adjusted in the child. The return value is the exit status",
|
||||
"of the child.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin push_struct = {
|
||||
"push",
|
||||
push_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
push_doc,
|
||||
"push",
|
||||
0
|
||||
};
|
207
examples/loadables/realpath.c
Normal file
207
examples/loadables/realpath.c
Normal file
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* realpath -- canonicalize pathnames, resolving symlinks
|
||||
*
|
||||
* usage: realpath [-cqsv] [-a name] pathname [pathname...]
|
||||
*
|
||||
* options: -a name assign each canonicalized pathname to indexed array
|
||||
* variable NAME
|
||||
* -c check whether or not each resolved path exists
|
||||
* -q no output, exit status determines whether path is valid
|
||||
* -s strip . and .. from the pathname only, no symlink resolution
|
||||
* -v produce verbose output
|
||||
*
|
||||
*
|
||||
* exit status: 0 if all pathnames resolved
|
||||
* 1 if any of the pathname arguments could not be resolved
|
||||
*
|
||||
*
|
||||
* Bash loadable builtin version
|
||||
*
|
||||
* Chet Ramey
|
||||
* chet@po.cwru.edu
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009,2021,2022 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 <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include "bashansi.h"
|
||||
#include <maxpath.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
extern char *sh_realpath();
|
||||
|
||||
int
|
||||
realpath_builtin(WORD_LIST *list)
|
||||
{
|
||||
int opt, cflag, vflag, qflag, sflag, aflag, es;
|
||||
char *r, realbuf[PATH_MAX], *p, *newpath;
|
||||
struct stat sb;
|
||||
#if defined (ARRAY_VARS)
|
||||
arrayind_t ind;
|
||||
char *aname;
|
||||
SHELL_VAR *v;
|
||||
#endif
|
||||
|
||||
if (list == 0) {
|
||||
builtin_usage();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
vflag = cflag = qflag = aflag = sflag = 0;
|
||||
#if defined (ARRAY_VARS)
|
||||
aname = NULL;
|
||||
v = NULL;
|
||||
ind = 0;
|
||||
#endif
|
||||
reset_internal_getopt();
|
||||
while ((opt = internal_getopt (list, "a:cqsv")) != -1) {
|
||||
switch (opt) {
|
||||
#if defined (ARRAY_VARS)
|
||||
case 'a':
|
||||
aflag = 1;
|
||||
aname = list_optarg;
|
||||
break;
|
||||
#endif
|
||||
case 'c':
|
||||
cflag = 1;
|
||||
break;
|
||||
case 'q':
|
||||
qflag = 1;
|
||||
break;
|
||||
case 's':
|
||||
sflag = 1;
|
||||
break;
|
||||
case 'v':
|
||||
vflag = 1;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (list == 0) {
|
||||
builtin_usage();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (aflag && legal_identifier (aname) == 0) {
|
||||
sh_invalidid(aname);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
if (aname && builtin_unbind_variable (aname) == -2)
|
||||
return (EXECUTION_FAILURE);
|
||||
if (aname) {
|
||||
v = find_or_make_array_variable (aname, 1);
|
||||
if (v == 0 || readonly_p (v) || noassign_p (v)) {
|
||||
if (v && readonly_p (v))
|
||||
err_readonly (aname);
|
||||
return (EXECUTION_FAILURE);
|
||||
} else if (array_p (v) == 0) {
|
||||
builtin_error ("%s: not an indexed array", aname);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
if (invisible_p (v))
|
||||
VUNSETATTR (v, att_invisible);
|
||||
array_flush (array_cell (v));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (es = EXECUTION_SUCCESS; list; list = list->next) {
|
||||
p = list->word->word;
|
||||
if (sflag) {
|
||||
/* sh_canonpath doesn't convert to absolute pathnames */
|
||||
newpath = make_absolute(p, get_string_value("PWD"));
|
||||
r = sh_canonpath(newpath, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
|
||||
free(newpath);
|
||||
} else
|
||||
r = sh_realpath(p, realbuf);
|
||||
if (r == 0) {
|
||||
es = EXECUTION_FAILURE;
|
||||
if (qflag == 0)
|
||||
builtin_error("%s: cannot resolve: %s", p, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
if (cflag && (stat(r, &sb) < 0)) {
|
||||
es = EXECUTION_FAILURE;
|
||||
if (qflag == 0)
|
||||
builtin_error("%s: %s", p, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
if (aflag) {
|
||||
bind_array_element (v, ind, r, 0);
|
||||
ind++;
|
||||
}
|
||||
if (qflag == 0) {
|
||||
if (vflag)
|
||||
printf ("%s -> ", p);
|
||||
printf("%s\n", r);
|
||||
}
|
||||
if (sflag)
|
||||
free (r);
|
||||
}
|
||||
return es;
|
||||
}
|
||||
|
||||
char *realpath_doc[] = {
|
||||
"Display pathname in canonical form.",
|
||||
"",
|
||||
"Display the canonicalized version of each PATHNAME argument, resolving",
|
||||
"symbolic links.",
|
||||
"The -a option stores each canonicalized PATHNAME argument into the indexed",
|
||||
"array VARNAME.",
|
||||
"The -c option checks whether or not each resolved name exists.",
|
||||
"The -q option produces no output; the exit status determines the",
|
||||
"validity of each PATHNAME, but any array assignment is still performed.",
|
||||
"If the -s option is supplied, canonicalize . and .. pathname components",
|
||||
"without resolving symbolic links.",
|
||||
"The -v option produces verbose output.",
|
||||
"The exit status is 0 if each PATHNAME was resolved; non-zero otherwise.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin realpath_struct = {
|
||||
"realpath", /* builtin name */
|
||||
realpath_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
realpath_doc, /* array of long documentation strings */
|
||||
"realpath [-a varname] [-cqsv] pathname [pathname...]", /* usage synopsis */
|
||||
0 /* reserved for internal use */
|
||||
};
|
185
examples/loadables/rm.c
Normal file
185
examples/loadables/rm.c
Normal file
|
@ -0,0 +1,185 @@
|
|||
/* rm - remove files and directories with -r */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 2016 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 <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
static int rm_file(const char *fname);
|
||||
|
||||
static int force, recursive;
|
||||
|
||||
static int
|
||||
_remove_directory(const char *dirname)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *dp;
|
||||
size_t dirlen;
|
||||
int err;
|
||||
|
||||
dirlen = strlen (dirname);
|
||||
err = 0;
|
||||
|
||||
if ((dir = opendir(dirname)))
|
||||
{
|
||||
while ((dp = readdir(dir)))
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
char fname[dirlen + 1 + strlen (dp->d_name) + 1];
|
||||
#else
|
||||
char *fname;
|
||||
int fnsize;
|
||||
#endif
|
||||
|
||||
QUIT;
|
||||
if (*dp->d_name == '.' && (dp->d_name[1] == 0 || (dp->d_name[1] == '.' && dp->d_name[2] == 0)))
|
||||
continue;
|
||||
|
||||
#ifdef __GNUC__
|
||||
snprintf(fname, sizeof (fname), "%s/%s", dirname, dp->d_name);
|
||||
#else
|
||||
fnsize = dirlen + 1 + strlen (dp->d_name) + 1;
|
||||
fname = xmalloc (fnsize);
|
||||
snprintf(fname, fnsize, "%s/%s", dirname, dp->d_name);
|
||||
#endif
|
||||
|
||||
if (rm_file (fname) && force == 0)
|
||||
err = 1;
|
||||
#ifndef __GNUC__
|
||||
free (fname);
|
||||
#endif
|
||||
QUIT;
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
if (err == 0 && rmdir (dirname) && force == 0)
|
||||
err = 1;
|
||||
}
|
||||
else if (force == 0)
|
||||
err = 1;
|
||||
|
||||
if (err)
|
||||
builtin_error ("%s: %s", dirname, strerror (errno));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
rm_file(const char *fname)
|
||||
{
|
||||
if (unlink (fname) == 0)
|
||||
return 0;
|
||||
|
||||
QUIT;
|
||||
/* If FNAME is a directory glibc returns EISDIR but correct POSIX value
|
||||
would be EPERM. If we get that error and FNAME is a directory and -r
|
||||
was supplied, recursively remove the directory and its contents */
|
||||
if ((errno == EISDIR || errno == EPERM) && recursive && file_isdir (fname))
|
||||
return _remove_directory(fname);
|
||||
else if (force)
|
||||
return 0;
|
||||
|
||||
builtin_error ("%s: %s", fname, strerror (errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
rm_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
const char *name;
|
||||
WORD_LIST *l;
|
||||
int rval, opt;
|
||||
|
||||
recursive = force = 0;
|
||||
rval = EXECUTION_SUCCESS;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "Rrfi")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'R':
|
||||
case 'r':
|
||||
recursive = 1;
|
||||
break;
|
||||
case 'f':
|
||||
force = 1;
|
||||
break;
|
||||
case 'i':
|
||||
return (EX_DISKFALLBACK);
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
if (force == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
for (l = list; l; l = l->next)
|
||||
{
|
||||
QUIT;
|
||||
if (rm_file(l->word->word) && force == 0)
|
||||
rval = EXECUTION_FAILURE;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
char *rm_doc[] = {
|
||||
"Remove files.",
|
||||
"",
|
||||
"rm removes the files specified as arguments.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
/* The standard structure describing a builtin command. bash keeps an array
|
||||
of these structures. */
|
||||
struct builtin rm_struct = {
|
||||
"rm", /* builtin name */
|
||||
rm_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
rm_doc, /* array of long documentation strings. */
|
||||
"rm [-rf] file ...", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
72
examples/loadables/rmdir.c
Normal file
72
examples/loadables/rmdir.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
/* rmdir - remove directory */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
int
|
||||
rmdir_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int rval;
|
||||
WORD_LIST *l;
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
|
||||
for (rval = EXECUTION_SUCCESS, l = list; l; l = l->next)
|
||||
if (rmdir (l->word->word) < 0)
|
||||
{
|
||||
builtin_error ("%s: %s", l->word->word, strerror (errno));
|
||||
rval = EXECUTION_FAILURE;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
char *rmdir_doc[] = {
|
||||
"Remove directory.",
|
||||
"",
|
||||
"rmdir removes the directory entry specified by each argument,",
|
||||
"provided the directory is empty.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
/* The standard structure describing a builtin command. bash keeps an array
|
||||
of these structures. */
|
||||
struct builtin rmdir_struct = {
|
||||
"rmdir", /* builtin name */
|
||||
rmdir_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
rmdir_doc, /* array of long documentation strings. */
|
||||
"rmdir directory ...", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
502
examples/loadables/seq.c
Normal file
502
examples/loadables/seq.c
Normal file
|
@ -0,0 +1,502 @@
|
|||
/* seq - print sequence of numbers to standard output.
|
||||
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
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written as bash builtin by Chet Ramey. Portions from seq.c by Ulrich Drepper. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "loadables.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#if defined (PRI_MACROS_BROKEN)
|
||||
# undef PRIdMAX
|
||||
#endif
|
||||
|
||||
#if !defined (PRIdMAX)
|
||||
# if HAVE_LONG_LONG
|
||||
# define PRIdMAX "lld"
|
||||
# else
|
||||
# define PRIdMAX "ld"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD && !defined(STRTOLD_BROKEN)
|
||||
typedef long double floatmax_t;
|
||||
# define FLOATMAX_CONV "L"
|
||||
# define strtofltmax strtold
|
||||
# define FLOATMAX_FMT "%Lg"
|
||||
# define FLOATMAX_WFMT "%0.Lf"
|
||||
# define USE_LONG_DOUBLE
|
||||
#else
|
||||
typedef double floatmax_t;
|
||||
# define FLOATMAX_CONV ""
|
||||
# define strtofltmax strtod
|
||||
# define FLOATMAX_FMT "%g"
|
||||
# define FLOATMAX_WFMT "%0.f"
|
||||
#endif
|
||||
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))
|
||||
|
||||
static int conversion_error = 0;
|
||||
|
||||
/* If true print all number with equal width. */
|
||||
static int equal_width;
|
||||
|
||||
/* The string used to separate two numbers. */
|
||||
static char const *separator;
|
||||
|
||||
/* The string output after all numbers have been output. */
|
||||
static char const terminator[] = "\n";
|
||||
|
||||
static char decimal_point;
|
||||
|
||||
/* Pretty much the same as the version in builtins/printf.def */
|
||||
static floatmax_t
|
||||
getfloatmax (arg)
|
||||
const char *arg;
|
||||
{
|
||||
floatmax_t ret;
|
||||
char *ep;
|
||||
|
||||
errno = 0;
|
||||
ret = strtofltmax (arg, &ep);
|
||||
|
||||
if (*ep)
|
||||
{
|
||||
sh_invalidnum ((char *)arg);
|
||||
conversion_error = 1;
|
||||
}
|
||||
else if (errno == ERANGE)
|
||||
{
|
||||
builtin_error ("warning: %s: %s", arg, strerror(ERANGE));
|
||||
conversion_error = 1;
|
||||
}
|
||||
|
||||
if (ret == -0.0)
|
||||
ret = 0.0;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* If FORMAT is a valid printf format for a double argument, return
|
||||
its long double equivalent, allocated from dynamic storage. This
|
||||
was written by Ulrich Drepper, taken from coreutils:seq.c */
|
||||
static char *
|
||||
long_double_format (char const *fmt)
|
||||
{
|
||||
size_t i;
|
||||
size_t length_modifier_offset;
|
||||
int has_L;
|
||||
|
||||
for (i = 0; ! (fmt[i] == '%' && fmt[i + 1] != '%'); i += (fmt[i] == '%') + 1)
|
||||
{
|
||||
if (!fmt[i])
|
||||
{
|
||||
builtin_error ("format %s has no %% directive", fmt);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
i += strspn (fmt + i, "-+#0 '"); /* zero or more flags */
|
||||
i += strspn (fmt + i, "0123456789"); /* optional minimum field width */
|
||||
if (fmt[i] == '.') /* optional precision */
|
||||
{
|
||||
i++;
|
||||
i += strspn (fmt + i, "0123456789");
|
||||
}
|
||||
|
||||
length_modifier_offset = i; /* optional length modifier */
|
||||
/* we could ignore an 'l' length modifier here */
|
||||
has_L = (fmt[i] == 'L');
|
||||
i += has_L;
|
||||
switch (fmt[i])
|
||||
{
|
||||
case '\0':
|
||||
builtin_error ("format %s ends in %%", fmt);
|
||||
return 0;
|
||||
case 'A':
|
||||
case 'a':
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'F':
|
||||
case 'g':
|
||||
case 'G':
|
||||
break;
|
||||
default:
|
||||
builtin_error ("format %s has unknown `%%%c' directive", fmt, fmt[i]);
|
||||
return 0;
|
||||
}
|
||||
for (i++; ; i += (fmt[i] == '%') + 1)
|
||||
if (fmt[i] == '%' && fmt[i + 1] != '%')
|
||||
{
|
||||
builtin_error ("format %s has too many %% directives", fmt);
|
||||
return 0;
|
||||
}
|
||||
else if (fmt[i] == 0)
|
||||
{
|
||||
size_t format_size = i + 1;
|
||||
char *ldfmt = xmalloc (format_size + 1);
|
||||
memcpy (ldfmt, fmt, length_modifier_offset);
|
||||
#ifdef USE_LONG_DOUBLE
|
||||
ldfmt[length_modifier_offset] = 'L';
|
||||
strcpy (ldfmt + length_modifier_offset + 1,
|
||||
fmt + length_modifier_offset + has_L);
|
||||
#else
|
||||
strcpy (ldfmt + length_modifier_offset, fmt + length_modifier_offset);
|
||||
#endif
|
||||
return ldfmt;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the number of digits following the decimal point in NUMBUF */
|
||||
static int
|
||||
getprec (numbuf)
|
||||
const char *numbuf;
|
||||
{
|
||||
int p;
|
||||
char *dp;
|
||||
|
||||
if (dp = strchr (numbuf, decimal_point))
|
||||
dp++; /* skip over decimal point */
|
||||
for (p = 0; dp && *dp && ISDIGIT (*dp); dp++)
|
||||
p++;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Return the default format given FIRST, INCR, and LAST. */
|
||||
static char *
|
||||
genformat (first, incr, last)
|
||||
floatmax_t first, incr, last;
|
||||
{
|
||||
static char buf[6 + 2 * INT_STRLEN_BOUND (int)];
|
||||
int wfirst, wlast, width;
|
||||
int iprec, fprec, lprec, prec;
|
||||
|
||||
if (equal_width == 0)
|
||||
return (FLOATMAX_FMT);
|
||||
|
||||
/* OK, we have to figure out the largest number of decimal places. This is
|
||||
a little more expensive than using the original strings. */
|
||||
snprintf (buf, sizeof (buf), FLOATMAX_FMT, incr);
|
||||
iprec = getprec (buf);
|
||||
|
||||
wfirst = snprintf (buf, sizeof (buf), FLOATMAX_FMT, first);
|
||||
fprec = getprec (buf);
|
||||
|
||||
prec = MAX (fprec, iprec);
|
||||
|
||||
wlast = snprintf (buf, sizeof (buf), FLOATMAX_FMT, last);
|
||||
lprec = getprec (buf);
|
||||
|
||||
/* increase first width by any increased precision in increment */
|
||||
wfirst += (prec - fprec);
|
||||
|
||||
/* adjust last width to use precision from first/incr */
|
||||
wlast += (prec - lprec);
|
||||
|
||||
if (lprec && prec == 0)
|
||||
wlast--; /* no decimal point */
|
||||
if (lprec == 0 && prec)
|
||||
wlast++; /* include decimal point */
|
||||
if (fprec == 0 && prec)
|
||||
wfirst++; /* include decimal point */
|
||||
|
||||
width = MAX (wfirst, wlast);
|
||||
if (width)
|
||||
sprintf (buf, "%%0%d.%d%sf", width, prec, FLOATMAX_CONV);
|
||||
else
|
||||
sprintf (buf, "%%.%d%sf", prec, FLOATMAX_CONV);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
int
|
||||
print_fltseq (fmt, first, last, incr)
|
||||
const char *fmt;
|
||||
floatmax_t first, last, incr;
|
||||
{
|
||||
int n;
|
||||
floatmax_t next;
|
||||
const char *s;
|
||||
|
||||
n = 0; /* iteration counter */
|
||||
s = "";
|
||||
for (next = first; incr >= 0 ? (next <= last) : (next >= last); next = first + n * incr)
|
||||
{
|
||||
QUIT;
|
||||
if (*s && fputs (s, stdout) == EOF)
|
||||
return (sh_chkwrite (EXECUTION_FAILURE));
|
||||
if (printf (fmt, next) < 0)
|
||||
return (sh_chkwrite (EXECUTION_FAILURE));
|
||||
s = separator;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (n > 0 && fputs (terminator, stdout) == EOF)
|
||||
return (sh_chkwrite (EXECUTION_FAILURE));
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
/* must be <= INT_STRLEN_BOUND(intmax_t) */
|
||||
int
|
||||
width_needed (num)
|
||||
intmax_t num;
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = num < 0; /* sign */
|
||||
if (ret)
|
||||
num = -num;
|
||||
do
|
||||
ret++;
|
||||
while (num /= 10);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
print_intseq (ifirst, ilast, iincr)
|
||||
intmax_t ifirst, ilast, iincr;
|
||||
{
|
||||
char intwfmt[6 + INT_STRLEN_BOUND(int) + sizeof (PRIdMAX)];
|
||||
const char *s;
|
||||
intmax_t i, next;
|
||||
|
||||
/* compute integer format string */
|
||||
if (equal_width) /* -w supplied */
|
||||
{
|
||||
int wfirst, wlast, width;
|
||||
|
||||
wfirst = width_needed (ifirst);
|
||||
wlast = width_needed (ilast);
|
||||
width = MAX(wfirst, wlast);
|
||||
|
||||
/* The leading %s is for the separator */
|
||||
snprintf (intwfmt, sizeof (intwfmt), "%%s%%0%u" PRIdMAX, width);
|
||||
}
|
||||
|
||||
/* We could use braces.c:mkseq here but that allocates lots of memory */
|
||||
s = "";
|
||||
for (i = ifirst; (ifirst <= ilast) ? (i <= ilast) : (i >= ilast); i = next)
|
||||
{
|
||||
QUIT;
|
||||
/* The leading %s is for the separator */
|
||||
if (printf (equal_width ? intwfmt : "%s%" PRIdMAX, s, i) < 0)
|
||||
return (sh_chkwrite (EXECUTION_FAILURE));
|
||||
s = separator;
|
||||
next = i + iincr;
|
||||
}
|
||||
|
||||
if (fputs (terminator, stdout) == EOF)
|
||||
return (sh_chkwrite (EXECUTION_FAILURE));
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
int
|
||||
seq_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
floatmax_t first, last, incr;
|
||||
intmax_t ifirst, ilast, iincr;
|
||||
WORD_LIST *l;
|
||||
int opt, nargs, intseq, freefmt;
|
||||
char *first_str, *incr_str, *last_str;
|
||||
char const *fmtstr; /* The printf(3) format used for output. */
|
||||
|
||||
equal_width = 0;
|
||||
separator = "\n";
|
||||
fmtstr = NULL;
|
||||
|
||||
first = 1.0;
|
||||
last = 0.0;
|
||||
incr = 0.0; /* set later */
|
||||
ifirst = ilast = iincr = 0;
|
||||
first_str = incr_str = last_str = 0;
|
||||
|
||||
intseq = freefmt = 0;
|
||||
opt = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while (opt != -1)
|
||||
{
|
||||
l = lcurrent ? lcurrent : list;
|
||||
if (l && l->word && l->word->word && l->word->word[0] == '-' &&
|
||||
(l->word->word[1] == '.' || DIGIT (l->word->word[1])))
|
||||
{
|
||||
loptend = l;
|
||||
break; /* negative number */
|
||||
}
|
||||
if ((opt = internal_getopt (list, "f:s:w")) == -1)
|
||||
break;
|
||||
|
||||
switch (opt)
|
||||
{
|
||||
case 'f':
|
||||
fmtstr = list_optarg;
|
||||
break;
|
||||
case 's':
|
||||
separator = list_optarg;
|
||||
break;
|
||||
case 'w':
|
||||
equal_width = 1;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
for (nargs = 1, l = list; l->next; l = l->next)
|
||||
nargs++;
|
||||
if (nargs > 3)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* LAST */
|
||||
conversion_error = 0;
|
||||
last = getfloatmax (last_str = l->word->word);
|
||||
if (conversion_error)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
/* FIRST LAST */
|
||||
if (nargs > 1)
|
||||
{
|
||||
conversion_error = 0;
|
||||
first = getfloatmax (first_str = list->word->word);
|
||||
if (conversion_error)
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* FIRST INCR LAST */
|
||||
if (nargs > 2)
|
||||
{
|
||||
conversion_error = 0;
|
||||
incr = getfloatmax (incr_str = list->next->word->word);
|
||||
if (conversion_error)
|
||||
return (EXECUTION_FAILURE);
|
||||
if (incr == 0.0)
|
||||
{
|
||||
builtin_error ("zero %screment", (first < last) ? "in" : "de");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sanitize arguments */
|
||||
if (incr == 0.0)
|
||||
incr = (first <= last) ? 1.0 : -1.0;
|
||||
if ((incr < 0.0 && first < last) || (incr > 0 && first > last))
|
||||
{
|
||||
builtin_error ("incorrect %screment", (first < last) ? "in" : "de");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* validate format here */
|
||||
if (fmtstr)
|
||||
{
|
||||
fmtstr = long_double_format (fmtstr);
|
||||
freefmt = 1;
|
||||
if (fmtstr == 0)
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (fmtstr != NULL && equal_width)
|
||||
{
|
||||
builtin_warning ("-w ignored when the format string is specified");
|
||||
equal_width = 0;
|
||||
}
|
||||
|
||||
/* Placeholder for later additional conditions */
|
||||
if (last_str && all_digits (last_str) &&
|
||||
(first_str == 0 || all_digits (first_str)) &&
|
||||
(incr_str == 0 || all_digits (incr_str)) &&
|
||||
fmtstr == NULL)
|
||||
intseq = 1;
|
||||
|
||||
if (intseq)
|
||||
{
|
||||
ifirst = (intmax_t)first; /* truncation */
|
||||
ilast = (intmax_t)last;
|
||||
iincr = (intmax_t)incr;
|
||||
|
||||
return (print_intseq (ifirst, ilast, iincr));
|
||||
}
|
||||
|
||||
decimal_point = locale_decpoint ();
|
||||
if (fmtstr == NULL)
|
||||
fmtstr = genformat (first, incr, last);
|
||||
|
||||
print_fltseq (fmtstr, first, last, incr);
|
||||
|
||||
if (freefmt)
|
||||
free ((void *)fmtstr);
|
||||
return sh_chkwrite (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Taken largely from GNU seq. */
|
||||
char *seq_doc[] = {
|
||||
"Print numbers from FIRST to LAST, in steps of INCREMENT.",
|
||||
"",
|
||||
"-f FORMAT use printf style floating-point FORMAT",
|
||||
"-s STRING use STRING to separate numbers (default: \\n)",
|
||||
"-w equalize width by padding with leading zeroes",
|
||||
"",
|
||||
"If FIRST or INCREMENT is omitted, it defaults to 1. However, an",
|
||||
"omitted INCREMENT defaults to -1 when LAST is smaller than FIRST.",
|
||||
"The sequence of numbers ends when the sum of the current number and",
|
||||
"INCREMENT would become greater than LAST.",
|
||||
"FIRST, INCREMENT, and LAST are interpreted as floating point values.",
|
||||
"",
|
||||
"FORMAT must be suitable for printing one argument of type 'double';",
|
||||
"it defaults to %.PRECf if FIRST, INCREMENT, and LAST are all fixed point",
|
||||
"decimal numbers with maximum precision PREC, and to %g otherwise.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin seq_struct = {
|
||||
"seq",
|
||||
seq_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
seq_doc,
|
||||
"seq [-f format] [-s separator] [-w] [FIRST [INCR]] LAST",
|
||||
0
|
||||
};
|
121
examples/loadables/setpgid.c
Normal file
121
examples/loadables/setpgid.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
/* setpgid.c: bash loadable wrapper for setpgid system call
|
||||
|
||||
An example of how to wrap a system call with a loadable builtin.
|
||||
|
||||
Originally contributed by Jason Vas Dias <jason.vas.dias@gmail.com>
|
||||
|
||||
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 <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include "posixtime.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#if !defined (_POSIX_VERSION)
|
||||
# define setpgid(pid, pgrp) setpgrp (pid, pgrp)
|
||||
#endif
|
||||
|
||||
int
|
||||
setpgid_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register WORD_LIST *wl;
|
||||
intmax_t pid_arg, pgid_arg;
|
||||
pid_t pid, pgid;
|
||||
char *pidstr, *pgidstr;
|
||||
|
||||
wl = list;
|
||||
pid = pgid = 0;
|
||||
|
||||
if (wl == 0 || wl->next == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
pidstr = wl->word ? wl->word->word : 0;
|
||||
pgidstr = wl->next->word ? wl->next->word->word : 0;
|
||||
|
||||
if (pidstr == 0 || pgidstr == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
if (legal_number (pidstr, &pid_arg) == 0)
|
||||
{
|
||||
builtin_error ("%s: pid argument must be numeric", pidstr);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
if (pid_arg < 0)
|
||||
{
|
||||
builtin_error("%s: negative pid values not allowed", pidstr);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
pid = pid_arg;
|
||||
|
||||
if (legal_number (pgidstr, &pgid_arg) == 0)
|
||||
{
|
||||
builtin_error ("%s: pgrp argument must be numeric", pgidstr);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
if (pgid_arg < 0)
|
||||
{
|
||||
builtin_error ("%s: negative pgrp values not allowed", pgidstr);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
pgid = pgid_arg;
|
||||
|
||||
errno = 0;
|
||||
if (setpgid(pid, pgid) < 0)
|
||||
{
|
||||
builtin_error("setpgid failed: %s", strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
const char *setpgid_doc[] = {
|
||||
"invoke the setpgid(2) system call",
|
||||
"",
|
||||
"Arguments:",
|
||||
" pid : numeric process identifier, >= 0",
|
||||
" pgrpid: numeric process group identifier, >=0",
|
||||
"See the setpgid(2) manual page.",
|
||||
(const char *)NULL
|
||||
};
|
||||
|
||||
struct builtin setpgid_struct = {
|
||||
"setpgid",
|
||||
setpgid_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
(char **)setpgid_doc,
|
||||
"setpgid pid pgrpid",
|
||||
0
|
||||
};
|
179
examples/loadables/sleep.c
Normal file
179
examples/loadables/sleep.c
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* sleep -- sleep for fractions of a second
|
||||
*
|
||||
* usage: sleep seconds[.fraction]
|
||||
*
|
||||
* as an extension, we support the GNU time interval format (2m20s)
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2021 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"
|
||||
|
||||
#if defined (TIME_WITH_SYS_TIME)
|
||||
# include <sys/time.h>
|
||||
# include <time.h>
|
||||
#else
|
||||
# if defined (HAVE_SYS_TIME_H)
|
||||
# include <sys/time.h>
|
||||
# else
|
||||
# include <time.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "chartypes.h"
|
||||
|
||||
#include "loadables.h"
|
||||
|
||||
#define S_SEC 1
|
||||
#define S_MIN (60*S_SEC)
|
||||
#define S_HOUR (60*S_MIN)
|
||||
#define S_DAY (24*S_HOUR)
|
||||
|
||||
static int
|
||||
parse_gnutimefmt (char *string, long *sp, long *up)
|
||||
{
|
||||
int c, r;
|
||||
char *s, *ep;
|
||||
long tsec, tusec, accumsec, accumusec, t;
|
||||
int mult;
|
||||
|
||||
tsec = tusec = 0;
|
||||
accumsec = accumusec = 0;
|
||||
mult = 1;
|
||||
|
||||
for (s = string; s && *s; s++) {
|
||||
r = uconvert(s, &accumsec, &accumusec, &ep);
|
||||
if (r == 0 && *ep == 0)
|
||||
return r;
|
||||
c = *ep;
|
||||
mult = 1;
|
||||
switch (c) {
|
||||
case '\0':
|
||||
case 's':
|
||||
mult = S_SEC;
|
||||
break;
|
||||
case 'm':
|
||||
mult = S_MIN;
|
||||
break;
|
||||
case 'h':
|
||||
mult = S_HOUR;
|
||||
break;
|
||||
case 'd':
|
||||
mult = S_DAY;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* multiply the accumulated value by the multiplier */
|
||||
t = accumusec * mult;
|
||||
accumsec = accumsec * mult + (t / 1000000);
|
||||
accumusec = t % 1000000;
|
||||
|
||||
/* add to running total */
|
||||
tsec += accumsec;
|
||||
tusec += accumusec;
|
||||
if (tusec >= 1000000) {
|
||||
tsec++;
|
||||
tusec -= 1000000;
|
||||
}
|
||||
|
||||
/* reset and continue */
|
||||
accumsec = accumusec = 0;
|
||||
mult = 1;
|
||||
if (c == 0)
|
||||
break;
|
||||
s = ep;
|
||||
}
|
||||
|
||||
if (sp)
|
||||
*sp = tsec;
|
||||
if (up)
|
||||
*up = tusec;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
sleep_builtin (WORD_LIST *list)
|
||||
{
|
||||
long sec, usec;
|
||||
char *ep;
|
||||
int r, mul;
|
||||
time_t t;
|
||||
|
||||
if (list == 0) {
|
||||
builtin_usage();
|
||||
return(EX_USAGE);
|
||||
}
|
||||
|
||||
/* Skip over `--' */
|
||||
if (list->word && ISOPTION (list->word->word, '-'))
|
||||
list = list->next;
|
||||
|
||||
if (*list->word->word == '-' || list->next) {
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
r = uconvert(list->word->word, &sec, &usec, &ep);
|
||||
/*
|
||||
* Maybe postprocess conversion failures here based on EP
|
||||
*
|
||||
* A heuristic: if the conversion failed, but the argument appears to
|
||||
* contain a GNU-like interval specifier (e.g. "1m30s"), try to parse
|
||||
* it. If we can't, return the right exit code to tell
|
||||
* execute_builtin to try and execute a disk command instead.
|
||||
*/
|
||||
if (r == 0 && (strchr ("dhms", *ep) || strpbrk (list->word->word, "dhms")))
|
||||
r = parse_gnutimefmt (list->word->word, &sec, &usec);
|
||||
|
||||
if (r) {
|
||||
fsleep(sec, usec);
|
||||
QUIT;
|
||||
return(EXECUTION_SUCCESS);
|
||||
}
|
||||
builtin_error("%s: bad sleep interval", list->word->word);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
static char *sleep_doc[] = {
|
||||
"Suspend execution for specified period.",
|
||||
""
|
||||
"sleep suspends execution for a minimum of SECONDS[.FRACTION] seconds.",
|
||||
"As an extension, sleep accepts GNU-style time intervals (e.g., 2m30s).",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin sleep_struct = {
|
||||
"sleep",
|
||||
sleep_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
sleep_doc,
|
||||
"sleep seconds[.fraction]",
|
||||
0
|
||||
};
|
464
examples/loadables/stat.c
Normal file
464
examples/loadables/stat.c
Normal file
|
@ -0,0 +1,464 @@
|
|||
/* stat - load up an associative array with stat information about a file */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 2016,2022 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 <sys/types.h>
|
||||
#include "posixstat.h"
|
||||
#include <stdio.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <errno.h>
|
||||
#include "posixtime.h"
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "shell.h"
|
||||
#include "builtins.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#define ST_NAME 0
|
||||
#define ST_DEV 1
|
||||
#define ST_INO 2
|
||||
#define ST_MODE 3
|
||||
#define ST_NLINK 4
|
||||
#define ST_UID 5
|
||||
#define ST_GID 6
|
||||
#define ST_RDEV 7
|
||||
#define ST_SIZE 8
|
||||
#define ST_ATIME 9
|
||||
#define ST_MTIME 10
|
||||
#define ST_CTIME 11
|
||||
#define ST_BLKSIZE 12
|
||||
#define ST_BLOCKS 13
|
||||
#define ST_CHASELINK 14
|
||||
#define ST_PERMS 15
|
||||
|
||||
#define ST_END 16
|
||||
|
||||
static char *arraysubs[] =
|
||||
{
|
||||
"name", "device", "inode", "type", "nlink", "uid", "gid", "rdev",
|
||||
"size", "atime", "mtime", "ctime", "blksize", "blocks", "link", "perms",
|
||||
0
|
||||
};
|
||||
|
||||
#define DEFTIMEFMT "%a %b %e %k:%M:%S %Z %Y"
|
||||
#ifndef TIMELEN_MAX
|
||||
# define TIMELEN_MAX 128
|
||||
#endif
|
||||
|
||||
static char *stattime (time_t, const char *);
|
||||
|
||||
static int
|
||||
getstat (fname, flags, sp)
|
||||
const char *fname;
|
||||
int flags;
|
||||
struct stat *sp;
|
||||
{
|
||||
intmax_t lfd;
|
||||
int fd, r;
|
||||
|
||||
if (strncmp (fname, "/dev/fd/", 8) == 0)
|
||||
{
|
||||
if ((legal_number(fname + 8, &lfd) == 0) || (int)lfd != lfd)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
fd = lfd;
|
||||
r = fstat(fd, sp);
|
||||
}
|
||||
#ifdef HAVE_LSTAT
|
||||
else if (flags & 1)
|
||||
r = lstat(fname, sp);
|
||||
#endif
|
||||
else
|
||||
r = stat(fname, sp);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static char *
|
||||
statlink (fname, sp)
|
||||
char *fname;
|
||||
struct stat *sp;
|
||||
{
|
||||
#if defined (HAVE_READLINK)
|
||||
char linkbuf[PATH_MAX];
|
||||
int n;
|
||||
|
||||
if (fname && S_ISLNK (sp->st_mode) && (n = readlink (fname, linkbuf, PATH_MAX)) > 0)
|
||||
{
|
||||
linkbuf[n] = '\0';
|
||||
return (savestring (linkbuf));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
return (savestring (fname));
|
||||
}
|
||||
|
||||
static char *
|
||||
octalperms (m)
|
||||
int m;
|
||||
{
|
||||
int operms;
|
||||
char *ret;
|
||||
|
||||
operms = 0;
|
||||
|
||||
if (m & S_IRUSR)
|
||||
operms |= 0400;
|
||||
if (m & S_IWUSR)
|
||||
operms |= 0200;
|
||||
if (m & S_IXUSR)
|
||||
operms |= 0100;
|
||||
|
||||
if (m & S_IRGRP)
|
||||
operms |= 0040;
|
||||
if (m & S_IWGRP)
|
||||
operms |= 0020;
|
||||
if (m & S_IXGRP)
|
||||
operms |= 0010;
|
||||
|
||||
if (m & S_IROTH)
|
||||
operms |= 0004;
|
||||
if (m & S_IWOTH)
|
||||
operms |= 0002;
|
||||
if (m & S_IXOTH)
|
||||
operms |= 0001;
|
||||
|
||||
if (m & S_ISUID)
|
||||
operms |= 04000;
|
||||
if (m & S_ISGID)
|
||||
operms |= 02000;
|
||||
if (m & S_ISVTX)
|
||||
operms |= 01000;
|
||||
|
||||
ret = (char *)xmalloc (16);
|
||||
snprintf (ret, 16, "%04o", operms);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *
|
||||
statperms (m)
|
||||
int m;
|
||||
{
|
||||
char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */
|
||||
int i;
|
||||
char *ret;
|
||||
|
||||
i = 0;
|
||||
if (m & S_IRUSR)
|
||||
ubits[i++] = 'r';
|
||||
if (m & S_IWUSR)
|
||||
ubits[i++] = 'w';
|
||||
if (m & S_IXUSR)
|
||||
ubits[i++] = 'x';
|
||||
ubits[i] = '\0';
|
||||
|
||||
i = 0;
|
||||
if (m & S_IRGRP)
|
||||
gbits[i++] = 'r';
|
||||
if (m & S_IWGRP)
|
||||
gbits[i++] = 'w';
|
||||
if (m & S_IXGRP)
|
||||
gbits[i++] = 'x';
|
||||
gbits[i] = '\0';
|
||||
|
||||
i = 0;
|
||||
if (m & S_IROTH)
|
||||
obits[i++] = 'r';
|
||||
if (m & S_IWOTH)
|
||||
obits[i++] = 'w';
|
||||
if (m & S_IXOTH)
|
||||
obits[i++] = 'x';
|
||||
obits[i] = '\0';
|
||||
|
||||
if (m & S_ISUID)
|
||||
ubits[2] = (m & S_IXUSR) ? 's' : 'S';
|
||||
if (m & S_ISGID)
|
||||
gbits[2] = (m & S_IXGRP) ? 's' : 'S';
|
||||
if (m & S_ISVTX)
|
||||
obits[2] = (m & S_IXOTH) ? 't' : 'T';
|
||||
|
||||
ret = (char *)xmalloc (32);
|
||||
snprintf (ret, 32, "u=%s,g=%s,o=%s", ubits, gbits, obits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *
|
||||
statmode(mode)
|
||||
int mode;
|
||||
{
|
||||
char *modestr, *m;
|
||||
|
||||
modestr = m = (char *)xmalloc (8);
|
||||
if (S_ISBLK (mode))
|
||||
*m++ = 'b';
|
||||
if (S_ISCHR (mode))
|
||||
*m++ = 'c';
|
||||
if (S_ISDIR (mode))
|
||||
*m++ = 'd';
|
||||
if (S_ISREG(mode))
|
||||
*m++ = '-';
|
||||
if (S_ISFIFO(mode))
|
||||
*m++ = 'p';
|
||||
if (S_ISLNK(mode))
|
||||
*m++ = 'l';
|
||||
if (S_ISSOCK(mode))
|
||||
*m++ = 's';
|
||||
|
||||
#ifdef S_ISDOOR
|
||||
if (S_ISDOOR (mode))
|
||||
*m++ = 'D';
|
||||
#endif
|
||||
#ifdef S_ISWHT
|
||||
if (S_ISWHT(mode))
|
||||
*m++ = 'W';
|
||||
#endif
|
||||
#ifdef S_ISNWK
|
||||
if (S_ISNWK(mode))
|
||||
*m++ = 'n';
|
||||
#endif
|
||||
#ifdef S_ISMPC
|
||||
if (S_ISMPC (mode))
|
||||
*m++ = 'm';
|
||||
#endif
|
||||
|
||||
*m = '\0';
|
||||
return (modestr);
|
||||
}
|
||||
|
||||
static char *
|
||||
stattime (t, timefmt)
|
||||
time_t t;
|
||||
const char *timefmt;
|
||||
{
|
||||
char *tbuf, *ret;
|
||||
const char *fmt;
|
||||
size_t tlen;
|
||||
struct tm *tm;
|
||||
|
||||
fmt = timefmt ? timefmt : DEFTIMEFMT;
|
||||
tm = localtime (&t);
|
||||
|
||||
ret = xmalloc (TIMELEN_MAX);
|
||||
|
||||
tlen = strftime (ret, TIMELEN_MAX, fmt, tm);
|
||||
if (tlen == 0)
|
||||
tlen = strftime (ret, TIMELEN_MAX, DEFTIMEFMT, tm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *
|
||||
statval (which, fname, flags, fmt, sp)
|
||||
int which;
|
||||
char *fname;
|
||||
int flags;
|
||||
char *fmt;
|
||||
struct stat *sp;
|
||||
{
|
||||
int temp;
|
||||
|
||||
switch (which)
|
||||
{
|
||||
case ST_NAME:
|
||||
return savestring (fname);
|
||||
case ST_DEV:
|
||||
return itos (sp->st_dev);
|
||||
case ST_INO:
|
||||
return itos (sp->st_ino);
|
||||
case ST_MODE:
|
||||
return (statmode (sp->st_mode));
|
||||
case ST_NLINK:
|
||||
return itos (sp->st_nlink);
|
||||
case ST_UID:
|
||||
return itos (sp->st_uid);
|
||||
case ST_GID:
|
||||
return itos (sp->st_gid);
|
||||
case ST_RDEV:
|
||||
return itos (sp->st_rdev);
|
||||
case ST_SIZE:
|
||||
return itos (sp->st_size);
|
||||
case ST_ATIME:
|
||||
return ((flags & 2) ? stattime (sp->st_atime, fmt) : itos (sp->st_atime));
|
||||
case ST_MTIME:
|
||||
return ((flags & 2) ? stattime (sp->st_mtime, fmt) : itos (sp->st_mtime));
|
||||
case ST_CTIME:
|
||||
return ((flags & 2) ? stattime (sp->st_ctime, fmt) : itos (sp->st_ctime));
|
||||
case ST_BLKSIZE:
|
||||
return itos (sp->st_blksize);
|
||||
case ST_BLOCKS:
|
||||
return itos (sp->st_blocks);
|
||||
case ST_CHASELINK:
|
||||
return (statlink (fname, sp));
|
||||
case ST_PERMS:
|
||||
temp = sp->st_mode & (S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID);
|
||||
return (flags & 2) ? statperms (temp) : octalperms (temp);
|
||||
default:
|
||||
return savestring ("42");
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
loadstat (vname, var, fname, flags, fmt, sp)
|
||||
char *vname;
|
||||
SHELL_VAR *var;
|
||||
char *fname;
|
||||
int flags;
|
||||
char *fmt;
|
||||
struct stat *sp;
|
||||
{
|
||||
int i;
|
||||
char *key, *value;
|
||||
SHELL_VAR *v;
|
||||
|
||||
for (i = 0; arraysubs[i]; i++)
|
||||
{
|
||||
key = savestring (arraysubs[i]);
|
||||
value = statval (i, fname, flags, fmt, sp);
|
||||
v = bind_assoc_variable (var, vname, key, value, ASS_FORCE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
stat_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt, flags;
|
||||
char *aname, *fname, *timefmt;
|
||||
struct stat st;
|
||||
SHELL_VAR *v;
|
||||
|
||||
aname = "STAT";
|
||||
flags = 0;
|
||||
timefmt = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "A:F:Ll")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'A':
|
||||
aname = list_optarg;
|
||||
break;
|
||||
case 'L':
|
||||
flags |= 1; /* operate on links rather than resolving them */
|
||||
break;
|
||||
case 'l':
|
||||
flags |= 2;
|
||||
break;
|
||||
case 'F':
|
||||
timefmt = list_optarg;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
if (legal_identifier (aname) == 0)
|
||||
{
|
||||
sh_invalidid (aname);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
unbind_variable (aname);
|
||||
#endif
|
||||
fname = list->word->word;
|
||||
|
||||
if (getstat (fname, flags, &st) < 0)
|
||||
{
|
||||
builtin_error ("%s: cannot stat: %s", fname, strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
v = find_or_make_array_variable (aname, 3);
|
||||
if (v == 0)
|
||||
{
|
||||
builtin_error ("%s: cannot create variable", aname);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
if (loadstat (aname, v, fname, flags, timefmt, &st) < 0)
|
||||
{
|
||||
builtin_error ("%s: cannot assign file status information", aname);
|
||||
unbind_variable (aname);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* An array of strings forming the `long' documentation for a builtin xxx,
|
||||
which is printed by `help xxx'. It must end with a NULL. By convention,
|
||||
the first line is a short description. */
|
||||
char *stat_doc[] = {
|
||||
"Load an associative array with file status information.",
|
||||
"",
|
||||
"Take a filename and load the status information returned by a",
|
||||
"stat(2) call on that file into the associative array specified",
|
||||
"by the -A option. The default array name is STAT.",
|
||||
"",
|
||||
"If the -L option is supplied, stat does not resolve symbolic links",
|
||||
"and reports information about the link itself. The -l option results",
|
||||
"in longer-form listings for some of the fields. When -l is used,",
|
||||
"the -F option supplies a format string passed to strftime(3) to",
|
||||
"display the file time information.",
|
||||
"The exit status is 0 unless the stat fails or assigning the array",
|
||||
"is unsuccessful.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
/* The standard structure describing a builtin command. bash keeps an array
|
||||
of these structures. The flags must include BUILTIN_ENABLED so the
|
||||
builtin can be used. */
|
||||
struct builtin stat_struct = {
|
||||
"stat", /* builtin name */
|
||||
stat_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
stat_doc, /* array of long documentation strings. */
|
||||
"stat [-lL] [-A aname] file", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
128
examples/loadables/strftime.c
Normal file
128
examples/loadables/strftime.c
Normal file
|
@ -0,0 +1,128 @@
|
|||
/* strftime - loadable builtin interface to strftime(3) */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 "bashtypes.h"
|
||||
#include "posixtime.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
int
|
||||
strftime_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *format, *tbuf;
|
||||
size_t tbsize, tsize;
|
||||
time_t secs;
|
||||
struct tm *t;
|
||||
int n;
|
||||
intmax_t i;
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
list = loptend;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
format = list->word->word;
|
||||
if (format == 0 || *format == 0)
|
||||
{
|
||||
printf ("\n");
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
list = list->next;
|
||||
|
||||
if (list && list->word->word)
|
||||
{
|
||||
n = legal_number (list->word->word, &i);
|
||||
if (n == 0 || i < 0 || i != (time_t)i)
|
||||
{
|
||||
sh_invalidnum (list->word->word);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
secs = i;
|
||||
}
|
||||
else
|
||||
secs = NOW;
|
||||
|
||||
t = localtime (&secs);
|
||||
|
||||
tbsize = strlen (format) * 4;
|
||||
tbuf = 0;
|
||||
|
||||
/* 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 <= 8; n++)
|
||||
{
|
||||
tbuf = xrealloc (tbuf, tbsize * n);
|
||||
tsize = strftime (tbuf, tbsize * n, format, t);
|
||||
if (tsize)
|
||||
break;
|
||||
}
|
||||
|
||||
if (tsize)
|
||||
printf ("%s\n", tbuf);
|
||||
free (tbuf);
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* An array of strings forming the `long' documentation for a builtin xxx,
|
||||
which is printed by `help xxx'. It must end with a NULL. */
|
||||
char *strftime_doc[] = {
|
||||
"Display formatted time.",
|
||||
"",
|
||||
"Converts date and time format to a string and displays it on the",
|
||||
"standard output. If the optional second argument is supplied, it",
|
||||
"is used as the number of seconds since the epoch to use in the",
|
||||
"conversion, otherwise the current time is used.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
/* The standard structure describing a builtin command. bash keeps an array
|
||||
of these structures. The flags must include BUILTIN_ENABLED so the
|
||||
builtin can be used. */
|
||||
struct builtin strftime_struct = {
|
||||
"strftime", /* builtin name */
|
||||
strftime_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
strftime_doc, /* array of long documentation strings. */
|
||||
"strftime format [seconds]", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
53
examples/loadables/sync.c
Normal file
53
examples/loadables/sync.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* sync - sync the disks by forcing pending filesystem writes to complete */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
int
|
||||
sync_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
sync();
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *sync_doc[] = {
|
||||
"Sync disks.",
|
||||
""
|
||||
"Force completion of pending disk writes",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin sync_struct = {
|
||||
"sync", /* builtin name */
|
||||
sync_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
sync_doc, /* array of long documentation strings. */
|
||||
"sync", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
183
examples/loadables/tee.c
Normal file
183
examples/loadables/tee.c
Normal file
|
@ -0,0 +1,183 @@
|
|||
/* tee - duplicate standard input */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2021 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 "filecntl.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
typedef struct flist {
|
||||
struct flist *next;
|
||||
int fd;
|
||||
char *fname;
|
||||
} FLIST;
|
||||
|
||||
static FLIST *tee_flist;
|
||||
|
||||
#define TEE_BUFSIZE 8192
|
||||
|
||||
extern int interrupt_immediately;
|
||||
|
||||
extern char *strerror ();
|
||||
|
||||
int
|
||||
tee_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt, append, nointr, rval, fd, fflags;
|
||||
int n, nr, nw;
|
||||
FLIST *fl;
|
||||
char *buf, *bp;
|
||||
|
||||
char *t;
|
||||
|
||||
reset_internal_getopt ();
|
||||
append = nointr = 0;
|
||||
tee_flist = (FLIST *)NULL;
|
||||
while ((opt = internal_getopt (list, "ai")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
append = 1;
|
||||
break;
|
||||
case 'i':
|
||||
nointr = 1;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (nointr == 0)
|
||||
interrupt_immediately++;
|
||||
|
||||
buf = xmalloc (TEE_BUFSIZE);
|
||||
|
||||
/* Initialize output file list. */
|
||||
fl = tee_flist = (FLIST *)xmalloc (sizeof(FLIST));
|
||||
tee_flist->fd = 1;
|
||||
tee_flist->fname = "stdout";
|
||||
tee_flist->next = (FLIST *)NULL;
|
||||
|
||||
/* Add file arguments to list of output files. */
|
||||
fflags = append ? O_WRONLY|O_CREAT|O_APPEND : O_WRONLY|O_CREAT|O_TRUNC;
|
||||
for (rval = EXECUTION_SUCCESS; list; list = list->next)
|
||||
{
|
||||
fd = open (list->word->word, fflags, 0666);
|
||||
if (fd < 0)
|
||||
{
|
||||
builtin_error ("%s: cannot open: %s", list->word->word, strerror (errno));
|
||||
rval = EXECUTION_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
fl->next = (FLIST *)xmalloc (sizeof(FLIST));
|
||||
fl->next->fd = fd;
|
||||
fl->next->fname = list->word->word;
|
||||
fl = fl->next;
|
||||
fl->next = (FLIST *)NULL;
|
||||
}
|
||||
QUIT;
|
||||
}
|
||||
|
||||
while ((nr = read(0, buf, TEE_BUFSIZE)) > 0)
|
||||
for (fl = tee_flist; fl; fl = fl->next)
|
||||
{
|
||||
n = nr;
|
||||
bp = buf;
|
||||
do
|
||||
{
|
||||
if ((nw = write (fl->fd, bp, n)) == -1)
|
||||
{
|
||||
builtin_error ("%s: write error: %s", fl->fname, strerror (errno));
|
||||
rval = EXECUTION_FAILURE;
|
||||
break;
|
||||
}
|
||||
bp += nw;
|
||||
QUIT;
|
||||
}
|
||||
while (n -= nw);
|
||||
}
|
||||
if (nr < 0)
|
||||
builtin_error ("read error: %s", strerror (errno));
|
||||
|
||||
/* Deallocate resources -- this is a builtin command. */
|
||||
tee_flist = tee_flist->next; /* skip bogus close of stdout */
|
||||
while (tee_flist)
|
||||
{
|
||||
fl = tee_flist;
|
||||
if (close (fl->fd) < 0)
|
||||
{
|
||||
builtin_error ("%s: close_error: %s", fl->fname, strerror (errno));
|
||||
rval = EXECUTION_FAILURE;
|
||||
}
|
||||
tee_flist = tee_flist->next;
|
||||
free (fl);
|
||||
}
|
||||
|
||||
QUIT;
|
||||
return (rval);
|
||||
}
|
||||
|
||||
char *tee_doc[] = {
|
||||
"Duplicate standard output.",
|
||||
"",
|
||||
"Copy standard input to standard output, making a copy in each",
|
||||
"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
|
||||
};
|
||||
|
||||
struct builtin tee_struct = {
|
||||
"tee", /* builtin name */
|
||||
tee_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
tee_doc, /* array of long documentation strings. */
|
||||
"tee [-ai] [file ...]", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
75
examples/loadables/template.c
Normal file
75
examples/loadables/template.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
/* template - example template for loadable builtin */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include "bashansi.h"
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "loadables.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
extern char *strerror ();
|
||||
|
||||
int
|
||||
template_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt, rval;
|
||||
|
||||
rval = EXECUTION_SUCCESS;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
return (rval);
|
||||
}
|
||||
|
||||
/* Called when `template' is enabled and loaded from the shared object. If this
|
||||
function returns 0, the load fails. */
|
||||
int
|
||||
template_builtin_load (name)
|
||||
char *name;
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Called when `template' is disabled. */
|
||||
void
|
||||
template_builtin_unload (name)
|
||||
char *name;
|
||||
{
|
||||
}
|
||||
|
||||
char *template_doc[] = {
|
||||
"Short description.",
|
||||
""
|
||||
"Longer description of builtin and usage.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin template_struct = {
|
||||
"template", /* builtin name */
|
||||
template_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
template_doc, /* array of long documentation strings. */
|
||||
"template", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
72
examples/loadables/truefalse.c
Normal file
72
examples/loadables/truefalse.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
/* true and false builtins */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 "shell.h"
|
||||
#include "builtins.h"
|
||||
#include "common.h"
|
||||
|
||||
int
|
||||
true_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
return EXECUTION_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
false_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
return EXECUTION_FAILURE;
|
||||
}
|
||||
|
||||
static char *true_doc[] = {
|
||||
"Exit successfully.",
|
||||
"",
|
||||
"Return a successful result.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
static char *false_doc[] = {
|
||||
"Exit unsuccessfully.",
|
||||
"",
|
||||
"Return an unsuccessful result.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin true_struct = {
|
||||
"true",
|
||||
true_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
true_doc,
|
||||
"true",
|
||||
0
|
||||
};
|
||||
|
||||
struct builtin false_struct = {
|
||||
"false",
|
||||
false_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
false_doc,
|
||||
"false",
|
||||
0
|
||||
};
|
83
examples/loadables/tty.c
Normal file
83
examples/loadables/tty.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* tty - return terminal name */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2021 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 <stdio.h>
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
extern char *ttyname ();
|
||||
|
||||
int
|
||||
tty_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt, sflag;
|
||||
char *t;
|
||||
|
||||
reset_internal_getopt ();
|
||||
sflag = 0;
|
||||
while ((opt = internal_getopt (list, "s")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 's':
|
||||
sflag = 1;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
t = ttyname (0);
|
||||
QUIT;
|
||||
if (sflag == 0)
|
||||
puts (t ? t : "not a tty");
|
||||
return (t ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
char *tty_doc[] = {
|
||||
"Display terminal name.",
|
||||
"",
|
||||
"tty writes the name of the terminal that is opened for standard",
|
||||
"input to standard output. If the `-s' option is supplied, nothing",
|
||||
"is written; the exit status determines whether or not the standard",
|
||||
"input is connected to a tty.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
/* The standard structure describing a builtin command. bash keeps an array
|
||||
of these structures. */
|
||||
struct builtin tty_struct = {
|
||||
"tty", /* builtin name */
|
||||
tty_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
tty_doc, /* array of long documentation strings. */
|
||||
"tty [-s]", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
162
examples/loadables/uname.c
Normal file
162
examples/loadables/uname.c
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* uname - print system information
|
||||
*
|
||||
* usage: uname [-amnrsv]
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 <stdio.h>
|
||||
|
||||
#include "bashtypes.h"
|
||||
|
||||
#if defined (HAVE_UNAME)
|
||||
# include <sys/utsname.h>
|
||||
#else
|
||||
struct utsname {
|
||||
char sysname[32];
|
||||
char nodename[32];
|
||||
char release[32];
|
||||
char version[32];
|
||||
char machine[32];
|
||||
};
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#define FLAG_SYSNAME 0x01 /* -s */
|
||||
#define FLAG_NODENAME 0x02 /* -n */
|
||||
#define FLAG_RELEASE 0x04 /* -r */
|
||||
#define FLAG_VERSION 0x08 /* -v */
|
||||
#define FLAG_MACHINE 0x10 /* -m, -p */
|
||||
|
||||
#define FLAG_ALL 0x1f
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
static void uprint();
|
||||
|
||||
static int uname_flags;
|
||||
|
||||
int
|
||||
uname_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt, r;
|
||||
struct utsname uninfo;
|
||||
|
||||
uname_flags = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "amnprsv")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
uname_flags |= FLAG_ALL;
|
||||
break;
|
||||
case 'm':
|
||||
case 'p':
|
||||
uname_flags |= FLAG_MACHINE;
|
||||
break;
|
||||
case 'n':
|
||||
uname_flags |= FLAG_NODENAME;
|
||||
break;
|
||||
case 'r':
|
||||
uname_flags |= FLAG_RELEASE;
|
||||
break;
|
||||
case 's':
|
||||
uname_flags |= FLAG_SYSNAME;
|
||||
break;
|
||||
case 'v':
|
||||
uname_flags |= FLAG_VERSION;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
if (uname_flags == 0)
|
||||
uname_flags = FLAG_SYSNAME;
|
||||
|
||||
/* Only ancient systems will not have uname(2). */
|
||||
#ifdef HAVE_UNAME
|
||||
if (uname (&uninfo) < 0)
|
||||
{
|
||||
builtin_error ("cannot get system name: %s", strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#else
|
||||
builtin_error ("cannot get system information: uname(2) not available");
|
||||
return (EXECUTION_FAILURE);
|
||||
#endif
|
||||
|
||||
uprint (FLAG_SYSNAME, uninfo.sysname);
|
||||
uprint (FLAG_NODENAME, uninfo.nodename);
|
||||
uprint (FLAG_RELEASE, uninfo.release);
|
||||
uprint (FLAG_VERSION, uninfo.version);
|
||||
uprint (FLAG_MACHINE, uninfo.machine);
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
uprint (flag, info)
|
||||
int flag;
|
||||
char *info;
|
||||
{
|
||||
if (uname_flags & flag)
|
||||
{
|
||||
uname_flags &= ~flag;
|
||||
printf ("%s%c", info, uname_flags ? ' ' : '\n');
|
||||
}
|
||||
}
|
||||
|
||||
char *uname_doc[] = {
|
||||
"Display system information.",
|
||||
"",
|
||||
"Display information about the system hardware and OS.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin uname_struct = {
|
||||
"uname",
|
||||
uname_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
uname_doc,
|
||||
"uname [-amnrsv]",
|
||||
0
|
||||
};
|
74
examples/loadables/unlink.c
Normal file
74
examples/loadables/unlink.c
Normal file
|
@ -0,0 +1,74 @@
|
|||
/* unlink - remove a directory entry */
|
||||
|
||||
/* Should only be used to remove directories by a superuser prepared to let
|
||||
fsck clean up the file system. */
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "common.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
int
|
||||
unlink_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
if (unlink (list->word->word) != 0)
|
||||
{
|
||||
builtin_error ("%s: cannot unlink: %s", list->word->word, strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *unlink_doc[] = {
|
||||
"Remove a directory entry.",
|
||||
"",
|
||||
"Forcibly remove a directory entry, even if it's a directory.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin unlink_struct = {
|
||||
"unlink", /* builtin name */
|
||||
unlink_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
unlink_doc, /* array of long documentation strings. */
|
||||
"unlink name", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
75
examples/loadables/whoami.c
Normal file
75
examples/loadables/whoami.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* whoami - print out username of current user
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 1999-2009 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 <stdio.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
int
|
||||
whoami_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
if (list)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
if (current_user.user_name == 0)
|
||||
get_current_user_info ();
|
||||
printf ("%s\n", current_user.user_name);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *whoami_doc[] = {
|
||||
"Print user name",
|
||||
"",
|
||||
"Display name of current user.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin whoami_struct = {
|
||||
"whoami",
|
||||
whoami_builtin,
|
||||
BUILTIN_ENABLED,
|
||||
whoami_doc,
|
||||
"whoami",
|
||||
0
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue