Testing musl support, disabled by default

Imported multiple utilities from ubase to replace util-linux utils
Only build utilities from util-linux that can't be had elsewhere
This commit is contained in:
Nathan Fisher 2021-03-10 13:53:36 -05:00
parent 73b8fca0dd
commit f014b6d01c
280 changed files with 23725 additions and 127 deletions

View file

@ -84,8 +84,7 @@ $(build)/.skeleton.built: | $(dirs)
install -dv -m 1777 $(build)/tmp $(build)/var/tmp
[ -h $(build)/var/run ] || ln -sv /run $(build)/var/run
[ -h $(build)/var/lock ] || ln -sv /run/lock $(build)/var/lock
[ -c $(build)/dev/console ] || su -c "mknod -m 600 $(build)/dev/console c 5 1"
[ -c $(build)/dev/null ] || su -c "mknod -m 666 $(build)/dev/null c 1 3"
#su -c "mknod -m 600 $(build)/dev/console c 5 1 && mknod -m 666 $(build)/dev/null c 1 3"
touch $@
$(plists): $(build)/.built
@ -135,11 +134,14 @@ remove-toolchain:
$(MAKE) -C toolchain remove
clean:
$(MAKE) -C world clean
$(MAKE) -C toolchain clean
rm -rf build/src-*
rm -rf build/obj-*
distclean:
$(MAKE) -C world clean
$(MAKE) -C toolchain clean
rm -rf build/*
rm -rf build/.built
rm -rf build/.skeleton.built
rm -rf build/.stripped
.PHONY: clean

View file

@ -12,6 +12,7 @@ skarnet = https://skarnet.org/software
distfiles = \
acl-${acl_version}.tar.gz \
$(argp-standalone_version).tar.gz \
attr-${attr_version}.tar.gz \
autoconf-${autoconf_version}.tar.xz \
automake-${automake_version}.tar.xz \
@ -69,6 +70,8 @@ man-pages-${man-pages_version}.tar.xz \
meson-${meson_version}.tar.gz \
mpc-${mpc_version}.tar.gz \
mpfr-${mpfr_version}.tar.xz \
musl-$(musl_version).tar.gz \
musl-fts-$(musl-fts_version).tar.gz \
ncurses-${ncurses_version}.tar.gz \
netbsd-curses-${netbsd-curses_version}.tar.xz \
ninja-${ninja_version}.tar.gz \
@ -111,6 +114,11 @@ acl: acl-${acl_version}.tar.gz
acl-${acl_version}.tar.gz:
wget -c ${savannah}/acl/$@
argp-standalone: $(argp-standalone_version).tar.gz
$(argp-standalone_version).tar.gz:
wget -c $(github)/ericonr/argp-standalone/archive/$@
attr: attr-${attr_version}.tar.gz
attr-${attr_version}.tar.gz:
@ -406,6 +414,17 @@ mpfr: mpfr-${mpfr_version}.tar.xz
mpfr-${mpfr_version}.tar.xz:
wget -c http://www.mpfr.org/mpfr-${mpfr_version}/$@
musl: musl-$(musl_version).tar.gz
musl-$(musl_version).tar.gz:
wget -c http://musl.libc.org/releases/$@
musl-fts: musl-fts-$(musl-fts_version).tar.gz
musl-fts-$(musl-fts_version).tar.gz:
wget -c $(github)/void-linux/musl-fts/archive/v$(musl-fts_version).tar.gz \
-O $@
ncurses: ncurses-${ncurses_version}.tar.gz
ncurses-${ncurses_version}.tar.gz:

View file

@ -15,7 +15,7 @@ ifndef colormk
include hhl.colors.mk
endif
ifeq ($(filter armv7l aarch64, $(arch)), $(arch))
ifeq ($(filter armv6 armv7l aarch64, $(arch)), $(arch))
tgt = $(arch)-unknown-linux-gnueabi
else
tgt = $(arch)-unknown-linux-gnu
@ -26,6 +26,12 @@ ifeq ($(filter armv7l aarch64, $(bld_arch)), $(bld_arch))
else
bld = $(bld_arch)-unknown-linux-gnu
endif
#ifeq ($(filter armv6 armv7l aarch64, $(arch)), $(arch))
#tgt = $(arch)-hitchhiker-linux-musleabihf
#else
#tgt = $(arch)-hitchhiker-linux-musl
#endif
#bld = $(shell gcc -dumpmachine)
exec_prefix ?= ${DESTDIR}${install_prefix}
bindir ?= ${exec_prefix}/bin

View file

@ -72,6 +72,14 @@ $(objdir):
install -d $@
endif
ifeq ($(use_configure),1)
show-config_opts:
$(info $(grn)$(config_opts)$(reset))
else
show-config_opts:
$(info $(red)Package does not use configure$(reset))
endif
$(distlocal):
$(info $(grn)=== Fetching $(distfile) ===$(reset))
$(MAKE) -C $(distdir) $(distfile)

View file

@ -4,6 +4,7 @@
# package versions - hhl base
acl_version = 2.2.53
argp-standalone_version = 1.4.1
attr_version = 2.4.48
autoconf_version = 2.71
automake_version = 1.16.3
@ -55,7 +56,7 @@ libnl_version = 3.5.0
libressl_version = 3.0.2
libtool_version = 2.4.6
libz_version = 1.2.8.2015.12.26
linux_version = 5.11
linux_version = 5.11.5
linux_rpi_version = 5.4.45
m4_version = 1.4.18
make_version = 4.3
@ -64,6 +65,8 @@ mandoc_version = 1.14.5
meson_version = 0.56.2
mpc_version = 1.2.1
mpfr_version = 4.1.0
musl_version = 1.2.2
musl-fts_version = 1.2.7
ncurses_version = 6.2
netbsd-curses_version = 0.3.1
ninja_version = 1.10.2

View file

@ -21,6 +21,7 @@ subdirs += binutils
subdirs += gcc-pass1
subdirs += linux-headers
subdirs += glibc
#subdirs += musl
subdirs += gcc-pass2
installdirs += $(tooldir) $(global_srcdir) $(global_objdir)
@ -60,7 +61,7 @@ removedoc:
rm -rf $(tooldir)/share/man
remove-la:
find $(tooldir)/lib $(tooldir)/libexec -name '*.la' -delete
find $(tooldir) -name '*.la' -delete
reduce-size: strip removedoc remove-la

View file

@ -6,9 +6,12 @@ include toolchain.mk
objdir = $(global_objdir)/gcc-pass2
config_opts += --target=$(tgt)
config_opts += --with-sysroot=$(build)
config_opts += --with-glibc-version=2.11
config_opts += --enable-languages=c,c++
config_opts += --disable-multilib
config_opts += --disable-bootstrap
# For musl
#config_opts += --disable-libsanitizer
ifneq ($(filter i686 x86_64, $(arch)), $(arch))
config_opts += --disable-libsanitizer
endif

13
toolchain/musl/Makefile Normal file
View file

@ -0,0 +1,13 @@
# Makefile - hhl - /src/toolchain/musl
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
distname = musl
distext = gz
include world.mk
export CFLAGS = --sysroot=$(DESTDIR)
config_opts += --host=$(tgt)
config_opts += --bindir=/bin
include targets.mk

View file

@ -49,6 +49,8 @@ subdirs += expat
#subdirs += intltool
subdirs += kmod
subdirs += gettext
# for musl
subdirs += argp-standalone
subdirs += elfutils
subdirs += libffi
subdirs += libressl
@ -68,6 +70,10 @@ subdirs += mandoc
subdirs += texinfo
subdirs += procps-ng
subdirs += util-linux
# for musl
#subdirs += argp-standalone
# for musl
#subdirs += musl-fts
subdirs += e2fsprogs
subdirs += haveged
subdirs += eudev

View file

@ -0,0 +1,9 @@
# Makefile - hhl - /src/world/argp-standalone
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
libname = argp
doinstall = true
cflags += -O2
cflags += -Wall
cflags += --sysroot=$(DESTDIR)
include hhl.staticlib.mk

View file

@ -0,0 +1,3 @@
/* Global variables needed by argp */
#undef HAVE_PROGRAM_INVOCATION_NAME
#undef HAVE_PROGRAM_INVOCATION_SHORT_NAME

View file

@ -0,0 +1,25 @@
/* Default definition for ARGP_PROGRAM_BUG_ADDRESS.
Copyright (C) 1996-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Miles Bader <miles@gnu.ai.mit.edu>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/* If set by the user program, it should point to string that is the
bug-reporting address for the program. It will be printed by argp_help if
the ARGP_HELP_BUG_ADDR flag is set (as it is by various standard help
messages), embedded in a sentence that says something like `Report bugs to
ADDR.'. */
const char *argp_program_bug_address;

View file

@ -0,0 +1,31 @@
/* Default definition for ARGP_ERR_EXIT_STATUS
Copyright (C) 1997-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Miles Bader <miles@gnu.ai.mit.edu>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sysexits.h>
#include "argp.h"
/* The exit status that argp will use when exiting due to a parsing error.
If not defined or set by the user program, this defaults to EX_USAGE from
<sysexits.h>. */
error_t argp_err_exit_status = EX_USAGE;

View file

@ -0,0 +1,433 @@
/* Word-wrapping and line-truncating streams
Copyright (C) 1997-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Miles Bader <miles@gnu.ai.mit.edu>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/* This package emulates glibc `line_wrap_stream' semantics for systems that
don't have that. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <ctype.h>
#include <argp-fmtstream.h>
#include "argp-namefrob.h"
#ifndef ARGP_FMTSTREAM_USE_LINEWRAP
#ifndef isblank
#define isblank(ch) ((ch)==' ' || (ch)=='\t')
#endif
#if 0
# include <wchar.h>
# include <libio/libioP.h>
#endif
#define INIT_BUF_SIZE 200
#define PRINTF_SIZE_GUESS 150
/* Return an argp_fmtstream that outputs to STREAM, and which prefixes lines
written on it with LMARGIN spaces and limits them to RMARGIN columns
total. If WMARGIN >= 0, words that extend past RMARGIN are wrapped by
replacing the whitespace before them with a newline and WMARGIN spaces.
Otherwise, chars beyond RMARGIN are simply dropped until a newline.
Returns NULL if there was an error. */
argp_fmtstream_t
__argp_make_fmtstream (FILE *stream,
size_t lmargin, size_t rmargin, ssize_t wmargin)
{
argp_fmtstream_t fs;
fs = (struct argp_fmtstream *) malloc (sizeof (struct argp_fmtstream));
if (fs != NULL)
{
fs->stream = stream;
fs->lmargin = lmargin;
fs->rmargin = rmargin;
fs->wmargin = wmargin;
fs->point_col = 0;
fs->point_offs = 0;
fs->buf = (char *) malloc (INIT_BUF_SIZE);
if (! fs->buf)
{
free (fs);
fs = 0;
}
else
{
fs->p = fs->buf;
fs->end = fs->buf + INIT_BUF_SIZE;
}
}
return fs;
}
#if 0
/* Not exported. */
#ifdef weak_alias
weak_alias (__argp_make_fmtstream, argp_make_fmtstream)
#endif
#endif
/* Flush FS to its stream, and free it (but don't close the stream). */
void
__argp_fmtstream_free (argp_fmtstream_t fs)
{
__argp_fmtstream_update (fs);
if (fs->p > fs->buf)
{
#if 0
__fxprintf (fs->stream, "%.*s", (int) (fs->p - fs->buf), fs->buf);
#else
fwrite_unlocked (fs->buf, 1, fs->p - fs->buf, fs->stream);
#endif
}
free (fs->buf);
free (fs);
}
#if 0
/* Not exported. */
#ifdef weak_alias
weak_alias (__argp_fmtstream_free, argp_fmtstream_free)
#endif
#endif
/* Process FS's buffer so that line wrapping is done from POINT_OFFS to the
end of its buffer. This code is mostly from glibc stdio/linewrap.c. */
void
__argp_fmtstream_update (argp_fmtstream_t fs)
{
char *buf, *nl;
size_t len;
/* Scan the buffer for newlines. */
buf = fs->buf + fs->point_offs;
while (buf < fs->p)
{
size_t r;
if (fs->point_col == 0 && fs->lmargin != 0)
{
/* We are starting a new line. Print spaces to the left margin. */
const size_t pad = fs->lmargin;
if (fs->p + pad < fs->end)
{
/* We can fit in them in the buffer by moving the
buffer text up and filling in the beginning. */
memmove (buf + pad, buf, fs->p - buf);
fs->p += pad; /* Compensate for bigger buffer. */
memset (buf, ' ', pad); /* Fill in the spaces. */
buf += pad; /* Don't bother searching them. */
}
else
{
/* No buffer space for spaces. Must flush. */
size_t i;
for (i = 0; i < pad; i++)
{
#if 0
if (_IO_fwide (fs->stream, 0) > 0)
putwc_unlocked (L' ', fs->stream);
else
#endif
putc_unlocked (' ', fs->stream);
}
}
fs->point_col = pad;
}
len = fs->p - buf;
nl = memchr (buf, '\n', len);
if (fs->point_col < 0)
fs->point_col = 0;
if (!nl)
{
/* The buffer ends in a partial line. */
if (fs->point_col + len < fs->rmargin)
{
/* The remaining buffer text is a partial line and fits
within the maximum line width. Advance point for the
characters to be written and stop scanning. */
fs->point_col += len;
break;
}
else
/* Set the end-of-line pointer for the code below to
the end of the buffer. */
nl = fs->p;
}
else if (fs->point_col + (nl - buf) < (ssize_t) fs->rmargin)
{
/* The buffer contains a full line that fits within the maximum
line width. Reset point and scan the next line. */
fs->point_col = 0;
buf = nl + 1;
continue;
}
/* This line is too long. */
r = fs->rmargin - 1;
if (fs->wmargin < 0)
{
/* Truncate the line by overwriting the excess with the
newline and anything after it in the buffer. */
if (nl < fs->p)
{
memmove (buf + (r - fs->point_col), nl, fs->p - nl);
fs->p -= buf + (r - fs->point_col) - nl;
/* Reset point for the next line and start scanning it. */
fs->point_col = 0;
buf += r + 1; /* Skip full line plus \n. */
}
else
{
/* The buffer ends with a partial line that is beyond the
maximum line width. Advance point for the characters
written, and discard those past the max from the buffer. */
fs->point_col += len;
fs->p -= fs->point_col - r;
break;
}
}
else
{
/* Do word wrap. Go to the column just past the maximum line
width and scan back for the beginning of the word there.
Then insert a line break. */
char *p, *nextline;
int i;
p = buf + (r + 1 - fs->point_col);
while (p >= buf && !isblank (*p))
--p;
nextline = p + 1; /* This will begin the next line. */
if (nextline > buf)
{
/* Swallow separating blanks. */
if (p >= buf)
do
--p;
while (p >= buf && isblank (*p));
nl = p + 1; /* The newline will replace the first blank. */
}
else
{
/* A single word that is greater than the maximum line width.
Oh well. Put it on an overlong line by itself. */
p = buf + (r + 1 - fs->point_col);
/* Find the end of the long word. */
do
++p;
while (p < nl && !isblank (*p));
if (p == nl)
{
/* It already ends a line. No fussing required. */
fs->point_col = 0;
buf = nl + 1;
continue;
}
/* We will move the newline to replace the first blank. */
nl = p;
/* Swallow separating blanks. */
do
++p;
while (isblank (*p));
/* The next line will start here. */
nextline = p;
}
/* Note: There are a bunch of tests below for
NEXTLINE == BUF + LEN + 1; this case is where NL happens to fall
at the end of the buffer, and NEXTLINE is in fact empty (and so
we need not be careful to maintain its contents). */
if ((nextline == buf + len + 1
? fs->end - nl < fs->wmargin + 1
: nextline - (nl + 1) < fs->wmargin)
&& fs->p > nextline)
{
/* The margin needs more blanks than we removed. */
if (fs->end - fs->p > fs->wmargin + 1)
/* Make some space for them. */
{
size_t mv = fs->p - nextline;
memmove (nl + 1 + fs->wmargin, nextline, mv);
nextline = nl + 1 + fs->wmargin;
len = nextline + mv - buf;
*nl++ = '\n';
}
else
/* Output the first line so we can use the space. */
{
#if 0
__fxprintf (fs->stream, "%.*s\n",
(int) (nl - fs->buf), fs->buf);
#else
if (nl > fs->buf)
fwrite_unlocked (fs->buf, 1, nl - fs->buf, fs->stream);
putc_unlocked ('\n', fs->stream);
#endif
len += buf - fs->buf;
nl = buf = fs->buf;
}
}
else
/* We can fit the newline and blanks in before
the next word. */
*nl++ = '\n';
if (nextline - nl >= fs->wmargin
|| (nextline == buf + len + 1 && fs->end - nextline >= fs->wmargin))
/* Add blanks up to the wrap margin column. */
for (i = 0; i < fs->wmargin; ++i)
*nl++ = ' ';
else
for (i = 0; i < fs->wmargin; ++i)
#if 0
if (_IO_fwide (fs->stream, 0) > 0)
putwc_unlocked (L' ', fs->stream);
else
#endif
putc_unlocked (' ', fs->stream);
/* Copy the tail of the original buffer into the current buffer
position. */
if (nl < nextline)
memmove (nl, nextline, buf + len - nextline);
len -= nextline - buf;
/* Continue the scan on the remaining lines in the buffer. */
buf = nl;
/* Restore bufp to include all the remaining text. */
fs->p = nl + len;
/* Reset the counter of what has been output this line. If wmargin
is 0, we want to avoid the lmargin getting added, so we set
point_col to a magic value of -1 in that case. */
fs->point_col = fs->wmargin ? fs->wmargin : -1;
}
}
/* Remember that we've scanned as far as the end of the buffer. */
fs->point_offs = fs->p - fs->buf;
}
/* Ensure that FS has space for AMOUNT more bytes in its buffer, either by
growing the buffer, or by flushing it. True is returned iff we succeed. */
int
__argp_fmtstream_ensure (struct argp_fmtstream *fs, size_t amount)
{
if ((size_t) (fs->end - fs->p) < amount)
{
ssize_t wrote;
/* Flush FS's buffer. */
__argp_fmtstream_update (fs);
#if 0
__fxprintf (fs->stream, "%.*s", (int) (fs->p - fs->buf), fs->buf);
wrote = fs->p - fs->buf;
#else
wrote = fwrite_unlocked (fs->buf, 1, fs->p - fs->buf, fs->stream);
#endif
if (wrote == fs->p - fs->buf)
{
fs->p = fs->buf;
fs->point_offs = 0;
}
else
{
fs->p -= wrote;
fs->point_offs -= wrote;
memmove (fs->buf, fs->buf + wrote, fs->p - fs->buf);
return 0;
}
if ((size_t) (fs->end - fs->buf) < amount)
/* Gotta grow the buffer. */
{
size_t old_size = fs->end - fs->buf;
size_t new_size = old_size + amount;
char *new_buf;
if (new_size < old_size || ! (new_buf = realloc (fs->buf, new_size)))
{
__set_errno (ENOMEM);
return 0;
}
fs->buf = new_buf;
fs->end = new_buf + new_size;
fs->p = fs->buf;
}
}
return 1;
}
ssize_t
__argp_fmtstream_printf (struct argp_fmtstream *fs, const char *fmt, ...)
{
int out;
size_t avail;
size_t size_guess = PRINTF_SIZE_GUESS; /* How much space to reserve. */
do
{
va_list args;
if (! __argp_fmtstream_ensure (fs, size_guess))
return -1;
va_start (args, fmt);
avail = fs->end - fs->p;
out = vsnprintf (fs->p, avail, fmt, args);
va_end (args);
if ((size_t) out >= avail)
size_guess = out + 1;
}
while ((size_t) out >= avail);
fs->p += out;
return out;
}
#if 0
/* Not exported. */
#ifdef weak_alias
weak_alias (__argp_fmtstream_printf, argp_fmtstream_printf)
#endif
#endif
#endif /* !ARGP_FMTSTREAM_USE_LINEWRAP */

