Matthias Kruk [Fri, 28 May 2021 12:12:16 +0000 (21:12 +0900)]
include/json: Add functions for manipulating JSON arrays
Handling JSON arrays in shell scripts can be painful without jq. This
commit adds a number of convenience functions that wrap jq to make
array handling easier. The follow fuctions are added:
- json_array_head(): Returns the first element of a JSON array
- json_array_tail(): Returns a new JSON array without the first element
- json_array_to_lines(): Returns all elements of a JSON array, one per line
Matthias Kruk [Wed, 26 May 2021 04:31:15 +0000 (13:31 +0900)]
include/queue: queue_foreach: Return failure if callback fails
The queue_foreach() function always returns success, even if one of
the callbacks failed. This makes it hard to handle errors that occur
inside the callbacks.
This commit changes the function to return failure if a callback has
failed.
Matthias Kruk [Fri, 21 May 2021 07:04:45 +0000 (16:04 +0900)]
include/json: Correctly escape braces in RegEx
The json functions currently don't correctly recognize objects because
braces aren't correctly escaped. This commit changes the regexes so that
braces are escaped properly.
Matthias Kruk [Fri, 21 May 2021 06:39:19 +0000 (15:39 +0900)]
include/json: Allow arrays, objects as input to json_array() and json_object()
The json_array() and json_object() functions currently can only be used
to construct arrays and objects containing strings and integers.
This commit modifies the functions so that they can also encode objects
and arrays within objects and arrays.
Matthias Kruk [Thu, 20 May 2021 04:37:59 +0000 (13:37 +0900)]
include/log: Don't pass log message through date
The log_write() function passes the log message through `date' to
prepend the timestamp to it. This causes problems when the message
contains format placeholders that are interpreted by date.
This commit changes the log_write() function not to pass the log
message and prefix through date.
Matthias Kruk [Thu, 20 May 2021 00:58:31 +0000 (09:58 +0900)]
include/opt: Fix C-ish statement
The statement used to store the length of the longest option name in
opt_add_arg() looks very C-like, meaning it doesn't work correctly in
bash. This commit changes the statement to proper shell syntax.
Matthias Kruk [Thu, 20 May 2021 00:55:14 +0000 (09:55 +0900)]
include/opt: Work around bug in old bash versions
Declaring a non-local array and initializing it in the same statement
causes it to become local in older bash versions. This commit works
around this bug by removing the array initializations from internal
arrays of the opt module.
Matthias Kruk [Wed, 19 May 2021 23:32:28 +0000 (08:32 +0900)]
include/gitlab: Allow destination namespace to be passed to fork methods
The gitlab_fork() and gitlab_fork_sync() functions can only be used to
for a project to the user's personal namespace, since they do not allow
the destination namespace to be specified. This commit adds an argument
for the destination namespace, so that the functions can be used to fork
into arbitrary namespaces.
Matthias Kruk [Wed, 19 May 2021 23:26:24 +0000 (08:26 +0900)]
include/gitlab: Add method to query the current user
This commit adds the gitlab_get_current_user() function, which allows
the caller to retrieve a JSON object containing information about the
current GitLab user.
include/queue: Allow additional data to be passed along with files
Some use-cases require files to be passed through queues along with
additional data. This commit extends the queue_put_file() and
queue_get_file() functions to allow additional data to be passed
along with a file.
There is currently no way to inspect the state of a queue, making it
very hard to write scripts that safely show the contents of a queue.
This commit adds the queue_foreach() function, which allows the caller
to invoke a callback function for each item in a queue.
The queue_foreach() function must be passed at least two arguments,
the name of the queue and the name of the callback function. All other
arguments will be passed on to the callback function.
If the callback returns a non-zero value, the iteration of the queue
will be aborted.
The queue_foreach() function will lock the queue for the duration that
the callbacks are executed. The callbacks must under absolutely no
circumstances attempt to perform any queue operations on the queue or
otherwise attempt to modify the queue, since this will either result
in a deadlock or leave the queue in an inconsistent state.
Example use:
callback() {
local item="$1"
local user_data="$2"
local more_data="$3"
include/sem: Re-implement semaphores without busy-waiting workaround
The current sem module has a design issue that requires the use of sleep
or inotifywait to avoid busy-waiting when the semaphore counter is zero.
This commit adds a new sem implementation that avoids the problem
altogether through the use of a separate mutex (called waitlock), which
sem_wait() will attempt to acquire, causing it to be blocked until the
waitlock is released by a call to sem_post().
Further, the new implementation keeps all filesystem objects belonging to
a semaphore in a directory, giving it a cleaner appearance.
This commit also adds several test cases for the new sem module.
include/mutex,wmutex: Add weak mutexes that don't enforce ownership
When using mutexes as a means for signalling between two processes, the
lock and unlock operation will almost never be executed by the same
process. However, the mutex module does not allow such behavior.
This commit adds the wmutex module (the "w" is for "weak") which does
not enforce ownership on mutexes.
As a side note, the same could have been achieved by adding something
like mutex_weak_lock() and mutex_weak_unlock() to the mutex module, but
that would lead to people mixing the two. Implementing them in separate
modules hopefully makes it more clear that using wmutex functions on a
mutex (and vice-versa) is not acceptable. If necessary, I might even
implement the two in different ways so a mutex can't be released with
wmutex_unlock().
include/conf: Append config instead of overwriting it
The conf_set() function overwrites the configuration file instead of
appending to it, making it impossible to store multiple settings.
This commit changes conf_set() to append to the configuration file.
include/mutex: Prevent children from unlocking their parents' mutexes
The mutex_trylock() and mutex_unlock() functions use $$ to determine the
current process's PID. However, this variable always reflects the PID of
the original shell. This commit changes the functions to use $BASHPID to
determine the PID of the current shell.
include/mutex: Make mutex_lock() fail if the path does not exist
The mutex_lock() function does not check if the path of the mutex
exists, causing it to wait forever if an invalid path was passed.
This commit makes mutex_lock() fail if it could not inotifywait on
the directory that contains the mutex.
The is_alpha() and is_alnum() functions fail to recognize strings
containing mixed case and digits (in the case of the latter). This
commit fixes the implementations by making perform the check with a
regular expression instead of delegating the work to is_upper(),
is_lower(), and is_digits().
The name of the is_digit() function was originally taken from the
Standard C library function of the same name. However, that function
checks only a single character, while this function compares all
characters in a string. To avoid confusion, this commit renames the
function to is_digits().
It is more common to use -q or --quiet to make commandline utilities
emit less output. This commit renames the -w/--shush argument to -q/
--quiet to follow that convention.
include/opt: Add flag to define required arguments
The opt module currently does not provide a means to define required
arguments, making it hard for the callee to determine if an argument
was provided on the commandline, or if the default value was returned
by opt_get().
This commit adds a flag to specify if an argument must be provided on
the commandline. Further, since multiple flags can now be passed to
opt_add_arg(), the flag format is changed: now, a string containing
all flags as characters must be passed. The implementation understands
the following flags:
r - Argument is required
v - Argument has a value (e.g. is followed by a second argument)
For example, to declare a required argument with a value, one would
pass the flags "rv".
This commit increases the package version to 0.3-1 and removes the
description from the "Source" portion of the debian/control file so
the dpkg-buildpackage version used on deb.m10k.eu won't complain.
The queue module depends on the log module, however it doesn't include
it during initialization. This commit makes sure the log module is
loaded along with the queue module.
include/sem: Work around busy-waiting in sem_wait()
The sem_wait() function is implemented using busy-waiting, which is not
good for the environment. This commit adds a call to inotifywait as a
temporary workaround to avoid the busy-waiting.
include/mutex: Use inotifywait to improve performance
The current mutex implementation uses sleep to periodically check if
the lock can be acquired. This causes a lot of latency for short waits
and a lot of unnecessary sleep/wakeup cycles for long waits.
This commit changes the mutex implementation to use inotifywait
instead of sleep, increasing mutex performance for both short and long
waits.
include/inst: Make inst_stop emit a meaningful message upon error
Instead of emitting a user-understandable error message, the inst_stop()
function merely lets an error message from the sem module slip through.
This commit changes the function to emit an error message that tells the
caller why exactly the function failed.
include/inst: Add inst module for managing running instances of scripts
This commit adds the inst module which provides functions for managing
instances of scripts:
- The inst_start() function forks a function to the background
- The inst_stop() function asks an instance to stop
- The inst_list() function lists running instances
- The inst_running() function tells an instance if it should stop
Internally, the module makes use of semaphores to list instances and
determine their state. Semaphores are kept in per-script directories
within $TOOLBOX_HOME/inst.
include/opt: Remember arguments passed to opt_parse()
To allow the user to distinguish running instances of a script, it is
necessary to present the arguments that an instance was started with.
The most logical place to remember such information is inside the opt
module. Therefore, this commit adds the opt_get_argv() function, which
allows the caller to retrieve the arguments that were passed to the
opt_parse() function.
include/opt: Make --verbose and --shush default arguments
The -v/--verbose and -w/--shush options are frequently implemented in
scripts that use toolbox. To reduce code duplication and to make all
scripts follow the same argument naming conventions, this commit makes
-v/--verbose and -w/--shush standard arguments of the opt module.
include/log: Add functions to increase and decrease the verbosity
I frequently find myself implementing the same functions to increase
and decrease the verbosity of my scripts. This commit adds these
functions to the log module.
include/queue: Add functions for file queues and duplicate-free queues
For certain automation tasks, it would be helpful if filesystem objects
could be passed through queues. This commit adds such functionality to
the queue module.
For passing files, these functions can be used:
- queue_put_file()
- queue_get_file()
For duplicate-free transient data:
- queue_put_unique()
- queue_get()
For other transient data:
- queue_put()
- queue_get()
There are two things worth noting:
1. The queues are line-based (transient data may not contain newlines)
2. Queues cannot be used for transient data and files at the same time
include/sem: Allow semaphores to be created in arbitrary locations
The current implementation cannot be used to created semaphores outside
of $TOOLBOX_HOME/sem. This makes it impossible to share semaphores with
scripts that are executed as a different user.
This commit changes the semaphore implementation so that only semaphore
names that don't contain slashes will be created in $TOOLBOX_HOME/sem.
The ssh_tunnel_close() and ssh_proxy_close() functions do essentially
the same thing, so they should be merged into one. Further, both of
the functions require the user to remember multiple values from the
ssh_*_open() call in order to close the connection. This seems
unnecessarily complicated.
This commit adds the ssh_close() function as a replacement for
ssh_tunnel_close() and ssh_proxy_close(). Further, the ssh_*_open()
functions now return a handle that can be passed to ssh_close() to
close the respective connection.
include/log: Remove timestamp and pid from log path
Having the timestamp and pid in the log path causes a large number of
log files to be generated, which makes it difficult to find the correct
one.
This commit removes the timestamp and pid from the log path, causing
all processes with the same name to log to the same file. To distinguish
individual processes, the log_write() function will also log the pid of
the calling process.
debian: Change architecture to "all" and fix warnings during build
The architecture in the Debian control file is set to "any", causing
architecture-specific packages to be built. This commit changes the
architecture to "all", causing the resulting packages to be usable on
any architecture.
This commit further fixes other warnings emitted by dpkg-buildpackage
with regard to the changelog and fields in the control file.
Global variables declared in the sem and acpi/* modules are not exported,
causing them to become invisible in child processes. This effectively makes
it impossible to use these modules in scripts that fork themselves to the
background.
This commit changes the declarations so that the variables are exported.
toolbox: Allow modules to be included from TOOLBOX_HOME
The current implementation requires that modules be located in the
global module search path, TOOLBOX_PATH/include. This commit modifies
the implementation so that modules may be included from the user's
TOOLBOX_HOME in addition to the global search path:
When include() is invoked, it will attempt to include the module from
the TOOLBOX_HOME/include first, and only if it didn't succeed, it will
attempt to load the module from TOOLBOX_PATH/include.
The symlink to toolbox.sh points to the absolute path of the file in the
Debian buildroot, which is an invalid location in an installed system.
This commit fixes the symlink to point to the location of the installed
file.
toolbox: Change the default prefix to appease Debian package builds
Debian package builds are failing because the installation prefix defaults
to /usr/local instead of /usr. This changes the default prefix to /usr, to
make Debian package builds happy.
A bug in _net_iface_parse_iwlist() caused found access points to be printed
multiple times. This commit fixes the bug, so that each access point is
printed only once.
Matthias Kruk [Sun, 28 Mar 2021 02:11:59 +0000 (11:11 +0900)]
include/opt: Add parser for command line parameters
Parsing of command line parameters and printing the help text adds
a significant amount of boilerplate code to any shell script (when
done thoroughly). This commit adds the opt module, which will parse
short and long parameters, execute callbacks, and print the help
text if either "-h" or "--help" were passed.
Matthias Kruk [Sun, 28 Mar 2021 01:38:52 +0000 (10:38 +0900)]
include/array: Add functions for printing and sorting arrays
Printing and sorting arrays in-line tends to be rather awkward.
This commit adds the array_to_lines() and array_sort() functions
that take over this task.
Matthias Kruk [Sat, 27 Mar 2021 03:10:05 +0000 (12:10 +0900)]
include/iface: Add function for scanning for wireless network
The output from `iwlist scan' is rather hard to look at and bothersome
to use in scripts. This commit adds a function that parses the output
into a more machine-friendly format.
Matthias Kruk [Wed, 24 Mar 2021 23:22:35 +0000 (08:22 +0900)]
include/gitlab: Add functions to call Gitlab API from the shell
Gitlab can be integrated with other software through Gitlab's REST
API. This commit adds functions that allow using various Gitlab API
functions from the shell, such as forking repositories, managing
branches, and creating merge requests.
Matthias Kruk [Wed, 24 Mar 2021 23:17:07 +0000 (08:17 +0900)]
include/iruca: Add functions to get and set somebody's iruca status
Iruca provides a REST-ful API that can be used more conveniently than
the website. This commit adds functions for setting and getting an iruca
user's status and status message from the commandline.
Matthias Kruk [Wed, 24 Mar 2021 22:26:46 +0000 (07:26 +0900)]
include/ssh: Add functions for handling SSH tunnels and proxies
SSH provides a clean way to open and close tunnels and proxies on demand
through control sockets, however keeping track of the control sockets can
be somewhat bothersome. This commit adds functions that provide an easy
way to open and close tunnels and proxies without the caller having to
bother with control sockets.
Matthias Kruk [Wed, 24 Mar 2021 22:24:30 +0000 (07:24 +0900)]
include/array: Add function for checking if an element is in an array
Bash doesn't provide a simple way to check if an element is in an array.
This commit adds the array_contains convenience function to solve that
problem.
Matthias Kruk [Wed, 24 Mar 2021 22:20:36 +0000 (07:20 +0900)]
include/json: Add functions for creating json objects and arrays
Especially when interacting with REST-ful APIs via curl, it can be handy
to have functions to quickly generate JSON objects without having to
invoke jq. This commit adds functions for generating simple JSON objects
and arrays.
Matthias Kruk [Tue, 23 Mar 2021 23:56:27 +0000 (08:56 +0900)]
include/log: Log messages to the logfile AND stderr
The log module only writes messages to the log file, which is not
enough for scripts that are running in the foreground. This commit
changes the log_write() function to log messages to the logfile as
well as to stderr.
Matthias Kruk [Mon, 22 Mar 2021 00:46:46 +0000 (09:46 +0900)]
include/acpi: Add modules for querying battery and PSU state
This commit adds the acpi/battery and acpi/ac module which can be used
to query the state of batteries and power supply units in the system
through the kernel's sysfs ACPI interface.
Matthias Kruk [Mon, 22 Mar 2021 00:43:39 +0000 (09:43 +0900)]
include/sem: Fix names of logging functions
The functions that the sem module was using for logging do not exist in
the latest log module. This commit changes the sem module to use the
right functions.
Matthias Kruk [Mon, 22 Mar 2021 00:36:25 +0000 (09:36 +0900)]
include/log: Add logging facilities
This commit adds the log module which can be adopted by scripts to log
messages to log files that are stored in TOOLBOX_HOME. The module also
provides convenience functions for highlighting output and printing
stack traces.
In certain situations, mutex are not enough for synchronization. This
commit adds a POSIX-like semaphore implementation that can be used to
implement things like queues or singleton scripts.
Scripts that access shared resources need a means to synchronize accesses
to those resources. This commit adds a symlink-based mutex implementation
that can be used for this purpose.
Matthias Kruk [Sat, 20 Mar 2021 23:23:32 +0000 (08:23 +0900)]
toolbox: Implement toolbox initialization and module loading
When writing shell scripts, I often find myself copying or rewriting
functions because bash does not provide a mechanism to easily reuse
code. This commit adds a mechanism for loadable bash "modules".