View file

@ -0,0 +1,263 @@
/* Word-wrapping and line-truncating streams.
Copyright (C) 1997-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Miles Bader <miles@gnu.ai.mit.edu>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/* This package emulates glibc `line_wrap_stream' semantics for systems that
don't have that. If the system does have it, it is just a wrapper for
that. This header file is only used internally while compiling argp, and
shouldn't be installed. */
#ifndef _ARGP_FMTSTREAM_H
#define _ARGP_FMTSTREAM_H
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#ifndef PRINTF_STYLE
# if __GNUC__ >= 2
# define PRINTF_STYLE(f, a) __attribute__ ((__format__ (__printf__, f, a)))
# else
# define PRINTF_STYLE(f, a)
# endif
#endif
#if 0
/* line_wrap_stream is available, so use that. */
#define ARGP_FMTSTREAM_USE_LINEWRAP
#endif
#ifdef ARGP_FMTSTREAM_USE_LINEWRAP
/* Just be a simple wrapper for line_wrap_stream; the semantics are
*slightly* different, as line_wrap_stream doesn't actually make a new
object, it just modifies the given stream (reversibly) to do
line-wrapping. Since we control who uses this code, it doesn't matter. */
#include <linewrap.h>
typedef FILE *argp_fmtstream_t;
#define argp_make_fmtstream line_wrap_stream
#define __argp_make_fmtstream line_wrap_stream
#define argp_fmtstream_free line_unwrap_stream
#define __argp_fmtstream_free line_unwrap_stream
#define __argp_fmtstream_putc(fs,ch) putc(ch,fs)
#define argp_fmtstream_putc(fs,ch) putc(ch,fs)
#define __argp_fmtstream_puts(fs,str) fputs(str,fs)
#define argp_fmtstream_puts(fs,str) fputs(str,fs)
#define __argp_fmtstream_write(fs,str,len) fwrite(str,1,len,fs)
#define argp_fmtstream_write(fs,str,len) fwrite(str,1,len,fs)
#define __argp_fmtstream_printf fprintf
#define argp_fmtstream_printf fprintf
#define __argp_fmtstream_lmargin line_wrap_lmargin
#define argp_fmtstream_lmargin line_wrap_lmargin
#define __argp_fmtstream_set_lmargin line_wrap_set_lmargin
#define argp_fmtstream_set_lmargin line_wrap_set_lmargin
#define __argp_fmtstream_rmargin line_wrap_rmargin
#define argp_fmtstream_rmargin line_wrap_rmargin
#define __argp_fmtstream_set_rmargin line_wrap_set_rmargin
#define argp_fmtstream_set_rmargin line_wrap_set_rmargin
#define __argp_fmtstream_wmargin line_wrap_wmargin
#define argp_fmtstream_wmargin line_wrap_wmargin
#define __argp_fmtstream_set_wmargin line_wrap_set_wmargin
#define argp_fmtstream_set_wmargin line_wrap_set_wmargin
#define __argp_fmtstream_point line_wrap_point
#define argp_fmtstream_point line_wrap_point
#else /* !ARGP_FMTSTREAM_USE_LINEWRAP */
/* Guess we have to define our own version. */
struct argp_fmtstream
{
FILE *stream; /* The stream we're outputting to. */
size_t lmargin, rmargin; /* Left and right margins. */
ssize_t wmargin; /* Margin to wrap to, or -1 to truncate. */
/* Point in buffer to which we've processed for wrapping, but not output. */
size_t point_offs;
/* Output column at POINT_OFFS, or -1 meaning 0 but don't add lmargin. */
ssize_t point_col;
char *buf; /* Output buffer. */
char *p; /* Current end of text in BUF. */
char *end; /* Absolute end of BUF. */
};
typedef struct argp_fmtstream *argp_fmtstream_t;
/* Return an argp_fmtstream that outputs to STREAM, and which prefixes lines
written on it with LMARGIN spaces and limits them to RMARGIN columns
total. If WMARGIN >= 0, words that extend past RMARGIN are wrapped by
replacing the whitespace before them with a newline and WMARGIN spaces.
Otherwise, chars beyond RMARGIN are simply dropped until a newline.
Returns NULL if there was an error. */
extern argp_fmtstream_t __argp_make_fmtstream (FILE *__stream,
size_t __lmargin,
size_t __rmargin,
ssize_t __wmargin);
extern argp_fmtstream_t argp_make_fmtstream (FILE *__stream,
size_t __lmargin,
size_t __rmargin,
ssize_t __wmargin);
/* Flush __FS to its stream, and free it (but don't close the stream). */
extern void __argp_fmtstream_free (argp_fmtstream_t __fs);
extern void argp_fmtstream_free (argp_fmtstream_t __fs);
extern ssize_t __argp_fmtstream_printf (argp_fmtstream_t __fs,
const char *__fmt, ...)
PRINTF_STYLE(2,3);
extern ssize_t argp_fmtstream_printf (argp_fmtstream_t __fs,
const char *__fmt, ...)
PRINTF_STYLE(2,3);
/* Access macros for various bits of state. */
#define argp_fmtstream_lmargin(__fs) ((__fs)->lmargin)
#define argp_fmtstream_rmargin(__fs) ((__fs)->rmargin)
#define argp_fmtstream_wmargin(__fs) ((__fs)->wmargin)
#define __argp_fmtstream_lmargin argp_fmtstream_lmargin
#define __argp_fmtstream_rmargin argp_fmtstream_rmargin
#define __argp_fmtstream_wmargin argp_fmtstream_wmargin
/* Internal routines. */
extern void _argp_fmtstream_update (argp_fmtstream_t __fs);
extern void __argp_fmtstream_update (argp_fmtstream_t __fs);
extern int _argp_fmtstream_ensure (argp_fmtstream_t __fs, size_t __amount);
extern int __argp_fmtstream_ensure (argp_fmtstream_t __fs, size_t __amount);
#if 1
/* Inline versions of above routines. */
#if 1
#define __argp_fmtstream_putc argp_fmtstream_putc
#define __argp_fmtstream_puts argp_fmtstream_puts
#define __argp_fmtstream_write argp_fmtstream_write
#define __argp_fmtstream_set_lmargin argp_fmtstream_set_lmargin
#define __argp_fmtstream_set_rmargin argp_fmtstream_set_rmargin
#define __argp_fmtstream_set_wmargin argp_fmtstream_set_wmargin
#define __argp_fmtstream_point argp_fmtstream_point
#define __argp_fmtstream_update _argp_fmtstream_update
#define __argp_fmtstream_ensure _argp_fmtstream_ensure
#endif
#ifndef ARGP_FS_EI
#define ARGP_FS_EI static inline
#endif
ARGP_FS_EI size_t
__argp_fmtstream_write (argp_fmtstream_t __fs, const char *__str, size_t __len)
{
if (__fs->p + __len <= __fs->end || __argp_fmtstream_ensure (__fs, __len))
{
memcpy (__fs->p, __str, __len);
__fs->p += __len;
return __len;
}
else
return 0;
}
ARGP_FS_EI int
__argp_fmtstream_puts (argp_fmtstream_t __fs, const char *__str)
{
size_t __len = strlen (__str);
if (__len)
{
size_t __wrote = __argp_fmtstream_write (__fs, __str, __len);
return __wrote == __len ? 0 : -1;
}
else
return 0;
}
ARGP_FS_EI int
__argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch)
{
if (__fs->p < __fs->end || __argp_fmtstream_ensure (__fs, 1))
return *__fs->p++ = __ch;
else
return EOF;
}
/* Set __FS's left margin to __LMARGIN and return the old value. */
ARGP_FS_EI size_t
__argp_fmtstream_set_lmargin (argp_fmtstream_t __fs, size_t __lmargin)
{
size_t __old;
if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
__argp_fmtstream_update (__fs);
__old = __fs->lmargin;
__fs->lmargin = __lmargin;
return __old;
}
/* Set __FS's right margin to __RMARGIN and return the old value. */
ARGP_FS_EI size_t
__argp_fmtstream_set_rmargin (argp_fmtstream_t __fs, size_t __rmargin)
{
size_t __old;
if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
__argp_fmtstream_update (__fs);
__old = __fs->rmargin;
__fs->rmargin = __rmargin;
return __old;
}
/* Set FS's wrap margin to __WMARGIN and return the old value. */
ARGP_FS_EI size_t
__argp_fmtstream_set_wmargin (argp_fmtstream_t __fs, size_t __wmargin)
{
size_t __old;
if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
__argp_fmtstream_update (__fs);
__old = __fs->wmargin;
__fs->wmargin = __wmargin;
return __old;
}
/* Return the column number of the current output point in __FS. */
ARGP_FS_EI size_t
__argp_fmtstream_point (argp_fmtstream_t __fs)
{
if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
__argp_fmtstream_update (__fs);
return __fs->point_col >= 0 ? __fs->point_col : 0;
}
#if 1
#undef __argp_fmtstream_putc
#undef __argp_fmtstream_puts
#undef __argp_fmtstream_write
#undef __argp_fmtstream_set_lmargin
#undef __argp_fmtstream_set_rmargin
#undef __argp_fmtstream_set_wmargin
#undef __argp_fmtstream_point
#undef __argp_fmtstream_update
#undef __argp_fmtstream_ensure
#endif
#endif /* __OPTIMIZE__ */
#endif /* ARGP_FMTSTREAM_USE_LINEWRAP */
#endif /* argp-fmtstream.h */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,149 @@
/* Name frobnication for compiling argp outside of glibc
Copyright (C) 1997-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Miles Bader <miles@gnu.ai.mit.edu>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#if 1
/* This code is written for inclusion in gnu-libc, and uses names in the
namespace reserved for libc. If we're not compiling in libc, define those
names to be the normal ones instead. */
/* argp-parse functions */
#undef __argp_parse
#define __argp_parse argp_parse
#undef __option_is_end
#define __option_is_end _option_is_end
#undef __option_is_short
#define __option_is_short _option_is_short
#undef __argp_input
#define __argp_input _argp_input
/* argp-help functions */
#undef __argp_help
#define __argp_help argp_help
#undef __argp_error
#define __argp_error argp_error
#undef __argp_failure
#define __argp_failure argp_failure
#undef __argp_state_help
#define __argp_state_help argp_state_help
#undef __argp_usage
#define __argp_usage argp_usage
/* argp-fmtstream functions */
#undef __argp_make_fmtstream
#define __argp_make_fmtstream argp_make_fmtstream
#undef __argp_fmtstream_free
#define __argp_fmtstream_free argp_fmtstream_free
#undef __argp_fmtstream_putc
#define __argp_fmtstream_putc argp_fmtstream_putc
#undef __argp_fmtstream_puts
#define __argp_fmtstream_puts argp_fmtstream_puts
#undef __argp_fmtstream_write
#define __argp_fmtstream_write argp_fmtstream_write
#undef __argp_fmtstream_printf
#define __argp_fmtstream_printf argp_fmtstream_printf
#undef __argp_fmtstream_set_lmargin
#define __argp_fmtstream_set_lmargin argp_fmtstream_set_lmargin
#undef __argp_fmtstream_set_rmargin
#define __argp_fmtstream_set_rmargin argp_fmtstream_set_rmargin
#undef __argp_fmtstream_set_wmargin
#define __argp_fmtstream_set_wmargin argp_fmtstream_set_wmargin
#undef __argp_fmtstream_point
#define __argp_fmtstream_point argp_fmtstream_point
#undef __argp_fmtstream_update
#define __argp_fmtstream_update _argp_fmtstream_update
#undef __argp_fmtstream_ensure
#define __argp_fmtstream_ensure _argp_fmtstream_ensure
#undef __argp_fmtstream_lmargin
#define __argp_fmtstream_lmargin argp_fmtstream_lmargin
#undef __argp_fmtstream_rmargin
#define __argp_fmtstream_rmargin argp_fmtstream_rmargin
#undef __argp_fmtstream_wmargin
#define __argp_fmtstream_wmargin argp_fmtstream_wmargin
/* normal libc functions we call */
#undef __flockfile
#define __flockfile flockfile
#undef __funlockfile
#define __funlockfile funlockfile
#undef __mempcpy
#define __mempcpy mempcpy
#undef __sleep
#define __sleep sleep
#undef __strcasecmp
#define __strcasecmp strcasecmp
#undef __strchrnul
#define __strchrnul strchrnul
#undef __strerror_r
#define __strerror_r strerror_r
#undef __strndup
#define __strndup strndup
#if defined(HAVE_DECL_CLEARERR_UNLOCKED) && !HAVE_DECL_CLEARERR_UNLOCKED
# define clearerr_unlocked(x) clearerr (x)
#endif
#if defined(HAVE_DECL_FEOF_UNLOCKED) && !HAVE_DECL_FEOF_UNLOCKED
# define feof_unlocked(x) feof (x)
# endif
#if defined(HAVE_DECL_FERROR_UNLOCKED) && !HAVE_DECL_FERROR_UNLOCKED
# define ferror_unlocked(x) ferror (x)
# endif
#if defined(HAVE_DECL_FFLUSH_UNLOCKED) && !HAVE_DECL_FFLUSH_UNLOCKED
# define fflush_unlocked(x) fflush (x)
# endif
#if defined(HAVE_DECL_FGETS_UNLOCKED) && !HAVE_DECL_FGETS_UNLOCKED
# define fgets_unlocked(x,y,z) fgets (x,y,z)
# endif
#if defined(HAVE_DECL_FPUTC_UNLOCKED) && !HAVE_DECL_FPUTC_UNLOCKED
# define fputc_unlocked(x,y) fputc (x,y)
# endif
#if defined(HAVE_DECL_FPUTS_UNLOCKED) && !HAVE_DECL_FPUTS_UNLOCKED
# define fputs_unlocked(x,y) fputs (x,y)
# endif
#if defined(HAVE_DECL_FREAD_UNLOCKED) && !HAVE_DECL_FREAD_UNLOCKED
# define fread_unlocked(w,x,y,z) fread (w,x,y,z)
# endif
#if defined(HAVE_DECL_FWRITE_UNLOCKED) && !HAVE_DECL_FWRITE_UNLOCKED
# define fwrite_unlocked(w,x,y,z) fwrite (w,x,y,z)
# endif
#if defined(HAVE_DECL_GETC_UNLOCKED) && !HAVE_DECL_GETC_UNLOCKED
# define getc_unlocked(x) getc (x)
# endif
#if defined(HAVE_DECL_GETCHAR_UNLOCKED) && !HAVE_DECL_GETCHAR_UNLOCKED
# define getchar_unlocked() getchar ()
# endif
#if defined(HAVE_DECL_PUTC_UNLOCKED) && !HAVE_DECL_PUTC_UNLOCKED
# define putc_unlocked(x,y) putc (x,y)
# endif
#if defined(HAVE_DECL_PUTCHAR_UNLOCKED) && !HAVE_DECL_PUTCHAR_UNLOCKED
# define putchar_unlocked(x) putchar (x)
# endif
extern char *__argp_basename (char *name);
#endif /* !_LIBC */
#ifndef __set_errno
#define __set_errno(e) (errno = (e))
#endif
#if 0 || HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME
# define __argp_short_program_name() (program_invocation_short_name)
#else
extern char *__argp_short_program_name (void);
#endif

View file

@ -0,0 +1,941 @@
/* Hierarchial argument parsing, layered over getopt
Copyright (C) 1995-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Miles Bader <miles@gnu.ai.mit.edu>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
/* AIX requires this to be the first thing in the file. */
#ifndef __GNUC__
# if HAVE_ALLOCA_H || 0
# include <alloca.h>
# else
# ifdef _AIX
#pragma alloca
# else
# ifndef alloca /* predefined by HP cc +Olibcalls */
char *alloca ();
# endif
# endif
# endif
#endif
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <getopt.h>
#ifndef _
/* This is for other GNU distributions with internationalized messages.
When compiling libc, the _ macro is predefined. */
# if defined HAVE_LIBINTL_H || 0
# include <libintl.h>
# if 0
# undef dgettext
# define dgettext(domain, msgid) \
__dcgettext (domain, msgid, LC_MESSAGES)
# endif
# else
# define dgettext(domain, msgid) (msgid)
# define gettext(msgid) (msgid)
# endif
#endif
#ifndef N_
# define N_(msgid) (msgid)
#endif
#include <argp.h>
#include "argp-namefrob.h"
/* Getopt return values. */
#define KEY_END (-1) /* The end of the options. */
#define KEY_ARG 1 /* A non-option argument. */
#define KEY_ERR '?' /* An error parsing the options. */
/* The meta-argument used to prevent any further arguments being interpreted
as options. */
#define QUOTE "--"
/* The number of bits we steal in a long-option value for our own use. */
#define GROUP_BITS CHAR_BIT
/* The number of bits available for the user value. */
#define USER_BITS ((sizeof ((struct option *)0)->val * CHAR_BIT) - GROUP_BITS)
#define USER_MASK ((1 << USER_BITS) - 1)
/* EZ alias for ARGP_ERR_UNKNOWN. */
#define EBADKEY ARGP_ERR_UNKNOWN
/* Default options. */
/* When argp is given the --HANG switch, _ARGP_HANG is set and argp will sleep
for one second intervals, decrementing _ARGP_HANG until it's zero. Thus
you can force the program to continue by attaching a debugger and setting
it to 0 yourself. */
static volatile int _argp_hang;
#define OPT_PROGNAME -2
#define OPT_USAGE -3
#define OPT_HANG -4
static const struct argp_option argp_default_options[] =
{
{"help", '?', 0, 0, N_("Give this help list"), -1},
{"usage", OPT_USAGE, 0, 0, N_("Give a short usage message")},
{"program-name",OPT_PROGNAME, N_("NAME"), OPTION_HIDDEN,
N_("Set the program name")},
{"HANG", OPT_HANG, N_("SECS"), OPTION_ARG_OPTIONAL | OPTION_HIDDEN,
N_("Hang for SECS seconds (default 3600)")},
{0, 0}
};
static error_t
argp_default_parser (int key, char *arg, struct argp_state *state)
{
switch (key)
{
case '?':
__argp_state_help (state, state->out_stream, ARGP_HELP_STD_HELP);
break;
case OPT_USAGE:
__argp_state_help (state, state->out_stream,
ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK);
break;
case OPT_PROGNAME: /* Set the program name. */
#if 0 || HAVE_DECL_PROGRAM_INVOCATION_NAME
program_invocation_name = arg;
#endif
/* [Note that some systems only have PROGRAM_INVOCATION_SHORT_NAME (aka
__PROGNAME), in which case, PROGRAM_INVOCATION_NAME is just defined
to be that, so we have to be a bit careful here.] */
/* Update what we use for messages. */
state->name = strrchr (arg, '/');
if (state->name)
state->name++;
else
state->name = arg;
#if 0 || HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME
program_invocation_short_name = state->name;
#endif
if ((state->flags & (ARGP_PARSE_ARGV0 | ARGP_NO_ERRS))
== ARGP_PARSE_ARGV0)
/* Update what getopt uses too. */
state->argv[0] = arg;
break;
case OPT_HANG:
_argp_hang = atoi (arg ? arg : "3600");
while (_argp_hang-- > 0)
__sleep (1);
break;
default:
return EBADKEY;
}
return 0;
}
static const struct argp argp_default_argp =
{argp_default_options, &argp_default_parser, NULL, NULL, NULL, NULL, "libc"};
static const struct argp_option argp_version_options[] =
{
{"version", 'V', 0, 0, N_("Print program version"), -1},
{0, 0}
};
static error_t
argp_version_parser (int key, char *arg, struct argp_state *state)
{
switch (key)
{
case 'V':
if (argp_program_version_hook)
(*argp_program_version_hook) (state->out_stream, state);
else if (argp_program_version)
fprintf (state->out_stream, "%s\n", argp_program_version);
else
__argp_error (state, dgettext (state->root_argp->argp_domain,
"(PROGRAM ERROR) No version known!?"));
if (! (state->flags & ARGP_NO_EXIT))
exit (0);
break;
default:
return EBADKEY;
}
return 0;
}
static const struct argp argp_version_argp =
{argp_version_options, &argp_version_parser, NULL, NULL, NULL, NULL, "libc"};
/* Returns the offset into the getopt long options array LONG_OPTIONS of a
long option with called NAME, or -1 if none is found. Passing NULL as
NAME will return the number of options. */
static int
find_long_option (struct option *long_options, const char *name)
{
struct option *l = long_options;
while (l->name != NULL)
if (name != NULL && strcmp (l->name, name) == 0)
return l - long_options;
else
l++;
if (name == NULL)
return l - long_options;
else
return -1;
}
/* The state of a `group' during parsing. Each group corresponds to a
particular argp structure from the tree of such descending from the top
level argp passed to argp_parse. */
struct group
{
/* This group's parsing function. */
argp_parser_t parser;
/* Which argp this group is from. */
const struct argp *argp;
/* Points to the point in SHORT_OPTS corresponding to the end of the short
options for this group. We use it to determine from which group a
particular short options is from. */
char *short_end;
/* The number of non-option args sucessfully handled by this parser. */
unsigned args_processed;
/* This group's parser's parent's group. */
struct group *parent;
unsigned parent_index; /* And the our position in the parent. */
/* These fields are swapped into and out of the state structure when
calling this group's parser. */
void *input, **child_inputs;
void *hook;
};
/* Call GROUP's parser with KEY and ARG, swapping any group-specific info
from STATE before calling, and back into state afterwards. If GROUP has
no parser, EBADKEY is returned. */
static error_t
group_parse (struct group *group, struct argp_state *state, int key, char *arg)
{
if (group->parser)
{
error_t err;
state->hook = group->hook;
state->input = group->input;
state->child_inputs = group->child_inputs;
state->arg_num = group->args_processed;
err = (*group->parser)(key, arg, state);
group->hook = state->hook;
return err;
}
else
return EBADKEY;
}
struct parser
{
const struct argp *argp;
/* SHORT_OPTS is the getopt short options string for the union of all the
groups of options. */
char *short_opts;
/* LONG_OPTS is the array of getop long option structures for the union of
all the groups of options. */
struct option *long_opts;
/* States of the various parsing groups. */
struct group *groups;
/* The end of the GROUPS array. */
struct group *egroup;
/* An vector containing storage for the CHILD_INPUTS field in all groups. */
void **child_inputs;
/* True if we think using getopt is still useful; if false, then
remaining arguments are just passed verbatim with ARGP_KEY_ARG. This is
cleared whenever getopt returns KEY_END, but may be set again if the user
moves the next argument pointer backwards. */
int try_getopt;
/* State block supplied to parsing routines. */
struct argp_state state;
/* Memory used by this parser. */
void *storage;
};
/* The next usable entries in the various parser tables being filled in by
convert_options. */
struct parser_convert_state
{
struct parser *parser;
char *short_end;
struct option *long_end;
void **child_inputs_end;
};
/* Converts all options in ARGP (which is put in GROUP) and ancestors
into getopt options stored in SHORT_OPTS and LONG_OPTS; SHORT_END and
CVT->LONG_END are the points at which new options are added. Returns the
next unused group entry. CVT holds state used during the conversion. */
static struct group *
convert_options (const struct argp *argp,
struct group *parent, unsigned parent_index,
struct group *group, struct parser_convert_state *cvt)
{
/* REAL is the most recent non-alias value of OPT. */
const struct argp_option *real = argp->options;
const struct argp_child *children = argp->children;
if (real || argp->parser)
{
const struct argp_option *opt;
if (real)
for (opt = real; !__option_is_end (opt); opt++)
{
if (! (opt->flags & OPTION_ALIAS))
/* OPT isn't an alias, so we can use values from it. */
real = opt;
if (! (real->flags & OPTION_DOC))
/* A real option (not just documentation). */
{
if (__option_is_short (opt))
/* OPT can be used as a short option. */
{
*cvt->short_end++ = opt->key;
if (real->arg)
{
*cvt->short_end++ = ':';
if (real->flags & OPTION_ARG_OPTIONAL)
*cvt->short_end++ = ':';
}
*cvt->short_end = '\0'; /* keep 0 terminated */
}
if (opt->name
&& find_long_option (cvt->parser->long_opts, opt->name) < 0)
/* OPT can be used as a long option. */
{
cvt->long_end->name = opt->name;
cvt->long_end->has_arg =
(real->arg
? (real->flags & OPTION_ARG_OPTIONAL
? optional_argument
: required_argument)
: no_argument);
cvt->long_end->flag = 0;
/* we add a disambiguating code to all the user's
values (which is removed before we actually call
the function to parse the value); this means that
the user loses use of the high 8 bits in all his
values (the sign of the lower bits is preserved
however)... */
cvt->long_end->val =
((opt->key ? opt->key : real->key) & USER_MASK)
+ (((group - cvt->parser->groups) + 1) << USER_BITS);
/* Keep the LONG_OPTS list terminated. */
(++cvt->long_end)->name = NULL;
}
}
}
group->parser = argp->parser;
group->argp = argp;
group->short_end = cvt->short_end;
group->args_processed = 0;
group->parent = parent;
group->parent_index = parent_index;
group->input = 0;
group->hook = 0;
group->child_inputs = 0;
if (children)
/* Assign GROUP's CHILD_INPUTS field some space from
CVT->child_inputs_end.*/
{
unsigned num_children = 0;
while (children[num_children].argp)
num_children++;
group->child_inputs = cvt->child_inputs_end;
cvt->child_inputs_end += num_children;
}
parent = group++;
}
else
parent = 0;
if (children)
{
unsigned index = 0;
while (children->argp)
group =
convert_options (children++->argp, parent, index++, group, cvt);
}
return group;
}
/* Find the merged set of getopt options, with keys appropriately prefixed. */
static void
parser_convert (struct parser *parser, const struct argp *argp, int flags)
{
struct parser_convert_state cvt;
cvt.parser = parser;
cvt.short_end = parser->short_opts;
cvt.long_end = parser->long_opts;
cvt.child_inputs_end = parser->child_inputs;
if (flags & ARGP_IN_ORDER)
*cvt.short_end++ = '-';
else if (flags & ARGP_NO_ARGS)
*cvt.short_end++ = '+';
*cvt.short_end = '\0';
cvt.long_end->name = NULL;
parser->argp = argp;
if (argp)
parser->egroup = convert_options (argp, 0, 0, parser->groups, &cvt);
else
parser->egroup = parser->groups; /* No parsers at all! */
}
/* Lengths of various parser fields which we will allocated. */
struct parser_sizes
{
size_t short_len; /* Getopt short options string. */
size_t long_len; /* Getopt long options vector. */
size_t num_groups; /* Group structures we allocate. */
size_t num_child_inputs; /* Child input slots. */
};
/* For ARGP, increments the NUM_GROUPS field in SZS by the total number of
argp structures descended from it, and the SHORT_LEN & LONG_LEN fields by
the maximum lengths of the resulting merged getopt short options string and
long-options array, respectively. */
static void
calc_sizes (const struct argp *argp, struct parser_sizes *szs)
{
const struct argp_child *child = argp->children;
const struct argp_option *opt = argp->options;
if (opt || argp->parser)
{
szs->num_groups++;
if (opt)
{
int num_opts = 0;
while (!__option_is_end (opt++))
num_opts++;
szs->short_len += num_opts * 3; /* opt + up to 2 `:'s */
szs->long_len += num_opts;
}
}
if (child)
while (child->argp)
{
calc_sizes ((child++)->argp, szs);
szs->num_child_inputs++;
}
}
/* Initializes PARSER to parse ARGP in a manner described by FLAGS. */
static error_t
parser_init (struct parser *parser, const struct argp *argp,
int argc, char **argv, int flags, void *input)
{
error_t err = 0;
struct group *group;
struct parser_sizes szs;
szs.short_len = (flags & ARGP_NO_ARGS) ? 0 : 1;
szs.long_len = 0;
szs.num_groups = 0;
szs.num_child_inputs = 0;
if (argp)
calc_sizes (argp, &szs);
/* Lengths of the various bits of storage used by PARSER. */
#define GLEN (szs.num_groups + 1) * sizeof (struct group)
#define CLEN (szs.num_child_inputs * sizeof (void *))
#define LLEN ((szs.long_len + 1) * sizeof (struct option))
#define SLEN (szs.short_len + 1)
parser->storage = malloc (GLEN + CLEN + LLEN + SLEN);
if (! parser->storage)
return ENOMEM;
parser->groups = parser->storage;
parser->child_inputs = parser->storage + GLEN;
parser->long_opts = parser->storage + GLEN + CLEN;
parser->short_opts = parser->storage + GLEN + CLEN + LLEN;
memset (parser->child_inputs, 0, szs.num_child_inputs * sizeof (void *));
parser_convert (parser, argp, flags);
memset (&parser->state, 0, sizeof (struct argp_state));
parser->state.root_argp = parser->argp;
parser->state.argc = argc;
parser->state.argv = argv;
parser->state.flags = flags;
parser->state.err_stream = stderr;
parser->state.out_stream = stdout;
parser->state.next = 0; /* Tell getopt to initialize. */
parser->state.pstate = parser;
parser->try_getopt = 1;
/* Call each parser for the first time, giving it a chance to propagate
values to child parsers. */
if (parser->groups < parser->egroup)
parser->groups->input = input;
for (group = parser->groups;
group < parser->egroup && (!err || err == EBADKEY);
group++)
{
if (group->parent)
/* If a child parser, get the initial input value from the parent. */
group->input = group->parent->child_inputs[group->parent_index];
if (!group->parser
&& group->argp->children && group->argp->children->argp)
/* For the special case where no parsing function is supplied for an
argp, propagate its input to its first child, if any (this just
makes very simple wrapper argps more convenient). */
group->child_inputs[0] = group->input;
err = group_parse (group, &parser->state, ARGP_KEY_INIT, 0);
}
if (err == EBADKEY)
err = 0; /* Some parser didn't understand. */
if (err)
return err;
if (parser->state.flags & ARGP_NO_ERRS)
{
opterr = 0;
if (parser->state.flags & ARGP_PARSE_ARGV0)
/* getopt always skips ARGV[0], so we have to fake it out. As long
as OPTERR is 0, then it shouldn't actually try to access it. */
parser->state.argv--, parser->state.argc++;
}
else
opterr = 1; /* Print error messages. */
if (parser->state.argv == argv && argv[0])
/* There's an argv[0]; use it for messages. */
{
char *short_name = strrchr (argv[0], '/');
parser->state.name = short_name ? short_name + 1 : argv[0];
}
else
parser->state.name = __argp_short_program_name ();
return 0;
}
/* Free any storage consumed by PARSER (but not PARSER itself). */
static error_t
parser_finalize (struct parser *parser,
error_t err, int arg_ebadkey, int *end_index)
{
struct group *group;
if (err == EBADKEY && arg_ebadkey)
/* Suppress errors generated by unparsed arguments. */
err = 0;
if (! err)
{
if (parser->state.next == parser->state.argc)
/* We successfully parsed all arguments! Call all the parsers again,
just a few more times... */
{
for (group = parser->groups;
group < parser->egroup && (!err || err==EBADKEY);
group++)
if (group->args_processed == 0)
err = group_parse (group, &parser->state, ARGP_KEY_NO_ARGS, 0);
for (group = parser->egroup - 1;
group >= parser->groups && (!err || err==EBADKEY);
group--)
err = group_parse (group, &parser->state, ARGP_KEY_END, 0);
if (err == EBADKEY)
err = 0; /* Some parser didn't understand. */
/* Tell the user that all arguments are parsed. */
if (end_index)
*end_index = parser->state.next;
}
else if (end_index)
/* Return any remaining arguments to the user. */
*end_index = parser->state.next;
else
/* No way to return the remaining arguments, they must be bogus. */
{
if (!(parser->state.flags & ARGP_NO_ERRS)
&& parser->state.err_stream)
fprintf (parser->state.err_stream,
dgettext (parser->argp->argp_domain,
"%s: Too many arguments\n"),
parser->state.name);
err = EBADKEY;
}
}
/* Okay, we're all done, with either an error or success; call the parsers
to indicate which one. */
if (err)
{
/* Maybe print an error message. */
if (err == EBADKEY)
/* An appropriate message describing what the error was should have
been printed earlier. */
__argp_state_help (&parser->state, parser->state.err_stream,
ARGP_HELP_STD_ERR);
/* Since we didn't exit, give each parser an error indication. */
for (group = parser->groups; group < parser->egroup; group++)
group_parse (group, &parser->state, ARGP_KEY_ERROR, 0);
}
else
/* Notify parsers of success, and propagate back values from parsers. */
{
/* We pass over the groups in reverse order so that child groups are
given a chance to do there processing before passing back a value to
the parent. */
for (group = parser->egroup - 1
; group >= parser->groups && (!err || err == EBADKEY)
; group--)
err = group_parse (group, &parser->state, ARGP_KEY_SUCCESS, 0);
if (err == EBADKEY)
err = 0; /* Some parser didn't understand. */
}
/* Call parsers once more, to do any final cleanup. Errors are ignored. */
for (group = parser->egroup - 1; group >= parser->groups; group--)
group_parse (group, &parser->state, ARGP_KEY_FINI, 0);
if (err == EBADKEY)
err = EINVAL;
free (parser->storage);
return err;
}
/* Call the user parsers to parse the non-option argument VAL, at the current
position, returning any error. The state NEXT pointer is assumed to have
been adjusted (by getopt) to point after this argument; this function will
adjust it correctly to reflect however many args actually end up being
consumed. */
static error_t
parser_parse_arg (struct parser *parser, char *val)
{
/* Save the starting value of NEXT, first adjusting it so that the arg
we're parsing is again the front of the arg vector. */
int index = --parser->state.next;
error_t err = EBADKEY;
struct group *group;
int key = 0; /* Which of ARGP_KEY_ARG[S] we used. */
/* Try to parse the argument in each parser. */
for (group = parser->groups
; group < parser->egroup && err == EBADKEY
; group++)
{
parser->state.next++; /* For ARGP_KEY_ARG, consume the arg. */
key = ARGP_KEY_ARG;
err = group_parse (group, &parser->state, key, val);
if (err == EBADKEY)
/* This parser doesn't like ARGP_KEY_ARG; try ARGP_KEY_ARGS instead. */
{
parser->state.next--; /* For ARGP_KEY_ARGS, put back the arg. */
key = ARGP_KEY_ARGS;
err = group_parse (group, &parser->state, key, 0);
}
}
if (! err)
{
if (key == ARGP_KEY_ARGS)
/* The default for ARGP_KEY_ARGS is to assume that if NEXT isn't
changed by the user, *all* arguments should be considered
consumed. */
parser->state.next = parser->state.argc;
if (parser->state.next > index)
/* Remember that we successfully processed a non-option
argument -- but only if the user hasn't gotten tricky and set
the clock back. */
(--group)->args_processed += (parser->state.next - index);
else
/* The user wants to reparse some args, give getopt another try. */
parser->try_getopt = 1;
}
return err;
}
/* Call the user parsers to parse the option OPT, with argument VAL, at the
current position, returning any error. */
static error_t
parser_parse_opt (struct parser *parser, int opt, char *val)
{
/* The group key encoded in the high bits; 0 for short opts or
group_number + 1 for long opts. */
int group_key = opt >> USER_BITS;
error_t err = EBADKEY;
if (group_key == 0)
/* A short option. By comparing OPT's position in SHORT_OPTS to the
various starting positions in each group's SHORT_END field, we can
determine which group OPT came from. */
{
struct group *group;
char *short_index = strchr (parser->short_opts, opt);
if (short_index)
for (group = parser->groups; group < parser->egroup; group++)
if (group->short_end > short_index)
{
err = group_parse (group, &parser->state, opt, optarg);
break;
}
}
else
/* A long option. We use shifts instead of masking for extracting
the user value in order to preserve the sign. */
err =
group_parse (&parser->groups[group_key - 1], &parser->state,
(opt << GROUP_BITS) >> GROUP_BITS, optarg);
if (err == EBADKEY)
/* At least currently, an option not recognized is an error in the
parser, because we pre-compute which parser is supposed to deal
with each option. */
{
static const char bad_key_err[] =
N_("(PROGRAM ERROR) Option should have been recognized!?");
if (group_key == 0)
__argp_error (&parser->state, "-%c: %s", opt,
dgettext (parser->argp->argp_domain, bad_key_err));
else
{
struct option *long_opt = parser->long_opts;
while (long_opt->val != opt && long_opt->name)
long_opt++;
__argp_error (&parser->state, "--%s: %s",
long_opt->name ? long_opt->name : "???",
dgettext (parser->argp->argp_domain, bad_key_err));
}
}
return err;
}
/* Parse the next argument in PARSER (as indicated by PARSER->state.next).
Any error from the parsers is returned, and *ARGP_EBADKEY indicates
whether a value of EBADKEY is due to an unrecognized argument (which is
generally not fatal). */
static error_t
parser_parse_next (struct parser *parser, int *arg_ebadkey)
{
int opt;
error_t err = 0;
if (parser->state.quoted && parser->state.next < parser->state.quoted)
/* The next argument pointer has been moved to before the quoted
region, so pretend we never saw the quoting `--', and give getopt
another chance. If the user hasn't removed it, getopt will just
process it again. */
parser->state.quoted = 0;
if (parser->try_getopt && !parser->state.quoted)
/* Give getopt a chance to parse this. */
{
/* Put it back in OPTIND for getopt. */
optind = parser->state.next;
/* Distinguish KEY_ERR from a real option. */
optopt = KEY_END;
if (parser->state.flags & ARGP_LONG_ONLY)
opt = getopt_long_only (parser->state.argc, parser->state.argv,
parser->short_opts, parser->long_opts, 0);
else
opt = getopt_long (parser->state.argc, parser->state.argv,
parser->short_opts, parser->long_opts, 0);
/* And see what getopt did. */
parser->state.next = optind;
if (opt == KEY_END)
/* Getopt says there are no more options, so stop using
getopt; we'll continue if necessary on our own. */
{
parser->try_getopt = 0;
if (parser->state.next > 1
&& strcmp (parser->state.argv[parser->state.next - 1], QUOTE)
== 0)
/* Not only is this the end of the options, but it's a
`quoted' region, which may have args that *look* like
options, so we definitely shouldn't try to use getopt past
here, whatever happens. */
parser->state.quoted = parser->state.next;
}
else if (opt == KEY_ERR && optopt != KEY_END)
/* KEY_ERR can have the same value as a valid user short
option, but in the case of a real error, getopt sets OPTOPT
to the offending character, which can never be KEY_END. */
{
*arg_ebadkey = 0;
return EBADKEY;
}
}
else
opt = KEY_END;
if (opt == KEY_END)
{
/* We're past what getopt considers the options. */
if (parser->state.next >= parser->state.argc
|| (parser->state.flags & ARGP_NO_ARGS))
/* Indicate that we're done. */
{
*arg_ebadkey = 1;
return EBADKEY;
}
else
/* A non-option arg; simulate what getopt might have done. */
{
opt = KEY_ARG;
optarg = parser->state.argv[parser->state.next++];
}
}
if (opt == KEY_ARG)
/* A non-option argument; try each parser in turn. */
err = parser_parse_arg (parser, optarg);
else
err = parser_parse_opt (parser, opt, optarg);
if (err == EBADKEY)
*arg_ebadkey = (opt == KEY_END || opt == KEY_ARG);
return err;
}
/* Parse the options strings in ARGC & ARGV according to the argp in ARGP.
FLAGS is one of the ARGP_ flags above. If END_INDEX is non-NULL, the
index in ARGV of the first unparsed option is returned in it. If an
unknown option is present, EINVAL is returned; if some parser routine
returned a non-zero value, it is returned; otherwise 0 is returned. */
error_t
__argp_parse (const struct argp *argp, int argc, char **argv, unsigned flags,
int *end_index, void *input)
{
error_t err;
struct parser parser;
/* If true, then err == EBADKEY is a result of a non-option argument failing
to be parsed (which in some cases isn't actually an error). */
int arg_ebadkey = 0;
if (! (flags & ARGP_NO_HELP))
/* Add our own options. */
{
struct argp_child *child = alloca (4 * sizeof (struct argp_child));
struct argp *top_argp = alloca (sizeof (struct argp));
/* TOP_ARGP has no options, it just serves to group the user & default
argps. */
memset (top_argp, 0, sizeof (*top_argp));
top_argp->children = child;
memset (child, 0, 4 * sizeof (struct argp_child));
if (argp)
(child++)->argp = argp;
(child++)->argp = &argp_default_argp;
if (argp_program_version || argp_program_version_hook)
(child++)->argp = &argp_version_argp;
child->argp = 0;
argp = top_argp;
}
/* Construct a parser for these arguments. */
err = parser_init (&parser, argp, argc, argv, flags, input);
if (! err)
/* Parse! */
{
while (! err)
err = parser_parse_next (&parser, &arg_ebadkey);
err = parser_finalize (&parser, err, arg_ebadkey, end_index);
}
return err;
}
#ifdef weak_alias
weak_alias (__argp_parse, argp_parse)
#endif
/* Return the input field for ARGP in the parser corresponding to STATE; used
by the help routines. */
void *
__argp_input (const struct argp *argp, const struct argp_state *state)
{
if (state)
{
struct group *group;
struct parser *parser = state->pstate;
for (group = parser->groups; group < parser->egroup; group++)
if (group->argp == argp)
return group->input;
}
return 0;
}
#ifdef weak_alias
weak_alias (__argp_input, _argp_input)
#endif

View file

@ -0,0 +1,24 @@
/* Default definition for ARGP_PROGRAM_VERSION.
Copyright (C) 1996-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Miles Bader <miles@gnu.ai.mit.edu>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/* If set by the user program to a non-zero value, then a default option
--version is added (unless the ARGP_NO_HELP flag is used), which will
print this this string followed by a newline and exit (unless the
ARGP_NO_EXIT flag is used). Overridden by ARGP_PROGRAM_VERSION_HOOK. */
const char *argp_program_version;

View file

@ -0,0 +1,31 @@
/* Default definition for ARGP_PROGRAM_VERSION_HOOK.
Copyright (C) 1996-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Miles Bader <miles@gnu.ai.mit.edu>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "argp.h"
/* If set by the user program to a non-zero value, then a default option
--version is added (unless the ARGP_NO_HELP flag is used), which calls
this function with a stream to print the version to and a pointer to the
current parsing state, and then exits (unless the ARGP_NO_EXIT flag is
used). This variable takes precedent over ARGP_PROGRAM_VERSION. */
void (*argp_program_version_hook) (FILE *stream, struct argp_state *state);

View file

@ -0,0 +1,212 @@
/* Test program for argp argument parser
Copyright (C) 1997-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Miles Bader <miles@gnu.ai.mit.edu>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <argp.h>
const char *argp_program_version = "argp-test 1.0";
struct argp_option sub_options[] =
{
{"subopt1", 's', 0, 0, "Nested option 1"},
{"subopt2", 'S', 0, 0, "Nested option 2"},
{ 0, 0, 0, 0, "Some more nested options:", 10},
{"subopt3", 'p', 0, 0, "Nested option 3"},
{"subopt4", 'q', 0, 0, "Nested option 4", 1},
{0}
};
static const char sub_args_doc[] = "STRING...\n-";
static const char sub_doc[] = "\vThis is the doc string from the sub-arg-parser.";
static error_t
sub_parse_opt (int key, char *arg, struct argp_state *state)
{
switch (key)
{
case ARGP_KEY_NO_ARGS:
printf ("NO SUB ARGS\n");
break;
case ARGP_KEY_ARG:
printf ("SUB ARG: %s\n", arg);
break;
case 's' : case 'S': case 'p': case 'q':
printf ("SUB KEY %c\n", key);
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
static char *
sub_help_filter (int key, const char *text, void *input)
{
if (key == ARGP_KEY_HELP_EXTRA)
return strdup ("This is some extra text from the sub parser (note that it \
is preceded by a blank line).");
else
return (char *)text;
}
static struct argp sub_argp = {
sub_options, sub_parse_opt, sub_args_doc, sub_doc, 0, sub_help_filter
};
/* Structure used to communicate with the parsing functions. */
struct params
{
unsigned foonly; /* Value parsed for foonly. */
unsigned foonly_default; /* Default value for it. */
};
#define OPT_PGRP 1
#define OPT_SESS 2
struct argp_option options[] =
{
{"pid", 'p', "PID", 0, "List the process PID"},
{"pgrp", OPT_PGRP,"PGRP",0, "List processes in the process group PGRP"},
{"no-parent", 'P', 0, 0, "Include processes without parents"},
{0, 'x', 0, OPTION_ALIAS},
{"all-fields",'Q', 0, 0, "Don't elide unusable fields (normally"
" if there's some reason ps can't"
" print a field for any process, it's"
" removed from the output entirely)" },
{"reverse", 'r', 0, 0, "Reverse the order of any sort"},
{"gratuitously-long-reverse-option", 0, 0, OPTION_ALIAS},
{"session", OPT_SESS,"SID", OPTION_ARG_OPTIONAL,
"Add the processes from the session"
" SID (which defaults to the sid of"
" the current process)" },
{0,0,0,0, "Here are some more options:"},
{"foonly", 'f', "ZOT", OPTION_ARG_OPTIONAL, "Glork a foonly"},
{"zaza", 'z', 0, 0, "Snit a zar"},
{0}
};
static const char args_doc[] = "STRING";
static const char doc[] = "Test program for argp."
"\vThis doc string comes after the options."
"\nHey! Some manual formatting!"
"\nThe current time is: %s";
static void
popt (int key, char *arg)
{
char buf[12];
if (isprint (key))
sprintf (buf, "%c", key);
else
sprintf (buf, "%d", key);
if (arg)
printf ("KEY %s: %s\n", buf, arg);
else
printf ("KEY %s\n", buf);
}
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
struct params *params = state->input;
switch (key)
{
case ARGP_KEY_NO_ARGS:
printf ("NO ARGS\n");
break;
case ARGP_KEY_ARG:
if (state->arg_num > 0)
return ARGP_ERR_UNKNOWN; /* Leave it for the sub-arg parser. */
printf ("ARG: %s\n", arg);
break;
case 'f':
if (arg)
params->foonly = atoi (arg);
else
params->foonly = params->foonly_default;
popt (key, arg);
break;
case 'p': case 'P': case OPT_PGRP: case 'x': case 'Q':
case 'r': case OPT_SESS: case 'z':
popt (key, arg);
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
static char *
help_filter (int key, const char *text, void *input)
{
char *new_text;
struct params *params = input;
if (key == ARGP_KEY_HELP_POST_DOC && text)
{
time_t now = time (0);
asprintf (&new_text, text, ctime (&now));
}
else if (key == 'f')
/* Show the default for the --foonly option. */
asprintf (&new_text, "%s (ZOT defaults to %x)",
text, params->foonly_default);
else
new_text = (char *)text;
return new_text;
}
static struct argp_child argp_children[] = { { &sub_argp }, { 0 } };
static struct argp argp = {
options, parse_opt, args_doc, doc, argp_children, help_filter
};
int
main (int argc, char **argv)
{
struct params params;
params.foonly = 0;
params.foonly_default = random ();
argp_parse (&argp, argc, argv, 0, 0, &params);
printf ("After parsing: foonly = %x\n", params.foonly);
return 0;
}

View file

@ -0,0 +1,582 @@
/* Hierarchical argument parsing, layered over getopt.
Copyright (C) 1995-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Miles Bader <miles@gnu.ai.mit.edu>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#ifndef _ARGP_H
#define _ARGP_H
#include <stdio.h>
#include <ctype.h>
#include <getopt.h>
#include <limits.h>
#include <errno.h>
/* From glibc's <sys/cdef.h> */
# if (defined __cplusplus \
|| (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L))
# define __inline inline
# else
# define __inline /* No inline functions. */
# endif
# define __THROW
# define __THROWNL
# define __NTH(fct) fct
/* FIXME: conflict? */
typedef int error_t;
/* FIXME: What's the right way to check for __restrict? Sun's cc seems
not to have it. Perhaps it's easiest to just delete the use of
__restrict from the prototypes. */
#ifndef __restrict
# ifndef __GNUC___
# define __restrict
# endif
#endif
/* NOTE: We can't use the autoconf tests, since this is supposed to be
an installed header file and argp's config.h is of course not
installed. */
#ifndef PRINTF_STYLE
# if __GNUC__ >= 2
# define PRINTF_STYLE(f, a) __attribute__ ((__format__ (__printf__, f, a)))
# else
# define PRINTF_STYLE(f, a)
# endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* A description of a particular option. A pointer to an array of
these is passed in the OPTIONS field of an argp structure. Each option
entry can correspond to one long option and/or one short option; more
names for the same option can be added by following an entry in an option
array with options having the OPTION_ALIAS flag set. */
struct argp_option
{
/* The long option name. For more than one name for the same option, you
can use following options with the OPTION_ALIAS flag set. */
const char *name;
/* What key is returned for this option. If > 0 and printable, then it's
also accepted as a short option. */
int key;
/* If non-NULL, this is the name of the argument associated with this
option, which is required unless the OPTION_ARG_OPTIONAL flag is set. */
const char *arg;
/* OPTION_ flags. */
int flags;
/* The doc string for this option. If both NAME and KEY are 0, This string
will be printed outdented from the normal option column, making it
useful as a group header (it will be the first thing printed in its
group); in this usage, it's conventional to end the string with a `:'. */
const char *doc;
/* The group this option is in. In a long help message, options are sorted
alphabetically within each group, and the groups presented in the order
0, 1, 2, ..., n, -m, ..., -2, -1. Every entry in an options array with
if this field 0 will inherit the group number of the previous entry, or
zero if it's the first one, unless its a group header (NAME and KEY both
0), in which case, the previous entry + 1 is the default. Automagic
options such as --help are put into group -1. */
int group;
};
/* The argument associated with this option is optional. */
#define OPTION_ARG_OPTIONAL 0x1
/* This option isn't displayed in any help messages. */
#define OPTION_HIDDEN 0x2
/* This option is an alias for the closest previous non-alias option. This
means that it will be displayed in the same help entry, and will inherit
fields other than NAME and KEY from the aliased option. */
#define OPTION_ALIAS 0x4
/* This option isn't actually an option (and so should be ignored by the
actual option parser), but rather an arbitrary piece of documentation that
should be displayed in much the same manner as the options. If this flag
is set, then the option NAME field is displayed unmodified (e.g., no `--'
prefix is added) at the left-margin (where a *short* option would normally
be displayed), and the documentation string in the normal place. For
purposes of sorting, any leading whitespace and punctuation is ignored,
except that if the first non-whitespace character is not `-', this entry
is displayed after all options (and OPTION_DOC entries with a leading `-')
in the same group. */
#define OPTION_DOC 0x8
/* This option shouldn't be included in `long' usage messages (but is still
included in help messages). This is mainly intended for options that are
completely documented in an argp's ARGS_DOC field, in which case including
the option in the generic usage list would be redundant. For instance,
if ARGS_DOC is "FOO BAR\n-x BLAH", and the `-x' option's purpose is to
distinguish these two cases, -x should probably be marked
OPTION_NO_USAGE. */
#define OPTION_NO_USAGE 0x10
struct argp; /* fwd declare this type */
struct argp_state; /* " */
struct argp_child; /* " */
/* The type of a pointer to an argp parsing function. */
typedef error_t (*argp_parser_t) (int __key, char *__arg,
struct argp_state *__state);
/* What to return for unrecognized keys. For special ARGP_KEY_ keys, such
returns will simply be ignored. For user keys, this error will be turned
into EINVAL (if the call to argp_parse is such that errors are propagated
back to the user instead of exiting); returning EINVAL itself would result
in an immediate stop to parsing in *all* cases. */
#define ARGP_ERR_UNKNOWN E2BIG /* Hurd should never need E2BIG. XXX */
/* Special values for the KEY argument to an argument parsing function.
ARGP_ERR_UNKNOWN should be returned if they aren't understood.
The sequence of keys to a parsing function is either (where each
uppercased word should be prefixed by `ARGP_KEY_' and opt is a user key):
INIT opt... NO_ARGS END SUCCESS -- No non-option arguments at all
or INIT (opt | ARG)... END SUCCESS -- All non-option args parsed
or INIT (opt | ARG)... SUCCESS -- Some non-option arg unrecognized
The third case is where every parser returned ARGP_KEY_UNKNOWN for an
argument, in which case parsing stops at that argument (returning the
unparsed arguments to the caller of argp_parse if requested, or stopping
with an error message if not).
If an error occurs (either detected by argp, or because the parsing
function returned an error value), then the parser is called with
ARGP_KEY_ERROR, and no further calls are made. */
/* This is not an option at all, but rather a command line argument. If a
parser receiving this key returns success, the fact is recorded, and the
ARGP_KEY_NO_ARGS case won't be used. HOWEVER, if while processing the
argument, a parser function decrements the NEXT field of the state it's
passed, the option won't be considered processed; this is to allow you to
actually modify the argument (perhaps into an option), and have it
processed again. */
#define ARGP_KEY_ARG 0
/* There are remaining arguments not parsed by any parser, which may be found
starting at (STATE->argv + STATE->next). If success is returned, but
STATE->next left untouched, it's assumed that all arguments were consume,
otherwise, the parser should adjust STATE->next to reflect any arguments
consumed. */
#define ARGP_KEY_ARGS 0x1000006
/* There are no more command line arguments at all. */
#define ARGP_KEY_END 0x1000001
/* Because it's common to want to do some special processing if there aren't
any non-option args, user parsers are called with this key if they didn't
successfully process any non-option arguments. Called just before
ARGP_KEY_END (where more general validity checks on previously parsed
arguments can take place). */
#define ARGP_KEY_NO_ARGS 0x1000002
/* Passed in before any parsing is done. Afterwards, the values of each
element of the CHILD_INPUT field, if any, in the state structure is
copied to each child's state to be the initial value of the INPUT field. */
#define ARGP_KEY_INIT 0x1000003
/* Use after all other keys, including SUCCESS & END. */
#define ARGP_KEY_FINI 0x1000007
/* Passed in when parsing has successfully been completed (even if there are
still arguments remaining). */
#define ARGP_KEY_SUCCESS 0x1000004
/* Passed in if an error occurs. */
#define ARGP_KEY_ERROR 0x1000005
/* An argp structure contains a set of options declarations, a function to
deal with parsing one, documentation string, a possible vector of child
argp's, and perhaps a function to filter help output. When actually
parsing options, getopt is called with the union of all the argp
structures chained together through their CHILD pointers, with conflicts
being resolved in favor of the first occurrence in the chain. */
struct argp
{
/* An array of argp_option structures, terminated by an entry with both
NAME and KEY having a value of 0. */
const struct argp_option *options;
/* What to do with an option from this structure. KEY is the key
associated with the option, and ARG is any associated argument (NULL if
none was supplied). If KEY isn't understood, ARGP_ERR_UNKNOWN should be
returned. If a non-zero, non-ARGP_ERR_UNKNOWN value is returned, then
parsing is stopped immediately, and that value is returned from
argp_parse(). For special (non-user-supplied) values of KEY, see the
ARGP_KEY_ definitions below. */
argp_parser_t parser;
/* A string describing what other arguments are wanted by this program. It
is only used by argp_usage to print the `Usage:' message. If it
contains newlines, the strings separated by them are considered
alternative usage patterns, and printed on separate lines (lines after
the first are prefix by ` or: ' instead of `Usage:'). */
const char *args_doc;
/* If non-NULL, a string containing extra text to be printed before and
after the options in a long help message (separated by a vertical tab
`\v' character). */
const char *doc;
/* A vector of argp_children structures, terminated by a member with a 0
argp field, pointing to child argps should be parsed with this one. Any
conflicts are resolved in favor of this argp, or early argps in the
CHILDREN list. This field is useful if you use libraries that supply
their own argp structure, which you want to use in conjunction with your
own. */
const struct argp_child *children;
/* If non-zero, this should be a function to filter the output of help
messages. KEY is either a key from an option, in which case TEXT is
that option's help text, or a special key from the ARGP_KEY_HELP_
defines, below, describing which other help text TEXT is. The function
should return either TEXT, if it should be used as-is, a replacement
string, which should be malloced, and will be freed by argp, or NULL,
meaning `print nothing'. The value for TEXT is *after* any translation
has been done, so if any of the replacement text also needs translation,
that should be done by the filter function. INPUT is either the input
supplied to argp_parse, or NULL, if argp_help was called directly. */
char *(*help_filter) (int __key, const char *__text, void *__input);
/* If non-zero the strings used in the argp library are translated using
the domain described by this string. Otherwise the currently installed
default domain is used. */
const char *argp_domain;
};
/* Possible KEY arguments to a help filter function. */
#define ARGP_KEY_HELP_PRE_DOC 0x2000001 /* Help text preceding options. */
#define ARGP_KEY_HELP_POST_DOC 0x2000002 /* Help text following options. */
#define ARGP_KEY_HELP_HEADER 0x2000003 /* Option header string. */
#define ARGP_KEY_HELP_EXTRA 0x2000004 /* After all other documentation;
TEXT is NULL for this key. */
/* Explanatory note emitted when duplicate option arguments have been
suppressed. */
#define ARGP_KEY_HELP_DUP_ARGS_NOTE 0x2000005
#define ARGP_KEY_HELP_ARGS_DOC 0x2000006 /* Argument doc string. */
/* When an argp has a non-zero CHILDREN field, it should point to a vector of
argp_child structures, each of which describes a subsidiary argp. */
struct argp_child
{
/* The child parser. */
const struct argp *argp;
/* Flags for this child. */
int flags;
/* If non-zero, an optional header to be printed in help output before the
child options. As a side-effect, a non-zero value forces the child
options to be grouped together; to achieve this effect without actually
printing a header string, use a value of "". */
const char *header;
/* Where to group the child options relative to the other (`consolidated')
options in the parent argp; the values are the same as the GROUP field
in argp_option structs, but all child-groupings follow parent options at
a particular group level. If both this field and HEADER are zero, then
they aren't grouped at all, but rather merged with the parent options
(merging the child's grouping levels with the parents). */
int group;
};
/* Parsing state. This is provided to parsing functions called by argp,
which may examine and, as noted, modify fields. */
struct argp_state
{
/* The top level ARGP being parsed. */
const struct argp *root_argp;
/* The argument vector being parsed. May be modified. */
int argc;
char **argv;
/* The index in ARGV of the next arg that to be parsed. May be modified. */
int next;
/* The flags supplied to argp_parse. May be modified. */
unsigned flags;
/* While calling a parsing function with a key of ARGP_KEY_ARG, this is the
number of the current arg, starting at zero, and incremented after each
such call returns. At all other times, this is the number of such
arguments that have been processed. */
unsigned arg_num;
/* If non-zero, the index in ARGV of the first argument following a special
`--' argument (which prevents anything following being interpreted as an
option). Only set once argument parsing has proceeded past this point. */
int quoted;
/* An arbitrary pointer passed in from the user. */
void *input;
/* Values to pass to child parsers. This vector will be the same length as
the number of children for the current parser. */
void **child_inputs;
/* For the parser's use. Initialized to 0. */
void *hook;
/* The name used when printing messages. This is initialized to ARGV[0],
or PROGRAM_INVOCATION_NAME if that is unavailable. */
char *name;
/* Streams used when argp prints something. */
FILE *err_stream; /* For errors; initialized to stderr. */
FILE *out_stream; /* For information; initialized to stdout. */
void *pstate; /* Private, for use by argp. */
};
/* Flags for argp_parse (note that the defaults are those that are
convenient for program command line parsing): */
/* Don't ignore the first element of ARGV. Normally (and always unless
ARGP_NO_ERRS is set) the first element of the argument vector is
skipped for option parsing purposes, as it corresponds to the program name
in a command line. */
#define ARGP_PARSE_ARGV0 0x01
/* Don't print error messages for unknown options to stderr; unless this flag
is set, ARGP_PARSE_ARGV0 is ignored, as ARGV[0] is used as the program
name in the error messages. This flag implies ARGP_NO_EXIT (on the
assumption that silent exiting upon errors is bad behaviour). */
#define ARGP_NO_ERRS 0x02
/* Don't parse any non-option args. Normally non-option args are parsed by
calling the parse functions with a key of ARGP_KEY_ARG, and the actual arg
as the value. Since it's impossible to know which parse function wants to
handle it, each one is called in turn, until one returns 0 or an error
other than ARGP_ERR_UNKNOWN; if an argument is handled by no one, the
argp_parse returns prematurely (but with a return value of 0). If all
args have been parsed without error, all parsing functions are called one
last time with a key of ARGP_KEY_END. This flag needn't normally be set,
as the normal behavior is to stop parsing as soon as some argument can't
be handled. */
#define ARGP_NO_ARGS 0x04
/* Parse options and arguments in the same order they occur on the command
line -- normally they're rearranged so that all options come first. */
#define ARGP_IN_ORDER 0x08
/* Don't provide the standard long option --help, which causes usage and
option help information to be output to stdout, and exit (0) called. */
#define ARGP_NO_HELP 0x10
/* Don't exit on errors (they may still result in error messages). */
#define ARGP_NO_EXIT 0x20
/* Use the gnu getopt `long-only' rules for parsing arguments. */
#define ARGP_LONG_ONLY 0x40
/* Turns off any message-printing/exiting options. */
#define ARGP_SILENT (ARGP_NO_EXIT | ARGP_NO_ERRS | ARGP_NO_HELP)
/* Parse the options strings in ARGC & ARGV according to the options in ARGP.
FLAGS is one of the ARGP_ flags above. If ARG_INDEX is non-NULL, the
index in ARGV of the first unparsed option is returned in it. If an
unknown option is present, ARGP_ERR_UNKNOWN is returned; if some parser
routine returned a non-zero value, it is returned; otherwise 0 is
returned. This function may also call exit unless the ARGP_NO_HELP flag
is set. INPUT is a pointer to a value to be passed in to the parser. */
extern error_t argp_parse (const struct argp *__restrict __argp,
int __argc, char **__restrict __argv,
unsigned __flags, int *__restrict __arg_index,
void *__restrict __input);
extern error_t __argp_parse (const struct argp *__restrict __argp,
int __argc, char **__restrict __argv,
unsigned __flags, int *__restrict __arg_index,
void *__restrict __input);
/* Global variables. */
/* If defined or set by the user program to a non-zero value, then a default
option --version is added (unless the ARGP_NO_HELP flag is used), which
will print this string followed by a newline and exit (unless the
ARGP_NO_EXIT flag is used). Overridden by ARGP_PROGRAM_VERSION_HOOK. */
extern const char *argp_program_version;
/* If defined or set by the user program to a non-zero value, then a default
option --version is added (unless the ARGP_NO_HELP flag is used), which
calls this function with a stream to print the version to and a pointer to
the current parsing state, and then exits (unless the ARGP_NO_EXIT flag is
used). This variable takes precedent over ARGP_PROGRAM_VERSION. */
extern void (*argp_program_version_hook) (FILE *__restrict __stream,
struct argp_state *__restrict
__state);
/* If defined or set by the user program, it should point to string that is
the bug-reporting address for the program. It will be printed by
argp_help if the ARGP_HELP_BUG_ADDR flag is set (as it is by various
standard help messages), embedded in a sentence that says something like
`Report bugs to ADDR.'. */
extern const char *argp_program_bug_address;
/* The exit status that argp will use when exiting due to a parsing error.
If not defined or set by the user program, this defaults to EX_USAGE from
<sysexits.h>. */
extern error_t argp_err_exit_status;
/* Flags for argp_help. */
#define ARGP_HELP_USAGE 0x01 /* a Usage: message. */
#define ARGP_HELP_SHORT_USAGE 0x02 /* " but don't actually print options. */
#define ARGP_HELP_SEE 0x04 /* a `Try ... for more help' message. */
#define ARGP_HELP_LONG 0x08 /* a long help message. */
#define ARGP_HELP_PRE_DOC 0x10 /* doc string preceding long help. */
#define ARGP_HELP_POST_DOC 0x20 /* doc string following long help. */
#define ARGP_HELP_DOC (ARGP_HELP_PRE_DOC | ARGP_HELP_POST_DOC)
#define ARGP_HELP_BUG_ADDR 0x40 /* bug report address */
#define ARGP_HELP_LONG_ONLY 0x80 /* modify output appropriately to
reflect ARGP_LONG_ONLY mode. */
/* These ARGP_HELP flags are only understood by argp_state_help. */
#define ARGP_HELP_EXIT_ERR 0x100 /* Call exit(1) instead of returning. */
#define ARGP_HELP_EXIT_OK 0x200 /* Call exit(0) instead of returning. */
/* The standard thing to do after a program command line parsing error, if an
error message has already been printed. */
#define ARGP_HELP_STD_ERR \
(ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR)
/* The standard thing to do after a program command line parsing error, if no
more specific error message has been printed. */
#define ARGP_HELP_STD_USAGE \
(ARGP_HELP_SHORT_USAGE | ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR)
/* The standard thing to do in response to a --help option. */
#define ARGP_HELP_STD_HELP \
(ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG | ARGP_HELP_EXIT_OK \
| ARGP_HELP_DOC | ARGP_HELP_BUG_ADDR)
/* Output a usage message for ARGP to STREAM. FLAGS are from the set
ARGP_HELP_*. */
extern void argp_help (const struct argp *__restrict __argp,
FILE *__restrict __stream,
unsigned __flags, char *__restrict __name);
extern void __argp_help (const struct argp *__restrict __argp,
FILE *__restrict __stream, unsigned __flags,
char *__name);
/* The following routines are intended to be called from within an argp
parsing routine (thus taking an argp_state structure as the first
argument). They may or may not print an error message and exit, depending
on the flags in STATE -- in any case, the caller should be prepared for
them *not* to exit, and should return an appropriate error after calling
them. [argp_usage & argp_error should probably be called argp_state_...,
but they're used often enough that they should be short] */
/* Output, if appropriate, a usage message for STATE to STREAM. FLAGS are
from the set ARGP_HELP_*. */
extern void argp_state_help (const struct argp_state *__restrict __state,
FILE *__restrict __stream,
unsigned int __flags);
extern void __argp_state_help (const struct argp_state *__restrict __state,
FILE *__restrict __stream,
unsigned int __flags);
/* If appropriate, print the printf string FMT and following args, preceded
by the program name and `:', to stderr, and followed by a `Try ... --help'
message, then exit (1). */
extern void argp_error (const struct argp_state *__restrict __state,
const char *__restrict __fmt, ...)
PRINTF_STYLE(2,3);
extern void __argp_error (const struct argp_state *__restrict __state,
const char *__restrict __fmt, ...)
PRINTF_STYLE(2,3);
/* Similar to the standard gnu error-reporting function error(), but will
respect the ARGP_NO_EXIT and ARGP_NO_ERRS flags in STATE, and will print
to STATE->err_stream. This is useful for argument parsing code that is
shared between program startup (when exiting is desired) and runtime
option parsing (when typically an error code is returned instead). The
difference between this function and argp_error is that the latter is for
*parsing errors*, and the former is for other problems that occur during
parsing but don't reflect a (syntactic) problem with the input. */
extern void argp_failure (const struct argp_state *__restrict __state,
int __status, int __errnum,
const char *__restrict __fmt, ...)
PRINTF_STYLE(4,5);
extern void __argp_failure (const struct argp_state *__restrict __state,
int __status, int __errnum,
const char *__restrict __fmt, ...)
PRINTF_STYLE(4,5);
/* Return the input field for ARGP in the parser corresponding to STATE; used
by the help routines. */
extern void *_argp_input (const struct argp *__restrict __argp,
const struct argp_state *__restrict __state)
__THROW;
extern void *__argp_input (const struct argp *__restrict __argp,
const struct argp_state *__restrict __state)
__THROW;
#if 1
# if 1
# define __argp_usage argp_usage
# define __argp_state_help argp_state_help
# define __option_is_short _option_is_short
# define __option_is_end _option_is_end
# endif
# ifndef ARGP_EI
# define ARGP_EI static __inline
# endif
/* Possibly output the standard usage message for ARGP to stderr and exit. */
ARGP_EI void
__argp_usage (const struct argp_state *__state)
{
__argp_state_help (__state, stderr, ARGP_HELP_STD_USAGE);
}
/* Returns true if the option OPT is a valid short option. */
ARGP_EI int
__NTH (__option_is_short (const struct argp_option *__opt))
{
if (__opt->flags & OPTION_DOC)
return 0;
else
{
int __key = __opt->key;
return __key > 0 && __key <= UCHAR_MAX && isprint (__key);
}
}
/* Returns true if the option OPT is in fact the last (unused) entry in an
options array. */
ARGP_EI int
__NTH (__option_is_end (const struct argp_option *__opt))
{
return !__opt->key && !__opt->name && !__opt->doc && !__opt->group;
}
# if 1
# undef __argp_usage
# undef __argp_state_help
# undef __option_is_short
# undef __option_is_end
# endif
#endif /* Use extern inlines. */
#ifdef __cplusplus
}
#endif
#endif /* argp.h */

View file

@ -0,0 +1,18 @@
/* strndup.c
*
*/
/* Written by Niels Möller <nisse@lysator.liu.se>
*
* This file is hereby placed in the public domain.
*/
#include <string.h>
void *
mempcpy (void *to, const void *from, size_t size)
{
memcpy(to, from, size);
return (char *) to + size;
}

View file

@ -0,0 +1,21 @@
/* strchrnul.c
*
*/
/* Written by Niels Möller <nisse@lysator.liu.se>
*
* This file is hereby placed in the public domain.
*/
/* FIXME: What is this function supposed to do? My guess is that it is
* like strchr, but returns a pointer to the NUL character, not a NULL
* pointer, if the character isn't found. */
char *strchrnul(const char *s, int c)
{
const char *p = s;
while (*p && (*p != c))
p++;
return (char *) p;
}

View file

@ -0,0 +1,31 @@
/* strndup.c
*
*/
/* Written by Niels Möller <nisse@lysator.liu.se>
*
* This file is hereby placed in the public domain.
*/
#include <stdlib.h>
#include <string.h>
char *
strndup (const char *s, size_t size)
{
char *r;
char *end = memchr(s, 0, size);
if (end)
/* Length + 1 */
size = end - s + 1;
r = malloc(size);
if (size)
{
memcpy(r, s, size-1);
r[size-1] = '\0';
}
return r;
}

View file

@ -0,0 +1 @@
See LICENSE.suckless in top level source directory

View file

@ -0,0 +1,6 @@
# Makefile - hhl - /usr/src/world/bin/blkdiscard
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
progname = blkdiscard
include hhl.cprog.ubase.mk

View file

@ -0,0 +1,12 @@
.Dd July 2, 2018
.Dt BLKDISCARD 8
.Os ubase
.Sh NAME
.Nm blkdiscard
.Nd discard sectors on a device
.Sh SYNOPSIS
.Nm
.Ar device
.Sh DESCRIPTION
.Nm
is used to discard all device sectors on solid-state devices.

View file

@ -0,0 +1,48 @@
/* See LICENSE file for copyright and license details. */
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
#include "ubase/util.h"
#define OFFSET_IDX 0
#define LENGTH_IDX 1
#define BLKDISCARD _IO(0x12, 119)
static void
usage(void)
{
eprintf("usage: %s device\n", argv0);
}
int
main(int argc, char *argv[])
{
uint64_t range[2];
int fd;
ARGBEGIN {
default:
usage();
} ARGEND
if (argc != 1)
usage();
fd = open(argv[0], O_RDWR);
if (fd < 0)
eprintf("open: %s:", argv[0]);
range[OFFSET_IDX] = 0;
if (ioctl(fd, BLKGETSIZE64, &range[LENGTH_IDX]) < 0)
eprintf("BLKGETSIZE64: %s:", argv[0]);
if (ioctl(fd, BLKDISCARD, range) < 0)
eprintf("BLKDISCARD: %s:", argv[0]);
close(fd);
return 0;
}

1
world/bin/chgrp/LICENSE Normal file
View file

@ -0,0 +1 @@
See LICENSE.suckless in top level source directory

6
world/bin/chgrp/Makefile Normal file
View file

@ -0,0 +1,6 @@
# Makefile - hhl - /usr/src/world/bin/chgrp
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
progname = chgrp
include hhl.cprog.sbase.mk

View file

@ -0,0 +1,75 @@
/* See LICENSE file for copyright and license details. */
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <unistd.h>
#include "sbase/fs.h"
#include "sbase/util.h"
static int hflag = 0;
static gid_t gid = -1;
static int ret = 0;
static void
chgrp(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r)
{
int flags = 0;
if ((r->maxdepth == 0 && r->follow == 'P') || (r->follow == 'H' && r->depth) || (hflag && !(r->depth)))
flags |= AT_SYMLINK_NOFOLLOW;
if (fchownat(dirfd, name, -1, gid, flags) < 0) {
weprintf("chown %s:", r->path);
ret = 1;
} else if (S_ISDIR(st->st_mode)) {
recurse(dirfd, name, NULL, r);
}
}
static void
usage(void)
{
eprintf("usage: %s [-h] [-R [-H | -L | -P]] group file ...\n", argv0);
}
int
main(int argc, char *argv[])
{
struct group *gr;
struct recursor r = { .fn = chgrp, .maxdepth = 1, .follow = 'P' };
ARGBEGIN {
case 'h':
hflag = 1;
break;
case 'R':
r.maxdepth = 0;
break;
case 'H':
case 'L':
case 'P':
r.follow = ARGC();
break;
default:
usage();
} ARGEND
if (argc < 2)
usage();
errno = 0;
if ((gr = getgrnam(argv[0]))) {
gid = gr->gr_gid;
} else {
if (errno)
eprintf("getgrnam %s:", argv[0]);
gid = estrtonum(argv[0], 0, UINT_MAX);
}
for (argc--, argv++; *argv; argc--, argv++)
recurse(AT_FDCWD, *argv, NULL, &r);
return ret || recurse_status;
}

1
world/bin/chvt/LICENSE Normal file
View file

@ -0,0 +1 @@
See LICENSE.suckless in top level source directory

6
world/bin/chvt/Makefile Normal file
View file

@ -0,0 +1,6 @@
# Makefile - hhl - /usr/src/world/bin/chvt
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
progname = chvt
include hhl.cprog.ubase.mk

15
world/bin/chvt/man/chvt.1 Normal file
View file

@ -0,0 +1,15 @@
.Dd September 7, 2015
.Dt CHVT 1
.Os ubase
.Sh NAME
.Nm chvt
.Nd change foreground virtual terminal
.Sh SYNOPSIS
.Nm
.Ar num
.Sh DESCRIPTION
.Nm
brings
.Pf /dev/tty Ar num
to the foreground. This has the same effect as
.Pf Ctrl-Alt-F Ar num .

67
world/bin/chvt/src/chvt.c Normal file
View file

@ -0,0 +1,67 @@
/* See LICENSE file for copyright and license details. */
#include <sys/ioctl.h>
#include <sys/types.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "ubase/util.h"
#define KDGKBTYPE 0x4B33 /* get keyboard type */
#define VT_ACTIVATE 0x5606 /* make vt active */
#define VT_WAITACTIVE 0x5607 /* wait for vt active */
static char *vt[] = {
"/proc/self/fd/0",
"/dev/console",
"/dev/tty",
"/dev/tty0",
};
static void
usage(void)
{
eprintf("usage: %s num\n", argv0);
}
int
main(int argc, char *argv[])
{
unsigned int n, i;
int fd;
char c;
ARGBEGIN {
default:
usage();
} ARGEND;
if (argc != 1)
usage();
n = estrtonum(argv[0], 0, UINT_MAX);
for (i = 0; i < LEN(vt); i++) {
if ((fd = open(vt[i], O_RDONLY)) < 0)
continue;
c = 0;
if (ioctl(fd, KDGKBTYPE, &c) == 0)
goto found;
if (close(fd) < 0)
eprintf("close %s:", vt[i]);
}
eprintf("no console found\n");
found:
if (ioctl(fd, VT_ACTIVATE, n) == -1)
eprintf("VT_ACTIVATE %u:", n);
if (ioctl(fd, VT_WAITACTIVE, n) == -1)
eprintf("VT_WAITACTIVE %u:", n);
if (close(fd) < 0)
eprintf("close %s:", vt[i]);
return 0;
}

1
world/bin/clear/LICENSE Normal file
View file

@ -0,0 +1 @@
See LICENSE.suckless in top level source directory

6
world/bin/clear/Makefile Normal file
View file

@ -0,0 +1,6 @@
# Makefile - hhl - /usr/src/world/bin/clear
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
progname = clear
include hhl.cprog.ubase.mk

View file

@ -0,0 +1,11 @@
.Dd February 2, 2015
.Dt CLEAR 1
.Os ubase
.Sh NAME
.Nm clear
.Nd clear the screen
.Sh SYNOPSIS
.Nm
.Sh DESCRIPTION
.Nm
clears the screen.

View file

@ -0,0 +1,23 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include "ubase/util.h"
static void
usage(void)
{
eprintf("usage: %s\n", argv0);
}
int
main(int argc, char *argv[])
{
argv0 = argv[0], argc--, argv++;
if (argc)
usage();
printf("\x1b[2J\x1b[H");
return 0;
}

1
world/bin/cols/LICENSE Normal file
View file

@ -0,0 +1 @@
See LICENSE.suckless in top level source directory

6
world/bin/cols/Makefile Normal file
View file

@ -0,0 +1,6 @@
# Makefile - hhl - /usr/src/world/bin/cols
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
progname = cols
include hhl.cprog.sbase.mk

56
world/bin/cols/man/cols.1 Normal file
View file

@ -0,0 +1,56 @@
.Dd 2015-10-08
.Dt COLS 1
.Os sbase
.Sh NAME
.Nm cols
.Nd columnize output
.Sh SYNOPSIS
.Nm
.Op Fl c Ar num
.Op Ar file ...
.Sh DESCRIPTION
.Nm
reads each
.Ar file
in sequence and writes them to stdout, in as many vertical
columns as will fit in
.Ar num
character columns.
If no
.Ar file
is given,
.Nm
reads from stdin.
.Pp
By default
.Nm cols
tries to figure out the width of the output device.
If that fails, it defaults to 65 chars.
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl c Ar num
Set maximum number of character columns to
.Ar num ,
unless input lines exceed this limit.
.El
.Sh ENVIRONMENT
.Bl -tag -width Ds
.It COLUMNS
The width of the output device.
.El
.Sh HISTORY
.Nm
is similar to
.Xr mc 1
in Plan 9. It was renamed to
.Nm
to avoid the name collision with the popular file manager
Midnight Commander.
.Sh CAVEATS
This implementation of
.Nm
assumes that each UTF-8 code point occupies one character cell,
and thus mishandles TAB characters (among others).
.Pp
.Nm
currently mangles files which contain embedded NULs.

98
world/bin/cols/src/cols.c Normal file
View file

@ -0,0 +1,98 @@
/* See LICENSE file for copyright and license details. */
#include <sys/ioctl.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "sbase/text.h"
#include "sbase/util.h"
static void
usage(void)
{
eprintf("usage: %s [-c num] [file ...]\n", argv0);
}
int
main(int argc, char *argv[])
{
FILE *fp;
struct winsize w;
struct linebuf b = EMPTY_LINEBUF;
size_t chars = 65, maxlen = 0, i, j, k, len, cols, rows;
int cflag = 0, ret = 0;
char *p;
ARGBEGIN {
case 'c':
cflag = 1;
chars = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX));
break;
default:
usage();
} ARGEND
if (!cflag) {
if ((p = getenv("COLUMNS")))
chars = estrtonum(p, 1, MIN(LLONG_MAX, SIZE_MAX));
else if (!ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) && w.ws_col > 0)
chars = w.ws_col;
}
if (!argc) {
getlines(stdin, &b);
} else {
for (; *argv; argc--, argv++) {
if (!strcmp(*argv, "-")) {
*argv = "<stdin>";
fp = stdin;
} else if (!(fp = fopen(*argv, "r"))) {
weprintf("fopen %s:", *argv);
ret = 1;
continue;
}
getlines(fp, &b);
if (fp != stdin && fshut(fp, *argv))
ret = 1;
}
}
for (i = 0; i < b.nlines; i++) {
for (j = 0, len = 0; j < b.lines[i].len; j++) {
if (UTF8_POINT(b.lines[i].data[j]))
len++;
}
if (len && b.lines[i].data[b.lines[i].len - 1] == '\n') {
b.lines[i].data[--(b.lines[i].len)] = '\0';
len--;
}
if (len > maxlen)
maxlen = len;
}
for (cols = 1; (cols + 1) * maxlen + cols <= chars; cols++);
rows = b.nlines / cols + (b.nlines % cols > 0);
for (i = 0; i < rows; i++) {
for (j = 0; j < cols && i + j * rows < b.nlines; j++) {
for (k = 0, len = 0; k < b.lines[i + j * rows].len; k++) {
if (UTF8_POINT(b.lines[i + j * rows].data[k]))
len++;
}
fwrite(b.lines[i + j * rows].data, 1,
b.lines[i + j * rows].len, stdout);
if (j < cols - 1)
for (k = len; k < maxlen + 1; k++)
putchar(' ');
}
putchar('\n');
}
ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
return ret;
}

1
world/bin/cron/LICENSE Normal file
View file

@ -0,0 +1 @@
See LICENSE.suckless in top level source directory

6
world/bin/cron/Makefile Normal file
View file

@ -0,0 +1,6 @@
# Makefile - hhl - /usr/src/world/bin/cron
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
progname = cron
include hhl.cprog.sbase.mk

23
world/bin/cron/man/cron.1 Normal file
View file

@ -0,0 +1,23 @@
.Dd 2015-10-08
.Dt CRON 1
.Os sbase
.Sh NAME
.Nm cron
.Nd clock daemon
.Sh SYNOPSIS
.Nm
.Op Fl f Ar file
.Op Fl n
.Sh DESCRIPTION
.Nm
schedules commands to be run at specified dates and times.
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl f Ar file
Use the specified
.Ar file
instead of the default
.Pa /etc/crontab .
.It Fl n
Do not daemonize.
.El

566
world/bin/cron/src/cron.c Normal file
View file

@ -0,0 +1,566 @@
/* See LICENSE file for copyright and license details. */
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <limits.h>
#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#include "sbase/queue.h"
#include "sbase/util.h"
struct field {
enum {
ERROR,
WILDCARD,
NUMBER,
RANGE,
REPEAT,
LIST
} type;
long *val;
int len;
};
struct ctabentry {
struct field min;
struct field hour;
struct field mday;
struct field mon;
struct field wday;
char *cmd;
TAILQ_ENTRY(ctabentry) entry;
};
struct jobentry {
char *cmd;
pid_t pid;
TAILQ_ENTRY(jobentry) entry;
};
static sig_atomic_t chldreap;
static sig_atomic_t reload;
static sig_atomic_t quit;
static TAILQ_HEAD(, ctabentry) ctabhead = TAILQ_HEAD_INITIALIZER(ctabhead);
static TAILQ_HEAD(, jobentry) jobhead = TAILQ_HEAD_INITIALIZER(jobhead);
static char *config = "/etc/crontab";
static char *pidfile = "/var/run/crond.pid";
static int nflag;
static void
loginfo(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (nflag == 0)
vsyslog(LOG_INFO, fmt, ap);
else
vfprintf(stdout, fmt, ap);
fflush(stdout);
va_end(ap);
}
static void
logwarn(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (nflag == 0)
vsyslog(LOG_WARNING, fmt, ap);
else
vfprintf(stderr, fmt, ap);
va_end(ap);
}
static void
logerr(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (nflag == 0)
vsyslog(LOG_ERR, fmt, ap);
else
vfprintf(stderr, fmt, ap);
va_end(ap);
}
static void
runjob(char *cmd)
{
struct jobentry *je;
time_t t;
pid_t pid;
t = time(NULL);
/* If command is already running, skip it */
TAILQ_FOREACH(je, &jobhead, entry) {
if (strcmp(je->cmd, cmd) == 0) {
loginfo("already running %s pid: %d at %s",
je->cmd, je->pid, ctime(&t));
return;
}
}
switch ((pid = fork())) {
case -1:
logerr("error: failed to fork job: %s time: %s",
cmd, ctime(&t));
return;
case 0:
setsid();
loginfo("run: %s pid: %d at %s",
cmd, getpid(), ctime(&t));
execl("/bin/sh", "/bin/sh", "-c", cmd, (char *)NULL);
logerr("error: failed to execute job: %s time: %s",
cmd, ctime(&t));
_exit(1);
default:
je = emalloc(sizeof(*je));
je->cmd = estrdup(cmd);
je->pid = pid;
TAILQ_INSERT_TAIL(&jobhead, je, entry);
}
}
static void
waitjob(void)
{
struct jobentry *je, *tmp;
int status;
time_t t;
pid_t pid;
t = time(NULL);
while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
je = NULL;
TAILQ_FOREACH(tmp, &jobhead, entry) {
if (tmp->pid == pid) {
je = tmp;
break;
}
}
if (je) {
TAILQ_REMOVE(&jobhead, je, entry);
free(je->cmd);
free(je);
}
if (WIFEXITED(status) == 1)
loginfo("complete: pid: %d returned: %d time: %s",
pid, WEXITSTATUS(status), ctime(&t));
else if (WIFSIGNALED(status) == 1)
loginfo("complete: pid: %d terminated by signal: %s time: %s",
pid, strsignal(WTERMSIG(status)), ctime(&t));
else if (WIFSTOPPED(status) == 1)
loginfo("complete: pid: %d stopped by signal: %s time: %s",
pid, strsignal(WSTOPSIG(status)), ctime(&t));
}
}
static int
isleap(int year)
{
if (year % 400 == 0)
return 1;
if (year % 100 == 0)
return 0;
return (year % 4 == 0);
}
static int
daysinmon(int mon, int year)
{
int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if (year < 1900)
year += 1900;
if (isleap(year))
days[1] = 29;
return days[mon];
}
static int
matchentry(struct ctabentry *cte, struct tm *tm)
{
struct {
struct field *f;
int tm;
int len;
} matchtbl[] = {
{ .f = &cte->min, .tm = tm->tm_min, .len = 60 },
{ .f = &cte->hour, .tm = tm->tm_hour, .len = 24 },
{ .f = &cte->mday, .tm = tm->tm_mday, .len = daysinmon(tm->tm_mon, tm->tm_year) },
{ .f = &cte->mon, .tm = tm->tm_mon, .len = 12 },
{ .f = &cte->wday, .tm = tm->tm_wday, .len = 7 },
};
size_t i;
int j;
for (i = 0; i < LEN(matchtbl); i++) {
switch (matchtbl[i].f->type) {
case WILDCARD:
continue;
case NUMBER:
if (matchtbl[i].f->val[0] == matchtbl[i].tm)
continue;
break;
case RANGE:
if (matchtbl[i].f->val[0] <= matchtbl[i].tm)
if (matchtbl[i].f->val[1] >= matchtbl[i].tm)
continue;
break;
case REPEAT:
if (matchtbl[i].tm > 0) {
if (matchtbl[i].tm % matchtbl[i].f->val[0] == 0)
continue;
} else {
if (matchtbl[i].len % matchtbl[i].f->val[0] == 0)
continue;
}
break;
case LIST:
for (j = 0; j < matchtbl[i].f->len; j++)
if (matchtbl[i].f->val[j] == matchtbl[i].tm)
break;
if (j < matchtbl[i].f->len)
continue;
break;
default:
break;
}
break;
}
if (i != LEN(matchtbl))
return 0;
return 1;
}
static int
parsefield(const char *field, long low, long high, struct field *f)
{
int i;
char *e1, *e2;
const char *p;
p = field;
while (isdigit(*p))
p++;
f->type = ERROR;
switch (*p) {
case '*':
if (strcmp(field, "*") == 0) {
f->val = NULL;
f->len = 0;
f->type = WILDCARD;
} else if (strncmp(field, "*/", 2) == 0) {
f->val = emalloc(sizeof(*f->val));
f->len = 1;
errno = 0;
f->val[0] = strtol(field + 2, &e1, 10);
if (e1[0] != '\0' || errno != 0 || f->val[0] == 0)
break;
f->type = REPEAT;
}
break;
case '\0':
f->val = emalloc(sizeof(*f->val));
f->len = 1;
errno = 0;
f->val[0] = strtol(field, &e1, 10);
if (e1[0] != '\0' || errno != 0)
break;
f->type = NUMBER;
break;
case '-':
f->val = emalloc(2 * sizeof(*f->val));
f->len = 2;
errno = 0;
f->val[0] = strtol(field, &e1, 10);
if (e1[0] != '-' || errno != 0)
break;
errno = 0;
f->val[1] = strtol(e1 + 1, &e2, 10);
if (e2[0] != '\0' || errno != 0)
break;
f->type = RANGE;
break;
case ',':
for (i = 1; isdigit(*p) || *p == ','; p++)
if (*p == ',')
i++;
f->val = emalloc(i * sizeof(*f->val));
f->len = i;
errno = 0;
f->val[0] = strtol(field, &e1, 10);
if (f->val[0] < low || f->val[0] > high)
break;
for (i = 1; *e1 == ',' && errno == 0; i++) {
errno = 0;
f->val[i] = strtol(e1 + 1, &e2, 10);
e1 = e2;
}
if (e1[0] != '\0' || errno != 0)
break;
f->type = LIST;
break;
default:
return -1;
}
for (i = 0; i < f->len; i++)
if (f->val[i] < low || f->val[i] > high)
f->type = ERROR;
if (f->type == ERROR) {
free(f->val);
return -1;
}
return 0;
}
static void
freecte(struct ctabentry *cte, int nfields)
{
switch (nfields) {
case 6:
free(cte->cmd);
case 5:
free(cte->wday.val);
case 4:
free(cte->mon.val);
case 3:
free(cte->mday.val);
case 2:
free(cte->hour.val);
case 1:
free(cte->min.val);
}
free(cte);
}
static void
unloadentries(void)
{
struct ctabentry *cte, *tmp;
for (cte = TAILQ_FIRST(&ctabhead); cte; cte = tmp) {
tmp = TAILQ_NEXT(cte, entry);
TAILQ_REMOVE(&ctabhead, cte, entry);
freecte(cte, 6);
}
}
static int
loadentries(void)
{
struct ctabentry *cte;
FILE *fp;
char *line = NULL, *p, *col;
int r = 0, y;
size_t size = 0;
ssize_t len;
struct fieldlimits {
char *name;
long min;
long max;
struct field *f;
} flim[] = {
{ "min", 0, 59, NULL },
{ "hour", 0, 23, NULL },
{ "mday", 1, 31, NULL },
{ "mon", 1, 12, NULL },
{ "wday", 0, 6, NULL }
};
size_t x;
if ((fp = fopen(config, "r")) == NULL) {
logerr("error: can't open %s: %s\n", config, strerror(errno));
return -1;
}
for (y = 0; (len = getline(&line, &size, fp)) != -1; y++) {
p = line;
if (line[0] == '#' || line[0] == '\n' || line[0] == '\0')
continue;
cte = emalloc(sizeof(*cte));
flim[0].f = &cte->min;
flim[1].f = &cte->hour;
flim[2].f = &cte->mday;
flim[3].f = &cte->mon;
flim[4].f = &cte->wday;
for (x = 0; x < LEN(flim); x++) {
do
col = strsep(&p, "\t\n ");
while (col && col[0] == '\0');
if (!col || parsefield(col, flim[x].min, flim[x].max, flim[x].f) < 0) {
logerr("error: failed to parse `%s' field on line %d\n",
flim[x].name, y + 1);
freecte(cte, x);
r = -1;
break;
}
}
if (r == -1)
break;
col = strsep(&p, "\n");
if (col)
while (col[0] == '\t' || col[0] == ' ')
col++;
if (!col || col[0] == '\0') {
logerr("error: missing `cmd' field on line %d\n",
y + 1);
freecte(cte, 5);
r = -1;
break;
}
cte->cmd = estrdup(col);
TAILQ_INSERT_TAIL(&ctabhead, cte, entry);
}
if (r < 0)
unloadentries();
free(line);
fclose(fp);
return r;
}
static void
reloadentries(void)
{
unloadentries();
if (loadentries() < 0)
logwarn("warning: discarding old crontab entries\n");
}
static void
sighandler(int sig)
{
switch (sig) {
case SIGCHLD:
chldreap = 1;
break;
case SIGHUP:
reload = 1;
break;
case SIGTERM:
quit = 1;
break;
}
}
static void
usage(void)
{
eprintf("usage: %s [-f file] [-n]\n", argv0);
}
int
main(int argc, char *argv[])
{
FILE *fp;
struct ctabentry *cte;
time_t t;
struct tm *tm;
struct sigaction sa;
ARGBEGIN {
case 'n':
nflag = 1;
break;
case 'f':
config = EARGF(usage());
break;
default:
usage();
} ARGEND
if (argc > 0)
usage();
if (nflag == 0) {
openlog(argv[0], LOG_CONS | LOG_PID, LOG_CRON);
if (daemon(1, 0) < 0) {
logerr("error: failed to daemonize %s\n", strerror(errno));
return 1;
}
if ((fp = fopen(pidfile, "w"))) {
fprintf(fp, "%d\n", getpid());
fclose(fp);
}
}
sa.sa_handler = sighandler;
sigfillset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sigaction(SIGCHLD, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
loadentries();
while (1) {
t = time(NULL);
sleep(60 - t % 60);
if (quit == 1) {
if (nflag == 0)
unlink(pidfile);
unloadentries();
/* Don't wait or kill forked processes, just exit */
break;
}
if (reload == 1 || chldreap == 1) {
if (reload == 1) {
reloadentries();
reload = 0;
}
if (chldreap == 1) {
waitjob();
chldreap = 0;
}
continue;
}
TAILQ_FOREACH(cte, &ctabhead, entry) {
t = time(NULL);
tm = localtime(&t);
if (matchentry(cte, tm) == 1)
runjob(cte->cmd);
}
}
if (nflag == 0)
closelog();
return 0;
}

View file

@ -0,0 +1 @@
See LICENSE.suckless in top level source directory

View file

@ -0,0 +1,6 @@
# Makefile - hhl - /usr/src/world/bin/ctrlaltdel
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
progname = ctrlaltdel
include hhl.cprog.ubase.mk

View file

@ -0,0 +1,31 @@
.Dd September 7, 2015
.Dt CTRLALTDEL 8
.Os ubase
.Sh NAME
.Nm ctrlaltdel
.Nd toggle Ctrl-Alt-Del behaviour
.Sh SYNOPSIS
.Nm
.Fl h | s
.Sh DESCRIPTION
.Nm
toggles the function of Ctrl-Alt-Del based on the two choices given in
.Pa linux/kernel/sys.c :
.Bl -tag -width Ds
.It hard reset
reboot the computer immediately without calling
.Xr sync 2 .
.It soft reset
send SIGINT to
.Xr init 8 .
.El
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl h
Set to hard reset.
.It Fl s
Set to soft reset.
.El
.Sh SEE ALSO
.Xr sync 2 ,
.Xr init 8

View file

@ -0,0 +1,42 @@
/* See LICENSE file for copyright and license details. */
#include <sys/syscall.h>
#include <stdio.h>
#include <unistd.h>
#include "ubase/reboot.h"
#include "ubase/util.h"
static void
usage(void)
{
eprintf("usage: %s -h | -s\n", argv0);
}
int
main(int argc, char *argv[])
{
int hflag = 0, sflag = 0, cmd;
ARGBEGIN {
case 'h':
hflag = 1;
break;
case 's':
sflag = 1;
break;
default:
usage();
} ARGEND;
if (argc || !(hflag ^ sflag))
usage();
cmd = hflag ? LINUX_REBOOT_CMD_CAD_ON : LINUX_REBOOT_CMD_CAD_OFF;
if (syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
cmd, NULL) < 0)
eprintf("reboot:");
return 0;
}

View file

@ -0,0 +1 @@
See LICENSE.suckless in top level source directory

View file

@ -0,0 +1,6 @@
# Makefile - hhl - /usr/src/world/bin/fallocate
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
progname = fallocate
include hhl.cprog.ubase.mk

View file

@ -0,0 +1,33 @@
.Dd September 12, 2015
.Dt FALLOCATE 1
.Os ubase
.Sh NAME
.Nm fallocate
.Nd preallocate files
.Sh SYNOPSIS
.Nm
.Op Fl o Ar num
.Fl l Ar num
.Ar file ...
.Sh DESCRIPTION
.Nm
if necessary creates and preallocates each
.Ar file
without truncation.
.sp
Given the filesystem supports
.Xr fallocate 2 ,
it is a very fast method of preallocation.
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl l Ar num
Preallocate
.Ar num
bytes.
.It Fl o Ar num
Offset allocation by
.Ar num
bytes.
.El
.Sh SEE ALSO
.Xr fallocate 2

View file

@ -0,0 +1,55 @@
/* See LICENSE file for copyright and license details. */
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "ubase/util.h"
static void
usage(void)
{
eprintf("usage: %s [-o num] -l num file ...\n", argv0);
}
int
main(int argc, char *argv[])
{
int fd, ret = 0;
off_t size = 0, offset = 0;
ARGBEGIN {
case 'l':
size = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX));
break;
case 'o':
offset = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
break;
default:
usage();
} ARGEND;
if (!argc || !size)
usage();
for (; *argv; argc--, argv++) {
if ((fd = open(*argv, O_RDWR | O_CREAT, 0644)) < 0) {
weprintf("open %s:", *argv);
ret = 1;
} else if (posix_fallocate(fd, offset, size) < 0) {
weprintf("posix_fallocate %s:", *argv);
ret = 1;
}
if (fd >= 0 && close(fd) < 0) {
weprintf("close %s:", *argv);
ret = 1;
}
}
return ret;
}

View file

@ -0,0 +1 @@
See LICENSE.suckless in top level source directory

View file

@ -0,0 +1,6 @@
# Makefile - hhl - /usr/src/world/bin/freeramdisk
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
progname = freeramdisk
include hhl.cprog.ubase.mk

View file

@ -0,0 +1,13 @@
.Dd February 2, 2015
.Dt FREERAMDISK 8
.Os ubase
.Sh NAME
.Nm freeramdisk
.Nd free memory used by the loadlin ramdisk
.Sh SYNOPSIS
.Nm
.Sh DESCRIPTION
.Nm
frees the memory that is used by the ramdisk. It uses the
.Pa /dev/ram
device node.

View file

@ -0,0 +1,39 @@
/* See LICENSE file for copyright and license details. */
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "ubase/util.h"
static void
usage(void)
{
eprintf("usage: %s\n", argv0);
}
int
main(int argc, char *argv[])
{
char *dev = "/dev/ram";
int fd;
ARGBEGIN {
default:
usage();
} ARGEND;
if (argc != 0)
usage();
if ((fd = open(dev, O_RDWR)) < 0)
eprintf("open: %s:", dev);
if (ioctl(fd, BLKFLSBUF, dev) < 0)
eprintf("BLKFLSBUF %s:", dev);
close(fd);
return 0;
}

View file

@ -0,0 +1 @@
See LICENSE.suckless in top level source directory

View file

@ -0,0 +1,6 @@
# Makefile - hhl - /usr/src/world/bin/fsfreeze
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
progname = fsfreeze
include hhl.cprog.ubase.mk

View file

@ -0,0 +1,33 @@
.Dd March 26, 2016
.Dt FSFREEZE 8
.Os ubase
.Sh NAME
.Nm fsfreeze
.Nd suspend access to a filesystem
.Sh SYNOPSIS
.Nm
.Po Fl f | Fl u Pc
.Ar mountpoint
.Sh DESCRIPTION
.Nm
suspends and resumes access to a filesystem.
.Nm
is intended to be used with hardware RAID devices that support the creation
of snapshots.
The
.Ar mountpoint
argument is the pathname of the directory where the filesystem is mounted.
The filesystem must be mounted to be frozen.
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl f
Freeze the filesystem mounted at
.Ar mountpoint .
.It Fl u
Unfreeze the filesystem mounted at
.Ar mountpoint .
.El
.Sh SEE ALSO
.Xr mount 8
.Sh BUGS
Only works for ext3/4, reiserfs, jfs and xfs.

View file

@ -0,0 +1,54 @@
/* See LICENSE file for copyright and license details. */
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "ubase/util.h"
#define FIFREEZE _IOWR('X', 119, int) /* Freeze */
#define FITHAW _IOWR('X', 120, int) /* Thaw */
static void
usage(void)
{
eprintf("usage: %s (-f | -u) mountpoint\n", argv0);
}
int
main(int argc, char *argv[])
{
int fflag = 0;
int uflag = 0;
long p = 1;
int fd;
ARGBEGIN {
case 'f':
fflag = 1;
break;
case 'u':
uflag = 1;
break;
default:
usage();
} ARGEND;
if (argc != 1)
usage();
if ((fflag ^ uflag) == 0)
usage();
fd = open(argv[0], O_RDONLY);
if (fd < 0)
eprintf("open: %s:", argv[0]);
if (ioctl(fd, fflag == 1 ? FIFREEZE : FITHAW, &p) < 0)
eprintf("%s %s:", fflag == 1 ? "FIFREEZE" : "FITHAW", argv[0]);
close(fd);
return 0;
}

1
world/bin/getty/LICENSE Normal file
View file

@ -0,0 +1 @@
See LICENSE.suckless in top level source directory

6
world/bin/getty/Makefile Normal file
View file

@ -0,0 +1,6 @@
# Makefile - hhl - /usr/src/world/bin/getty
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
progname = getty
include hhl.cprog.ubase.mk

View file

@ -0,0 +1,22 @@
.Dd February 2, 2015
.Dt GETTY 8
.Os ubase
.Sh NAME
.Nm getty
.Nd suckless linux getty
.Sh SYNOPSIS
.Nm
.Op Ar tty Op Ar term Op Ar cmd Op Ar args...
.Sh DESCRIPTION
.Nm
opens a tty device, prompts for a login name and by default
invokes the /bin/login program. You can start another program instead of
/bin/login via
.Ar cmd
with
.Ar args .
The hostname is printed in the login name prompt as well. The
.Ar tty
should be specified using an absolute path.
.Sh SEE ALSO
.Xr login 1

140
world/bin/getty/src/getty.c Normal file
View file

@ -0,0 +1,140 @@
/* See LICENSE file for copyright and license details. */
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <utmp.h>
#include "ubase/config.h"
#include "ubase/util.h"
static char *tty = "/dev/tty1";
static char *defaultterm = "linux";
static void
usage(void)
{
eprintf("usage: %s [tty] [term] [cmd] [args...]\n", argv0);
}
int
main(int argc, char *argv[])
{
char term[128], logname[LOGIN_NAME_MAX], c;
char hostname[HOST_NAME_MAX + 1];
struct utmp usr;
struct sigaction sa;
FILE *fp;
int fd;
unsigned int i = 0;
ssize_t n;
long pos;
ARGBEGIN {
default:
usage();
} ARGEND;
strlcpy(term, defaultterm, sizeof(term));
if (argc > 0) {
tty = argv[0];
if (argc > 1)
strlcpy(term, argv[1], sizeof(term));
}
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(SIGHUP, &sa, NULL);
setenv("TERM", term, 1);
setsid();
fd = open(tty, O_RDWR);
if (fd < 0)
eprintf("open %s:", tty);
if (isatty(fd) == 0)
eprintf("%s is not a tty\n", tty);
/* steal the controlling terminal if necessary */
if (ioctl(fd, TIOCSCTTY, (void *)1) != 0)
weprintf("TIOCSCTTY: could not set controlling tty\n");
vhangup();
close(fd);
fd = open(tty, O_RDWR);
if (fd < 0)
eprintf("open %s:", tty);
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
if (fchown(fd, 0, 0) < 0)
weprintf("fchown %s:", tty);
if (fchmod(fd, 0600) < 0)
weprintf("fchmod %s:", tty);
if (fd > 2)
close(fd);
sa.sa_handler = SIG_DFL;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(SIGHUP, &sa, NULL);
/* Clear all utmp entries for this tty */
fp = fopen(UTMP_PATH, "r+");
if (fp) {
do {
pos = ftell(fp);
if (fread(&usr, sizeof(usr), 1, fp) != 1)
break;
if (usr.ut_line[0] == '\0')
continue;
if (strcmp(usr.ut_line, tty) != 0)
continue;
memset(&usr, 0, sizeof(usr));
fseek(fp, pos, SEEK_SET);
if (fwrite(&usr, sizeof(usr), 1, fp) != 1)
break;
} while (1);
if (ferror(fp))
weprintf("%s: I/O error:", UTMP_PATH);
fclose(fp);
}
if (argc > 2)
return execvp(argv[2], argv + 2);
if (gethostname(hostname, sizeof(hostname)) == 0)
printf("%s ", hostname);
printf("login: ");
fflush(stdout);
/* Flush pending input */
ioctl(0, TCFLSH, (void *)0);
memset(logname, 0, sizeof(logname));
while (1) {
n = read(0, &c, 1);
if (n < 0)
eprintf("read:");
if (n == 0)
return 1;
if (i >= sizeof(logname) - 1)
eprintf("login name too long\n");
if (c == '\n' || c == '\r')
break;
logname[i++] = c;
}
if (logname[0] == '-')
eprintf("login name cannot start with '-'\n");
if (logname[0] == '\0')
return 1;
return execlp("/bin/login", "login", "-p", logname, NULL);
}

1
world/bin/halt/LICENSE Normal file
View file

@ -0,0 +1 @@
See LICENSE.suckless in top level source directory

6
world/bin/halt/Makefile Normal file
View file

@ -0,0 +1,6 @@
# Makefile - hhl - /usr/src/world/bin/halt
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
progname = halt
include hhl.cprog.ubase.mk

21
world/bin/halt/man/halt.8 Normal file
View file

@ -0,0 +1,21 @@
.Dd February 2, 2015
.Dt HALT 8
.Os ubase
.Sh NAME
.Nm halt
.Nd power-off or reboot the machine
.Sh SYNOPSIS
.Nm
.Op Fl pr
.Sh DESCRIPTION
.Nm
can be used to power-off or reboot the machine.
This is a low-level tool and should not be used directly or data-loss
can happen if the filesystems are not properly unmounted first.
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl p
Power-off the machine.
.It Fl r
Reboot the machine.
.El

51
world/bin/halt/src/halt.c Normal file
View file

@ -0,0 +1,51 @@
/* See LICENSE file for copyright and license details. */
#include <sys/syscall.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "ubase/reboot.h"
#include "ubase/util.h"
static void
usage(void)
{
eprintf("usage: %s [-pr]\n", argv0);
}
int
main(int argc, char *argv[])
{
int pflag = 0, rflag = 0;
int cmd = LINUX_REBOOT_CMD_HALT;
ARGBEGIN {
case 'p':
pflag = 1;
break;
case 'r':
rflag = 1;
break;
default:
usage();
} ARGEND;
if (argc > 0)
usage();
sync();
if (pflag && rflag)
usage();
if (pflag)
cmd = LINUX_REBOOT_CMD_POWER_OFF;
if (rflag)
cmd = LINUX_REBOOT_CMD_RESTART;
if (syscall(__NR_reboot, LINUX_REBOOT_MAGIC1,
LINUX_REBOOT_MAGIC2, cmd, NULL) < 0)
eprintf("reboot:");
return 0;
}

View file

@ -0,0 +1 @@
See LICENSE.suckless in top level source directory

View file

@ -0,0 +1,6 @@
# Makefile - hhl - /usr/src/world/bin/hwclock
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
progname = hwclock
include hhl.cprog.ubase.mk

View file

@ -0,0 +1,31 @@
.Dd February 2, 2015
.Dt HWCLOCK 8
.Os ubase
.Sh NAME
.Nm hwclock
.Nd query or set the hardware clock
.Sh SYNOPSIS
.Nm
.Op Fl r | Fl s | Fl w
.Op Fl u
.Op Ar dev
.Sh DESCRIPTION
.Nm
is a tool for accessing the hardware clock. You can display the current time,
set the hardware clock from the System Time, or set the System Time from the
hardware clock. It currently only works with UTC. You can use
.Ar dev
to specify the RTC device node absolute path. By default
it will use
.Pa /dev/rtc .
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl r
Read the hardware clock and print the time on stdout.
.It Fl s
Set the system time from the hardware clock.
.It Fl u
Use UTC. This is the default option.
.It Fl w
Set the hardware clock to the system time.
.El

View file

@ -0,0 +1,159 @@
/* See LICENSE file for copyright and license details. */
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "ubase/rtc.h"
#include "ubase/util.h"
static void
readrtctm(struct tm *tm, int fd)
{
struct rtc_time rt;
memset(&rt, 0, sizeof(rt));
if (ioctl(fd, RTC_RD_TIME, &rt) < 0)
eprintf("RTC_RD_TIME:");
tm->tm_sec = rt.tm_sec;
tm->tm_min = rt.tm_min;
tm->tm_hour = rt.tm_hour;
tm->tm_mday = rt.tm_mday;
tm->tm_mon = rt.tm_mon;
tm->tm_year = rt.tm_year;
tm->tm_wday = rt.tm_wday;
tm->tm_yday = rt.tm_yday;
tm->tm_isdst = rt.tm_isdst;
}
static void
writertctm(struct tm *tm, int fd)
{
struct rtc_time rt;
rt.tm_sec = tm->tm_sec;
rt.tm_min = tm->tm_min;
rt.tm_hour = tm->tm_hour;
rt.tm_mday = tm->tm_mday;
rt.tm_mon = tm->tm_mon;
rt.tm_year = tm->tm_year;
rt.tm_wday = tm->tm_wday;
rt.tm_yday = tm->tm_yday;
rt.tm_isdst = tm->tm_isdst;
if (ioctl(fd, RTC_SET_TIME, &rt) < 0)
eprintf("RTC_SET_TIME:");
}
static void
show(char *dev)
{
struct tm tm;
time_t t;
int fd;
fd = open(dev, O_RDONLY);
if (fd < 0)
eprintf("open %s:", dev);
readrtctm(&tm, fd);
t = mktime(&tm);
printf("%s", asctime(localtime(&t)));
close(fd);
}
static void
hctosys(char *dev)
{
struct timeval tv;
struct tm tm;
int r;
int fd;
fd = open(dev, O_RDONLY);
if (fd < 0)
eprintf("open %s:", dev);
readrtctm(&tm, fd);
tv.tv_sec = mktime(&tm);
tv.tv_usec = 0;
r = settimeofday(&tv, NULL);
if (r < 0)
eprintf("settimeofday:");
close(fd);
}
static void
systohc(char *dev)
{
struct timeval tv;
struct tm *tm;
time_t t;
int fd;
fd = open(dev, O_WRONLY);
if (fd < 0)
eprintf("open %s:", dev);
gettimeofday(&tv, NULL);
t = tv.tv_sec;
tm = gmtime(&t);
weprintf("warning: assuming UTC for systohc\n");
writertctm(tm, fd);
close(fd);
}
static void
usage(void)
{
eprintf("usage: %s [-rsw] [-u] [dev]\n", argv0);
}
int
main(int argc, char *argv[])
{
char *dev = "/dev/rtc";
int rflag = 0;
int sflag = 0;
int wflag = 0;
ARGBEGIN {
case 'r':
rflag = 1;
break;
case 's':
sflag = 1;
break;
case 'w':
wflag = 1;
break;
case 'u':
break;
default:
usage();
} ARGEND;
if (argc > 1)
usage();
else if (argc == 1)
dev = argv[0];
if ((rflag ^ sflag ^ wflag) == 0)
eprintf("missing or incompatible function\n");
/* Only UTC support at the moment */
setenv("TZ", "UTC0", 1);
tzset();
if (rflag == 1)
show(dev);
else if (sflag == 1)
hctosys(dev);
else if (wflag == 1)
systohc(dev);
return 0;
}

1
world/bin/insmod/LICENSE Normal file
View file

@ -0,0 +1 @@
See LICENSE.suckless in top level source directory

View file

@ -0,0 +1,6 @@
# Makefile - hhl - /usr/src/world/bin/insmod
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
progname = insmod
include hhl.cprog.ubase.mk

View file

@ -0,0 +1,18 @@
.Dd February 2, 2015
.Dt INSMOD 8
.Os ubase
.Sh NAME
.Nm insmod
.Nd insert a module into the Linux kernel
.Sh SYNOPSIS
.Nm
.Ar filename
.Op Ar args...
.Sh DESCRIPTION
.Nm
inserts the module specified by
.Ar filename
into the kernel. It does not handle module dependencies.
.Sh SEE ALSO
.Xr lsmod 8 ,
.Xr rmmod 8

View file

@ -0,0 +1,69 @@
/* See LICENSE file for copyright and license details. */
#include <sys/stat.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ubase/util.h"
static void
usage(void)
{
eprintf("usage: %s filename [args...]\n", argv0);
}
int
main(int argc, char *argv[])
{
char *buf = NULL, *opts = NULL;
size_t blen, plen = 0;
int i, fd;
ssize_t n;
struct stat sb;
ARGBEGIN {
default:
usage();
} ARGEND;
if (argc < 1)
usage();
fd = open(argv[0], O_RDONLY);
if (fd < 0)
eprintf("open %s:", argv[0]);
if (fstat(fd, &sb) < 0)
eprintf("stat %s:", argv[0]);
blen = sb.st_size;
buf = emalloc(blen);
n = read(fd, buf, blen);
if (n < 0 || (size_t)n != blen)
eprintf("read:");
argc--;
argv++;
for (i = 0; i < argc; i++)
plen += strlen(argv[i]);
if (plen > 0) {
plen += argc;
opts = ecalloc(1, plen);
for (i = 0; i < argc; i++) {
strcat(opts, argv[i]);
if (i + 1 < argc)
strcat(opts, " ");
}
}
if (syscall(__NR_init_module, buf, blen, !opts ? "" : opts) < 0)
eprintf("init_module:");
free(opts);
free(buf);
return 0;
}

1
world/bin/kill/LICENSE Normal file
View file

@ -0,0 +1 @@
See LICENSE.suckless in top level source directory

6
world/bin/kill/Makefile Normal file
View file

@ -0,0 +1,6 @@
# Makefile - hhl - /usr/src/world/bin/kill
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
progname = kill
include hhl.cprog.sbase.mk

47
world/bin/kill/man/kill.1 Normal file
View file

@ -0,0 +1,47 @@
.Dd 2015-10-08
.Dt KILL 1
.Os sbase
.Sh NAME
.Nm kill
.Nd signal processes
.Sh SYNOPSIS
.Nm
.Op Fl s Ar signame | Fl num | Fl signame
.Ar pid ...
.Nm
.Fl l Op Ar num
.Sh DESCRIPTION
.Nm
signals TERM to each process or process group specified by
.Ar pid .
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl l Op Ar num
List all available signals or the signal name of
.Ar num .
.It Fl s Ar signame | Fl num | Fl signame
Send signal corresponding to
.Ar signame
|
.Ar num .
The default is TERM.
.El
.Sh SEE ALSO
.Xr kill 2 ,
.Xr signal 7
.Sh STANDARDS
The
.Nm
utility is compliant with the
.St -p1003.1-2013
specification.
.Pp
The
.Fl Ar signame
and
.Fl Ar num
syntax is marked by
.St -p1003.1-2013
as an
X/OPEN System Interfaces
option.

130
world/bin/kill/src/kill.c Normal file
View file

@ -0,0 +1,130 @@
/* See LICENSE file for copyright and license details. */
#include <sys/wait.h>
#include <ctype.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include "sbase/util.h"
struct {
const char *name;
const int sig;
} sigs[] = {
{ "0", 0 },
#define SIG(n) { #n, SIG##n }
SIG(ABRT), SIG(ALRM), SIG(BUS), SIG(CHLD), SIG(CONT), SIG(FPE), SIG(HUP),
SIG(ILL), SIG(INT), SIG(KILL), SIG(PIPE), SIG(QUIT), SIG(SEGV), SIG(STOP),
SIG(TERM), SIG(TSTP), SIG(TTIN), SIG(TTOU), SIG(USR1), SIG(USR2), SIG(URG),
#undef SIG
};
const char *
sig2name(const int sig)
{
size_t i;
for (i = 0; i < LEN(sigs); i++)
if (sigs[i].sig == sig)
return sigs[i].name;
eprintf("%d: bad signal number\n", sig);
return NULL; /* not reached */
}
int
name2sig(const char *name)
{
size_t i;
for (i = 0; i < LEN(sigs); i++)
if (!strcasecmp(sigs[i].name, name))
return sigs[i].sig;
eprintf("%s: bad signal name\n", name);
return -1; /* not reached */
}
static void
usage(void)
{
eprintf("usage: %s [-s signame | -num | -signame] pid ...\n"
" %s -l [num]\n", argv0, argv0);
}
int
main(int argc, char *argv[])
{
pid_t pid;
size_t i;
int ret = 0, sig = SIGTERM;
argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0;
if (!argc)
usage();
if ((*argv)[0] == '-') {
switch ((*argv)[1]) {
case 'l':
if ((*argv)[2])
goto longopt;
argc--, argv++;
if (!argc) {
for (i = 0; i < LEN(sigs); i++)
puts(sigs[i].name);
} else if (argc == 1) {
sig = estrtonum(*argv, 0, INT_MAX);
if (sig > 128)
sig = WTERMSIG(sig);
puts(sig2name(sig));
} else {
usage();
}
return fshut(stdout, "<stdout>");
case 's':
if ((*argv)[2])
goto longopt;
argc--, argv++;
if (!argc)
usage();
sig = name2sig(*argv);
argc--, argv++;
break;
case '-':
if ((*argv)[2])
goto longopt;
argc--, argv++;
break;
default:
longopt:
/* XSI-extensions -argnum and -argname*/
if (isdigit((*argv)[1])) {
sig = estrtonum((*argv) + 1, 0, INT_MAX);
sig2name(sig);
} else {
sig = name2sig((*argv) + 1);
}
argc--, argv++;
}
}
if (argc && !strcmp(*argv, "--"))
argc--, argv++;
if (!argc)
usage();
for (; *argv; argc--, argv++) {
pid = estrtonum(*argv, INT_MIN, INT_MAX);
if (kill(pid, sig) < 0) {
weprintf("kill %d:", pid);
ret = 1;
}
}
return ret;
}

View file

@ -0,0 +1 @@
See LICENSE.suckless in top level source directory

View file

@ -0,0 +1,6 @@
# Makefile - hhl - /usr/src/world/bin/killall5
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
progname = killall5
include hhl.cprog.ubase.mk

View file

@ -0,0 +1,31 @@
.Dd February 2, 2015
.Dt KILLALL5 8
.Os ubase
.Sh NAME
.Nm killall5
.Nd send a signal to all processes
.Sh SYNOPSIS
.Nm
.Op Fl o Ar pid1,pid2,...,pidN
.Op Fl s Ar signal
.Sh DESCRIPTION
.Nm
is an implementation of the SystemV
.Xr killall 8
command. It sends a signal to all processes except kernel threads and the
processes in its own session. It is primarily used by the system's init
scripts.
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl o
Tell
.Nm
to omit processes with that process id.
.It Fl s Ar signal
Send
.Ar signal
instead of the default SIGTERM.
.El
.Sh SEE ALSO
.Xr halt 8 ,
.Xr reboot 8

View file

@ -0,0 +1,111 @@
/* See LICENSE file for copyright and license details. */
#include <dirent.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ubase/proc.h"
#include "ubase/queue.h"
#include "ubase/util.h"
struct {
const char *name;
int sig;
} sigs[] = {
#define SIG(n) { #n, SIG##n }
SIG(ABRT), SIG(ALRM), SIG(BUS), SIG(CHLD), SIG(CONT), SIG(FPE), SIG(HUP),
SIG(ILL), SIG(INT), SIG(KILL), SIG(PIPE), SIG(QUIT), SIG(SEGV), SIG(STOP),
SIG(TERM), SIG(TSTP), SIG(TTIN), SIG(TTOU), SIG(USR1), SIG(USR2), SIG(URG),
#undef SIG
};
struct pidentry {
pid_t pid;
SLIST_ENTRY(pidentry) entry;
};
static SLIST_HEAD(, pidentry) omitpid_head;
static void
usage(void)
{
eprintf("usage: %s [-o pid1,pid2,..,pidN] [-s signal]\n", argv0);
}
int
main(int argc, char *argv[])
{
struct pidentry *pe;
struct dirent *entry;
DIR *dp;
char *p, *arg = NULL;
char *end, *v;
int oflag = 0;
int sig = SIGTERM;
pid_t pid;
size_t i;
ARGBEGIN {
case 's':
v = EARGF(usage());
sig = strtol(v, &end, 0);
if (*end == '\0')
break;
for (i = 0; i < LEN(sigs); i++) {
if (strcasecmp(v, sigs[i].name) == 0) {
sig = sigs[i].sig;
break;
}
}
if (i == LEN(sigs))
eprintf("%s: unknown signal\n", v);
break;
case 'o':
oflag = 1;
arg = EARGF(usage());
break;
default:
usage();
} ARGEND;
SLIST_INIT(&omitpid_head);
if (oflag) {
for (p = strtok(arg, ","); p; p = strtok(NULL, ",")) {
pe = emalloc(sizeof(*pe));
pe->pid = estrtol(p, 10);
SLIST_INSERT_HEAD(&omitpid_head, pe, entry);
}
}
if (sig != SIGSTOP && sig != SIGCONT)
kill(-1, SIGSTOP);
if (!(dp = opendir("/proc")))
eprintf("opendir /proc:");
while ((entry = readdir(dp))) {
if (pidfile(entry->d_name) == 0)
continue;
pid = estrtol(entry->d_name, 10);
if (pid == 1 || pid == getpid() ||
getsid(pid) == getsid(0) || getsid(pid) == 0)
continue;
if (oflag == 1) {
SLIST_FOREACH(pe, &omitpid_head, entry)
if (pe->pid == pid)
break;
if (pe)
continue;
}
kill(pid, sig);
}
closedir(dp);
if (sig != SIGSTOP && sig != SIGCONT)
kill(-1, SIGCONT);
return 0;
}

View file

@ -0,0 +1 @@
See LICENSE.suckless in top level source directory

View file

@ -0,0 +1,6 @@
# Makefile - hhl - /usr/src/world/bin/lastlog
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
progname = lastlog
include hhl.cprog.ubase.mk

View file

@ -0,0 +1,18 @@
.Dd February 2, 2015
.Dt LASTLOG 8
.Os ubase
.Sh NAME
.Nm lastlog
.Nd show last login of users
.Sh SYNOPSIS
.Nm
.Op Ar user...
.Sh DESCRIPTION
.Nm
shows the time, tty and host (if it was a remote connection) of the last
login of the users. If one or more
.Ar user
names are passed as a parameter then information about the last login of these
users are shown, otherwise the users in
.Pa /etc/passwd
will be used and shown in order of appearance.

View file

@ -0,0 +1,78 @@
/* See LICENSE file for copyright and license details. */
#include <errno.h>
#include <paths.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <utmp.h>
#include "ubase/text.h"
#include "ubase/util.h"
#define PASSWD "/etc/passwd"
static FILE *last;
static void
lastlog(char *user)
{
struct passwd *pwd;
struct lastlog ll;
time_t lltime;
errno = 0;
if ((pwd = getpwnam(user)) == NULL) {
if (errno)
weprintf("getpwnam %s:", user);
else
weprintf("unknown user: %s\n", user);
return;
}
fseek(last, pwd->pw_uid * sizeof(struct lastlog), 0);
fread(&ll, sizeof(struct lastlog), 1, last);
if (ferror(last))
eprintf("%s: read error:", _PATH_LASTLOG);
/* on glibc `ll_time' can be an int32_t with compat32
* avoid compiler warning when calling ctime() */
lltime = ll.ll_time;
printf("%-8.8s %-8.8s %-16.16s %s",
user, ll.ll_line, ll.ll_host, ctime(&lltime));
}
int
main(int argc, char **argv)
{
FILE *fp;
char *line = NULL, *p;
size_t sz = 0;
if ((last = fopen(_PATH_LASTLOG, "r")) == NULL)
eprintf("fopen %s:", _PATH_LASTLOG);
if (argc > 1) {
while (*++argv)
lastlog(*argv);
} else {
if ((fp = fopen(PASSWD, "r")) == NULL)
eprintf("fopen %s:", PASSWD);
while (agetline(&line, &sz, fp) != -1) {
if ((p = strchr(line, ':')) == NULL)
eprintf("invalid passwd entry\n");
*p = '\0';
lastlog(line);
}
if (fclose(fp))
eprintf("fclose %s:", PASSWD);
free(line);
}
if (fclose(last))
eprintf("fclose %s:", _PATH_LASTLOG);
return 0;
}

1
world/bin/lsmod/LICENSE Normal file
View file

@ -0,0 +1 @@
See LICENSE.suckless in top level source directory

6
world/bin/lsmod/Makefile Normal file
View file

@ -0,0 +1,6 @@
# Makefile - hhl - /usr/src/world/bin/lsmod
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
progname = lsmod
include hhl.cprog.ubase.mk

View file

@ -0,0 +1,13 @@
.Dd February 2, 2015
.Dt LSMOD 8
.Os ubase
.Sh NAME
.Nm lsmod
.Nd list loaded kernel modules
.Sh SYNOPSIS
.Nm
.Sh DESCRIPTION
.Nm
parses
.Pa /proc/modules
and shows the loadable kernel modules that are currently loaded.

View file

@ -0,0 +1,67 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ubase/text.h"
#include "ubase/util.h"
static void parse_modline(char *buf, char **name, char **size,
char **refcount, char **users);
static void
usage(void)
{
eprintf("usage: %s\n", argv0);
}
int
main(int argc, char *argv[])
{
const char *modfile = "/proc/modules";
FILE *fp;
char *buf = NULL;
char *name, *size, *refcount, *users;
size_t bufsize = 0;
size_t len;
ARGBEGIN {
default:
usage();
} ARGEND;
if (argc > 0)
usage();
fp = fopen(modfile, "r");
if (!fp)
eprintf("fopen %s:", modfile);
printf("%-23s Size Used by\n", "Module");
while (agetline(&buf, &bufsize, fp) != -1) {
parse_modline(buf, &name, &size, &refcount, &users);
if (!name || !size || !refcount || !users)
eprintf("invalid format: %s\n", modfile);
len = strlen(users) - 1;
if (users[len] == ',' || users[len] == '-')
users[len] = '\0';
printf("%-20s%8s%3s %s\n", name, size, refcount,
users);
}
if (ferror(fp))
eprintf("%s: read error:", modfile);
free(buf);
fclose(fp);
return 0;
}
static void
parse_modline(char *buf, char **name, char **size,
char **refcount, char **users)
{
*name = strtok(buf, " ");
*size = strtok(NULL, " ");
*refcount = strtok(NULL, " ");
*users = strtok(NULL, " ");
}

1
world/bin/lsusb/LICENSE Normal file
View file

@ -0,0 +1 @@
See LICENSE.suckless in top level source directory

6
world/bin/lsusb/Makefile Normal file
View file

@ -0,0 +1,6 @@
# Makefile - hhl - /usr/src/world/bin/lsusb
# Copyright 2020 Nathan Fisher <nfisher.sr@gmail.com>
#
progname = lsusb
include hhl.cprog.ubase.mk

View file

@ -0,0 +1,13 @@
.Dd February 2, 2015
.Dt LSUSB 8
.Os ubase
.Sh NAME
.Nm lsusb
.Nd list USB devices
.Sh SYNOPSIS
.Nm
.Sh DESCRIPTION
.Nm
searches in
.Pa /sys/bus/usb/devices
for USB's and connected devices and prints them one by one.

View file

@ -0,0 +1,58 @@
/* See LICENSE file for copyright and license details. */
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include "ubase/text.h"
#include "ubase/util.h"
static void
lsusb(const char *file)
{
FILE *fp;
char path[PATH_MAX];
char *buf = NULL;
size_t size = 0;
unsigned int i = 0, busnum = 0, devnum = 0, pid = 0, vid = 0;
if (strlcpy(path, file, sizeof(path)) >= sizeof(path))
eprintf("path too long\n");
if (strlcat(path, "/uevent", sizeof(path)) >= sizeof(path))
eprintf("path too long\n");
if (!(fp = fopen(path, "r")))
return;
while (agetline(&buf, &size, fp) != -1) {
if (sscanf(buf, "BUSNUM=%u\n", &busnum) ||
sscanf(buf, "DEVNUM=%u\n", &devnum) ||
sscanf(buf, "PRODUCT=%x/%x/", &pid, &vid))
i++;
if (i == 3) {
printf("Bus %03d Device %03d: ID %04x:%04x\n", busnum, devnum,
pid, vid);
break;
}
}
if (ferror(fp))
eprintf("%s: read error:", path);
free(buf);
fclose(fp);
}
static void
usage(void)
{
eprintf("usage: %s\n", argv0);
}
int
main(int argc, char *argv[])
{
ARGBEGIN {
default:
usage();
} ARGEND;
recurse("/sys/bus/usb/devices", lsusb);
return 0;
}

Some files were not shown because too many files have changed in this diff Show more