mirror of
https://github.com/troglobit/libite.git
synced 2026-10-13 10:14:42 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b69d8a6013 | ||
|
|
e874608b76 | ||
|
|
c1e050f93c | ||
|
|
0e45929323 | ||
|
|
958502d982 | ||
|
|
f0cb0b7bf2 | ||
|
|
ee5788d49b | ||
|
|
9bfe54f959 | ||
|
|
960e7f69ed | ||
|
|
68bc83f08f | ||
|
|
986d29caf0 | ||
|
|
2d9f8f595d | ||
|
|
3f8ad99f1f | ||
|
|
63e25ecae4 | ||
|
|
6c53ee819b | ||
|
|
da21e02be0 | ||
|
|
c33500c372 | ||
|
|
bed65c84e6 | ||
|
|
c4f262b721 | ||
|
|
563b387ec7 | ||
|
|
b93d74c065 | ||
|
|
c1f7bc2bbb | ||
|
|
99f644b512 | ||
|
|
92bb0ca399 | ||
|
|
921afdecb4 | ||
|
|
47b02df823 | ||
|
|
4dd14dac42 | ||
|
|
97a3d43e9c | ||
|
|
784a667584 | ||
|
|
1f6ff90d9e | ||
|
|
9eb847e56c | ||
|
|
55272c13f7 | ||
|
|
34097d33b6 | ||
|
|
311288eec9 | ||
|
|
63cf8867c5 | ||
|
|
ac7b4194cf | ||
|
|
e44aaa4fd5 | ||
|
|
97cb2cb87c | ||
|
|
837c3f23be | ||
|
|
4e9b5c13c1 | ||
|
|
d61b847e55 | ||
|
|
90fdcdeb39 | ||
|
|
e36ac8f462 |
No files matched your search
@@ -0,0 +1,12 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
libite (-lite) is a small project, as such we have no possibility to support older versions.
|
||||
The only supported version is the latest released on GitHub:
|
||||
|
||||
<https://github.com/troglobit/libite/releases>
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Contact the project's main author and owner to report and discuss vulnerabilities.
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install tree doxygen
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Configure
|
||||
run: |
|
||||
./autogen.sh
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
run: |
|
||||
make check || (cat test/test-suite.log; false)
|
||||
- name: Upload Test Results
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: libite-test-${{ matrix.compiler }}
|
||||
path: test/*
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
env:
|
||||
MAKEFLAGS: -j3
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Installing dependencies
|
||||
run: |
|
||||
apt-get update
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
coverity:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Fetch latest Coverity Scan MD5
|
||||
id: var
|
||||
env:
|
||||
@@ -24,10 +24,8 @@ jobs:
|
||||
wget -q https://scan.coverity.com/download/cxx/linux64 \
|
||||
--post-data "token=$TOKEN&project=${COVERITY_PROJ}&md5=1" \
|
||||
-O coverity-latest.tar.gz.md5
|
||||
export MD5=$(cat coverity-latest.tar.gz.md5)
|
||||
echo "Got MD5 $MD5"
|
||||
echo ::set-output name=md5::${MD5}
|
||||
- uses: actions/cache@v2
|
||||
echo "md5=$(cat coverity-latest.tar.gz.md5)" | tee -a $GITHUB_OUTPUT
|
||||
- uses: actions/cache@v4
|
||||
id: cache
|
||||
with:
|
||||
path: coverity-latest.tar.gz
|
||||
@@ -76,7 +74,7 @@ jobs:
|
||||
--form description="${PROJECT_NAME} $(git rev-parse HEAD)" \
|
||||
https://scan.coverity.com/builds?project=${COVERITY_PROJ}
|
||||
- name: Upload build.log
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverity-build.log
|
||||
path: cov-int/build-log.txt
|
||||
@@ -7,38 +7,11 @@ on:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Create GitHub release
|
||||
runs-on: ubuntu-latest
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
outputs:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
release_id: ${{ steps.create_release.outputs.id }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Extract ChangeLog entry ...
|
||||
# Hack to extract latest entry for body_path below
|
||||
run: |
|
||||
awk '/-----*/{if (x == 1) exit; x=1;next}x' ChangeLog.md \
|
||||
|head -n -1 > release.md
|
||||
cat release.md
|
||||
- name: Create release ...
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Libite (-lite) ${{ github.ref }}
|
||||
body_path: release.md
|
||||
draft: false
|
||||
prerelease: false
|
||||
tarball:
|
||||
name: Build and upload release tarball
|
||||
needs: release
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Installing dependencies ...
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
@@ -46,17 +19,19 @@ jobs:
|
||||
- name: Creating Makefiles ...
|
||||
run: |
|
||||
./autogen.sh
|
||||
./configure
|
||||
./configure --prefix=
|
||||
- name: Build release ...
|
||||
run: |
|
||||
make release || (cat test/test-suite.log; false)
|
||||
ls -lF ../
|
||||
make release
|
||||
mkdir -p artifacts/
|
||||
mv ../*.tar.* artifacts/
|
||||
- name: Upload release artifacts ...
|
||||
uses: skx/github-action-publish-binaries@release-0.15
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Extract ChangeLog entry ...
|
||||
run: |
|
||||
awk '/-----*/{if (x == 1) exit; x=1;next}x' ChangeLog.md \
|
||||
|head -n -1 > release.md
|
||||
cat release.md
|
||||
- uses: ncipollo/release-action@v1
|
||||
with:
|
||||
releaseId: ${{ needs.release.outputs.release_id }}
|
||||
args: artifacts/*
|
||||
name: Libite (-lite) ${{ github.ref_name }}
|
||||
bodyFile: "release.md"
|
||||
artifacts: "artifacts/*"
|
||||
+59
-1
@@ -4,6 +4,60 @@ Change Log
|
||||
All notable changes to the project are documented in this file.
|
||||
|
||||
|
||||
[UNRELEASED][]
|
||||
--------------
|
||||
|
||||
### Fixes
|
||||
- Fix `copyfile()` not preserving the source file mode when the process
|
||||
umask is more restrictive
|
||||
- Fix `mkpath()`, and `fmkpath()`, not applying the given mode when the
|
||||
process umask is more restrictive, e.g., requesting 0755 with umask
|
||||
0027 silently created a 0750 directory
|
||||
|
||||
[v2.6.2][] - 2025-11-22
|
||||
-----------------------
|
||||
|
||||
### Fixes
|
||||
- Fix memory leak in `which()` on `realloc()` failure
|
||||
- Fix `pidfile()` to handle missing trailing slash in prefix path
|
||||
|
||||
|
||||
[v2.6.1][] - 2023-10-15
|
||||
-----------------------
|
||||
|
||||
### Fixes
|
||||
- FTBFS uClibc and musl libc, `lite.h` missing `stdarg.h` include
|
||||
|
||||
|
||||
[v2.6.0][] - 2023-09-17
|
||||
-----------------------
|
||||
|
||||
### Changes
|
||||
- New APIs from the [Infix Project](https://github.com/kernelkit/infix):
|
||||
- `fexistf()`
|
||||
- `vfopenf()`
|
||||
- `popenf()`
|
||||
- `vreadsnf()`, `readsnf()`, `writesf()`
|
||||
- `vreadllf()`, `readllf()`, `readdf()`
|
||||
- `writellf()`, `writedf()`
|
||||
|
||||
### Fixes
|
||||
- Spellchecking of API docs
|
||||
|
||||
|
||||
[v2.5.3][] - 2023-04-08
|
||||
-----------------------
|
||||
|
||||
### Changes
|
||||
- Refactor `copyfile()` unit test and verify number of bytes copied
|
||||
- Add missing `rsync()` unit test to ensure proper function
|
||||
|
||||
### Fixes
|
||||
- `rsync()` does not copy single files correctly
|
||||
- `copyfile()` does not handle empty source files correctly (error)
|
||||
- `copyfile()` does not properly create destination dir
|
||||
|
||||
|
||||
[v2.5.2][] - 2022-04-17
|
||||
-----------------------
|
||||
|
||||
@@ -475,7 +529,11 @@ problems this may cause!
|
||||
Initial extraction of frog DNA from [Finit][]. See [README][] for API details.
|
||||
|
||||
|
||||
[UNRELEASED]: https://github.com/troglobit/libite/compare/v2.5.2...HEAD
|
||||
[UNRELEASED]: https://github.com/troglobit/libite/compare/v2.6.2...HEAD
|
||||
[v2.6.2]: https://github.com/troglobit/libite/compare/v2.6.1...v2.6.2
|
||||
[v2.6.1]: https://github.com/troglobit/libite/compare/v2.6.0...v2.6.1
|
||||
[v2.6.0]: https://github.com/troglobit/libite/compare/v2.5.3...v2.6.0
|
||||
[v2.5.3]: https://github.com/troglobit/libite/compare/v2.5.2...v2.5.3
|
||||
[v2.5.2]: https://github.com/troglobit/libite/compare/v2.5.1...v2.5.2
|
||||
[v2.5.1]: https://github.com/troglobit/libite/compare/v2.5.0...v2.5.1
|
||||
[v2.5.0]: https://github.com/troglobit/libite/compare/v2.4.1...v2.5.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
* TODO Write tests for new APIs
|
||||
|
||||
* More formatted variants?
|
||||
- symlinkf()
|
||||
- accessf()
|
||||
- statf() / lstatf()
|
||||
|
||||
* Relocate from Finit
|
||||
|
||||
- fnread()
|
||||
- fnwrite()
|
||||
- fngetint()
|
||||
- paste()
|
||||
- unquote()
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
AC_INIT(libite, 2.5.2, https://github.com/troglobit/libite/issues)
|
||||
AC_INIT(libite, 2.6.2, https://github.com/troglobit/libite/issues)
|
||||
AC_CONFIG_AUX_DIR(aux)
|
||||
AM_INIT_AUTOMAKE([1.11 foreign dist-xz])
|
||||
AM_SILENT_RULES([yes])
|
||||
|
||||
Vendored
+24
@@ -1,3 +1,27 @@
|
||||
libite (2.6.0) stable; urgency=medium
|
||||
|
||||
* New APIs from Infix Project:
|
||||
- fexistf()
|
||||
- vfopenf()
|
||||
- popenf()
|
||||
- vreadsnf(), readsnf(), writesf()
|
||||
- vreadllf(), readllf(), readdf()
|
||||
- writellf(), writedf()
|
||||
* Spellchecking of API docs
|
||||
|
||||
-- Joachim Wiberg <troglobit@gmail.com> Sun, 17 Sep 2023 12:16:47 +0200
|
||||
|
||||
libite (2.5.3) stable; urgency=medium
|
||||
|
||||
* rsync() does not copy single files correctly
|
||||
* copyfile() does not handle empty source files correctly (error)
|
||||
* copyfile() does not properly create destination dir
|
||||
* Add printf format attribute hint to all vararg functions
|
||||
* Fix fisdir() segfault on GNU/Hurd
|
||||
* Fix touch() on Debian/kFreeBSD, use creat() instad of mknod()
|
||||
|
||||
-- Joachim Wiberg <troglobit@gmail.com> Sat, 08 Apr 2023 07:04:00 +0200
|
||||
|
||||
libite (2.5.1) stable; urgency=medium
|
||||
|
||||
* Use dh_link(1) to install `/usr/include/lite -> libite/`.
|
||||
|
||||
+84
-1
@@ -124,7 +124,7 @@ Generic Functions
|
||||
|
||||
Check for the existence of a directory, returns True(1) or False(0).
|
||||
|
||||
- `fopenf(mode, fmt, ...)`
|
||||
- `fopenf(mode, fmt, ...)` and `vfopenf(mode, fmt, ap)`
|
||||
|
||||
Like `fopen()`, but takes a formatted string as argument. This
|
||||
greatly simplifies operations that usually consist of composing a
|
||||
@@ -249,6 +249,19 @@ Generic Functions
|
||||
`delete`, it is now called `opt`. The APIs are 100% compatible if the
|
||||
value `1` was used.
|
||||
|
||||
- `runbg(cmd, delay)`
|
||||
|
||||
Run a command in the background, after delay microseconds, essentially
|
||||
a background `execvp()` with a delay. The function employs double-fork
|
||||
to prevent zombies and closes all open files, including stdio.
|
||||
|
||||
```C
|
||||
char *cmd[] = { "sh", "-c", "echo 'hej' >/tmp/foo", NULL};
|
||||
|
||||
runbg(cmd, 200000); /* Create /tmp/foo after 200 millisec */
|
||||
/* Execution continues here immediately */
|
||||
```
|
||||
|
||||
- `strmatch(str, list)`, `strnmatch(str, list, len)`
|
||||
|
||||
Find matching string in an array of strings. Returns index in array on
|
||||
@@ -307,6 +320,76 @@ Generic Functions
|
||||
yes (both `y` and `Y` are handled) and `FALSE` for everything else.
|
||||
|
||||
|
||||
Procfile Functions
|
||||
------------------
|
||||
|
||||
These functions can be used to simplify access to data in `/proc` and
|
||||
`/sys` on a Linux system.
|
||||
|
||||
### String Functions
|
||||
|
||||
- `readsnf(line, len, fmt, ...)`
|
||||
|
||||
Read first line from a file composed from `fmt`, with optional args.
|
||||
At most `len` bytes from the file are stored in `line`.
|
||||
|
||||
On success this function returns `line` with any trailing newlines
|
||||
`chomp()`ed off. On error `NULL` is returned.
|
||||
|
||||
- `vreadsnf(line, len, fmt, ap)`
|
||||
|
||||
Similar to `readsnf()` but takes a `va_list` argument instead.
|
||||
|
||||
- `writesf(str, mode, fmt, ...)`
|
||||
|
||||
Write the string buffer `str`, with an additional newline, to a file
|
||||
composed from `fmt`, with optional args. The file is opened with the
|
||||
given `mode`, e.g. "w+", which allows for both replacing and appending
|
||||
file content.
|
||||
|
||||
The function returns POSIX OK(0) on success or -1 on failure with the
|
||||
`errno` variable set to a value from either `fopen()` or `fclose()`.
|
||||
|
||||
### Integer Functions
|
||||
|
||||
Read and write 32-bit and 64-bit signed values from/to files.
|
||||
|
||||
- `vreadllf(value, fmt, ap)` and `readllf(value, fmt, ...)`
|
||||
|
||||
Only the first line is read. If the line has newline that is stripped
|
||||
before calling `strtoll()` on the line. The arguments to the latter
|
||||
function is such that it can convert also from a hexadecimal value.
|
||||
|
||||
This function may fail and return -1 on opening the file, reading a
|
||||
line, or if the `strtoll()` function fails. All of which set the
|
||||
`errno` variable. Otherwise this function return POSIX OK(0).
|
||||
|
||||
- `readdf(value, fmt, ...)`
|
||||
|
||||
Read a signed 32-bit value from a file composed from `fmt`, with
|
||||
optional args. This function use `vreadllf()` with an additional
|
||||
range checking for `INT_MIN` and `INT_MAX`. Values outside that
|
||||
cause this function to return -1 with `errno` set to `ERANGE`.
|
||||
|
||||
- `writedf(value, mode, fmt, ...)`
|
||||
|
||||
Write a signed 32-bit `value` to a file composed from `fmt`, with
|
||||
optional args. The file is opened with the given `mode`, e.g. "w+",
|
||||
which allows for both replacing and appending file content.
|
||||
|
||||
The function returns POSIX OK(0) on success or -1 on failure with the
|
||||
`errno` variable set to a value from either `fopen()` or `fclose()`.
|
||||
|
||||
- `writellf(value, mode, fmt, ...)`
|
||||
|
||||
Write a signed 64-bit `value` to a file composed from `fmt`, with
|
||||
optional args. The file is opened with the given `mode`, e.g. "w+",
|
||||
which allows for both replacing and appending file content.
|
||||
|
||||
The function returns POSIX OK(0) on success or -1 on failure with the
|
||||
`errno` variable set to a value from either `fopen()` or `fclose()`.
|
||||
|
||||
|
||||
GNU Functions
|
||||
-------------
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
# The DX_*_FEATURE macros control the default setting for the given
|
||||
# Doxygen feature. Supported features are 'DOXYGEN' itself, 'DOT' for
|
||||
# generating graphics, 'HTML' for plain HTML, 'CHM' for compressed HTML
|
||||
# help (for MS users), 'CHI' for generating a seperate .chi file by the
|
||||
# help (for MS users), 'CHI' for generating a separate .chi file by the
|
||||
# .chm file, and 'MAN', 'RTF', 'XML', 'PDF' and 'PS' for the appropriate
|
||||
# output formats. The environment variable DOXYGEN_PAPER_SIZE may be
|
||||
# specified to override the default 'a4wide' paper size.
|
||||
@@ -321,8 +321,8 @@ DX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation],
|
||||
DX_ENV_APPEND(GENERATE_HTMLHELP, YES)],
|
||||
[DX_ENV_APPEND(GENERATE_HTMLHELP, NO)])
|
||||
|
||||
# Seperate CHI file generation.
|
||||
DX_ARG_ABLE(chi, [generate doxygen seperate compressed HTML help index file],
|
||||
# Separate CHI file generation.
|
||||
DX_ARG_ABLE(chi, [generate doxygen separate compressed HTML help index file],
|
||||
[DX_CHECK_DEPEND(chm, 1)],
|
||||
[DX_CLEAR_DEPEND(chm, 1)],
|
||||
[],
|
||||
|
||||
+6
-6
@@ -2,21 +2,21 @@ lib_LTLIBRARIES = libite.la
|
||||
|
||||
libite_la_CPPFLAGS = -D_GNU_SOURCE
|
||||
libite_la_CFLAGS = -W -Wall -Wextra
|
||||
libite_la_LDFLAGS = $(AM_LDFLAGS) -version-info 8:2:3
|
||||
libite_la_LDFLAGS = $(AM_LDFLAGS) -version-info 9:0:4
|
||||
libite_la_SOURCES = chomp.c copyfile.c \
|
||||
conio.c conio.h dir.c \
|
||||
erasef.c fopenf.c fremove.c \
|
||||
fexist.c fisdir.c \
|
||||
fparseln.c fsendfile.c \
|
||||
ifconfig.c lfile.c \
|
||||
makepath.c progress.c \
|
||||
pidfile.c pidfilefn.c \
|
||||
reallocarray.c rsync.c strtrim.c \
|
||||
makepath.c procval.c progress.c \
|
||||
pidfile.c pidfilefn.c popenf.c \
|
||||
reallocarray.c rsync.c runbg.c \
|
||||
strlcpy.c strlcat.c strtonum.c \
|
||||
strdupa.h strndupa.h strnlen.h \
|
||||
strmatch.c systemf.c touchf.c \
|
||||
strmatch.c systemf.c strtrim.c \
|
||||
telnet.c tempfile.c truncatef.c \
|
||||
yorn.c which.c \
|
||||
touchf.c yorn.c which.c \
|
||||
lite.h strlite.h \
|
||||
queue.h tree.h
|
||||
|
||||
|
||||
+28
-5
@@ -38,6 +38,7 @@ static int adjust_target(const char *src, char **dst)
|
||||
{
|
||||
int isdir = 0;
|
||||
|
||||
retry:
|
||||
if (fisdir(*dst)) {
|
||||
int slash = 0;
|
||||
char *tmp, *ptr = strrchr(src, '/');
|
||||
@@ -58,16 +59,25 @@ static int adjust_target(const char *src, char **dst)
|
||||
|
||||
sprintf(tmp, "%s%s%s", *dst, slash ? "" : "/", ptr);
|
||||
*dst = tmp;
|
||||
} else {
|
||||
struct stat st;
|
||||
|
||||
if (stat(*dst, &st) && fisslashdir(*dst)) {
|
||||
makedir(*dst, 0755);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
return isdir;
|
||||
}
|
||||
|
||||
/* Actual copy loop, used by both copyfile() and fcopyfile()
|
||||
* breaks loop on error and EOF */
|
||||
/*
|
||||
* Actual copy loop, used by both copyfile() and fcopyfile() breaks loop
|
||||
* on error and EOF
|
||||
*/
|
||||
static ssize_t do_copy(int in, int out, size_t num, char *buffer, size_t len)
|
||||
{
|
||||
ssize_t ret = 0, size = 0;
|
||||
ssize_t ret = 0, size = -1;
|
||||
|
||||
do {
|
||||
size_t count = num > len ? len : num;
|
||||
@@ -76,11 +86,16 @@ static ssize_t do_copy(int in, int out, size_t num, char *buffer, size_t len)
|
||||
if (ret <= 0) {
|
||||
if (ret == -1 && EINTR == errno)
|
||||
continue;
|
||||
if (ret == 0 && size == -1)
|
||||
size = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret > 0)
|
||||
if (ret > 0) {
|
||||
if (size == -1)
|
||||
size = 0;
|
||||
size += write(out, buffer, ret);
|
||||
}
|
||||
num -= count;
|
||||
} while (num > 0);
|
||||
|
||||
@@ -193,12 +208,20 @@ ssize_t copyfile(const char *src, const char *dst, int len, int opt)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* open(2) applies umask, we want the source file mode */
|
||||
if (fchmod(out, st.st_mode & 07777)) {
|
||||
saved_errno = errno;
|
||||
size = -1;
|
||||
goto close_exit;
|
||||
}
|
||||
|
||||
size = do_copy(in, out, num, buffer, BUFSIZ);
|
||||
if (!size && errno)
|
||||
if (size < 0)
|
||||
saved_errno = errno;
|
||||
else if (keep_mtim)
|
||||
set_mtime(in, out);
|
||||
|
||||
close_exit:
|
||||
close(out);
|
||||
close(in);
|
||||
|
||||
|
||||
@@ -29,8 +29,13 @@
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lite.h"
|
||||
|
||||
/**
|
||||
* Check if a file exists in the file system.
|
||||
* @param file File to look for, with full path.
|
||||
@@ -50,6 +55,39 @@ int fexist(const char *file)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like fexist() but with formatted string support
|
||||
* @param fmt Formatted string to be composed into the file to look for.
|
||||
*
|
||||
* This is a wrapper for the fexist() function in lite.h, lessening the
|
||||
* burden of having to compose the filename from parts in a seprate
|
||||
* buffer.
|
||||
*
|
||||
* @returns @c TRUE(1) if the @a file exists, otherwise @c FALSE(0).
|
||||
*/
|
||||
int fexistf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *file;
|
||||
int len;
|
||||
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
file = alloca(len + 1);
|
||||
if (!file) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(file, len + 1, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return fexist(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
|
||||
+39
-15
@@ -27,10 +27,43 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Similar to fopenf() except it takes a @a va_list argument
|
||||
* @param mode An fopen() mode string, e.g. "w+".
|
||||
* @param fmt Formatted string to be composed into a pathname.
|
||||
* @param ap List of variable arguemnts from va_start().
|
||||
*
|
||||
* See fopenf() for details.
|
||||
*
|
||||
* @returns a FILE pointer, or @c NULL on error.
|
||||
*/
|
||||
FILE *vfopenf(const char *mode, const char *fmt, va_list ap)
|
||||
{
|
||||
va_list apc;
|
||||
char *file;
|
||||
int len;
|
||||
|
||||
va_copy(apc, ap);
|
||||
len = vsnprintf(NULL, 0, fmt, apc);
|
||||
va_end(apc);
|
||||
|
||||
file = alloca(len + 1);
|
||||
if (!file) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
va_copy(apc, ap);
|
||||
vsnprintf(file, len + 1, fmt, apc);
|
||||
va_end(apc);
|
||||
|
||||
return fopen(file, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a file based on the formatted string and optional arguments
|
||||
* @param mode An fopen() mode string, e.g. "w+"
|
||||
* @param fmt Formatted string to be composed into a pathname
|
||||
* @param mode An fopen() mode string, e.g. "w+".
|
||||
* @param fmt Formatted string to be composed into a pathname.
|
||||
*
|
||||
* This function is an extension to the fopen() family, lessening the burden
|
||||
* of first having to compose the filename from parts in a seprate buffer.
|
||||
@@ -42,24 +75,15 @@
|
||||
FILE *fopenf(const char *mode, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *file;
|
||||
int len;
|
||||
FILE *fp;
|
||||
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(NULL, 0, fmt, ap);
|
||||
fp = vfopenf(mode, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
file = alloca(len + 1);
|
||||
if (!file) {
|
||||
errno = ENOMEM;
|
||||
if (!fp)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(file, len + 1, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return fopen(file, mode);
|
||||
return fp;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+18
-2
@@ -1,7 +1,7 @@
|
||||
/* Collection of frog DNA
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
* Copyright (c) 2008-2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -26,7 +26,7 @@
|
||||
* Collection of frog DNA
|
||||
* @file lite.h
|
||||
* @author Claudio Matsuoka (2008-2010)
|
||||
* @author Joachim Wiberg (2008-2021)
|
||||
* @author Joachim Wiberg (2008-2023)
|
||||
* @copyright MIT License
|
||||
*
|
||||
* The latest version of this manual and the libite (-lite) software
|
||||
@@ -44,6 +44,7 @@ extern "C"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h> /* Definition of AT_* constants for utimensat() */
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h> /* uint8_t, uint16_t, uint32_t, INT32_MAX, etc. */
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
@@ -77,8 +78,10 @@ int erasef (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))
|
||||
char *fparseln (FILE *, size_t *, size_t *, const char[3], int);
|
||||
|
||||
int fexist (const char *file);
|
||||
int fexistf (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));;
|
||||
int fisdir (const char *path);
|
||||
|
||||
FILE *vfopenf (const char *mode, const char *fmt, va_list ap);
|
||||
FILE *fopenf (const char *mode, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
int fremove (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
FILE *tempfile (void);
|
||||
@@ -88,6 +91,16 @@ int fcopyfile (FILE *src, FILE *dst);
|
||||
ssize_t fsendfile (FILE *src, FILE *dst, size_t len);
|
||||
int truncatef (off_t length, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
|
||||
char *vreadsnf (char *line, size_t len, const char *fmt, va_list ap);
|
||||
char *readsnf (char *line, size_t len, const char *fmt, ...);
|
||||
int writesf (const char *str, const char *mode, const char *fmt, ...);
|
||||
|
||||
int vreadllf (long long *value, const char *fmt, va_list ap);
|
||||
int readllf (long long *value, const char *fmt, ...);
|
||||
int readdf (int *value, const char *fmt, ...);
|
||||
int writellf (long long value, const char *mode, const char *fmt, ...);
|
||||
int writedf (int value, const char *mode, const char *fmt, ...);
|
||||
|
||||
int ifconfig (const char *ifname, const char *addr, const char *mask, int up);
|
||||
|
||||
lfile_t*lfopen (const char *file, const char *sep);
|
||||
@@ -104,6 +117,8 @@ int makepath (const char *dir);
|
||||
int dir (const char *dir, const char *type, int (*filter) (const char *file), char ***list, int strip);
|
||||
int rsync (char *src, char *dst, int opt, int (*filter) (const char *file));
|
||||
|
||||
FILE *popenf (const char *type, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
|
||||
int pidfile (const char *basename);
|
||||
int pidfile_signal(const char *pidfile, int signal);
|
||||
pid_t pidfile_read (const char *pidfile);
|
||||
@@ -114,6 +129,7 @@ void *reallocarray(void *optr, size_t nmemb, size_t size);
|
||||
void progress (int percent, int max_width);
|
||||
void progress_simple(int percent);
|
||||
|
||||
int runbg (char *const cmd[], int delay);
|
||||
int systemf (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
|
||||
sdbuf_t*telnet_open (int addr, short port);
|
||||
|
||||
+7
-1
@@ -35,6 +35,9 @@
|
||||
* @param dir Directory to created, relative or absolute
|
||||
* @param mode A &mode_t mode to create @a dir with
|
||||
*
|
||||
* Directories are created with exactly @a mode, the process umask is
|
||||
* not applied like it is for mkdir(2).
|
||||
*
|
||||
* @returns POSIX OK(0) on success, otherwise -1 with @a errno set.
|
||||
*/
|
||||
int mkpath(const char *dir, mode_t mode)
|
||||
@@ -51,7 +54,10 @@ int mkpath(const char *dir, mode_t mode)
|
||||
|
||||
mkpath(dirname(strdupa(dir)), mode);
|
||||
|
||||
return mkdir(dir, mode);
|
||||
if (mkdir(dir, mode))
|
||||
return -1;
|
||||
|
||||
return chmod(dir, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+5
-1
@@ -45,6 +45,7 @@
|
||||
#include <paths.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef pidfile
|
||||
@@ -93,7 +94,10 @@ int pidfile(const char *basename)
|
||||
}
|
||||
|
||||
if (basename[0] != '/') {
|
||||
if (asprintf(&pidfile_path, "%s%s.pid", __pidfile_path, basename) == -1)
|
||||
size_t len = strlen(__pidfile_path);
|
||||
int slash = __pidfile_path[len > 0 ? len - 1 : 0] != '/';
|
||||
|
||||
if (asprintf(&pidfile_path, "%s%s%s.pid", __pidfile_path, slash ? "/" : "", basename) == -1)
|
||||
return (-1);
|
||||
} else {
|
||||
if (asprintf(&pidfile_path, "%s", basename) == -1)
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/* Formatted popen()
|
||||
*
|
||||
* Copyright (c) 2023 Tobias Waldekranz <tobias@waldekranz.com>
|
||||
* Copyright (c) 2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Formatted pipe stream to or from a process
|
||||
* @param type A popen() type, "r" or "w", can also include "e" for @c O_CLOEXEC.
|
||||
* @param fmt Formatted string to be composed into a shell command line.
|
||||
*
|
||||
* This function is an extension to popen(), lessening the burden of
|
||||
* first having to compose the filename from parts in a seprate buffer.
|
||||
*
|
||||
* @returns Upon successful completion, popenf() returns a FILE pointer.
|
||||
* Otherwise, @c NULL is returned and @a errno is set to indicate the
|
||||
* error.
|
||||
*/
|
||||
FILE *popenf(const char *type, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *cmd;
|
||||
int len;
|
||||
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf(NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
cmd = alloca(len + 1);
|
||||
if (!cmd) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(cmd, len + 1, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return popen(cmd, type);
|
||||
}
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
/* Reading and writing values/strings to/from /proc and /sys style files
|
||||
*
|
||||
* Copyright (c) 2023 Tobias Waldekranz <tobias@waldekranz.com>
|
||||
* Copyright (c) 2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file procval.c
|
||||
* @author Joachim Wiberg
|
||||
* @date 2023
|
||||
* @copyright ISC License
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lite.h"
|
||||
|
||||
/**
|
||||
* Similar to readsnf() except it takes a @a va_list argument
|
||||
* @param line Pointer to line buffer.
|
||||
* @param len Size of line buffer.
|
||||
* @param fmt Formatted string to be composed into a pathname.
|
||||
* @param ap List of variable arguemnts from va_start().
|
||||
*
|
||||
* For details, see readsnf().
|
||||
*
|
||||
* @returns same as readsnf().
|
||||
*/
|
||||
char *vreadsnf(char *line, size_t len, const char *fmt, va_list ap)
|
||||
{
|
||||
va_list apc;
|
||||
FILE *fp;
|
||||
|
||||
va_copy(apc, ap);
|
||||
fp = vfopenf("r", fmt, apc);
|
||||
va_end(apc);
|
||||
if (!fp)
|
||||
return NULL;
|
||||
|
||||
if (!fgets(line, len, fp)) {
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return chomp(line);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read first line from a file composed from fmt and optional args.
|
||||
* @param line Pointer to line buffer.
|
||||
* @param len Size of line buffer.
|
||||
* @param fmt Formatted string to be composed into a pathname.
|
||||
*
|
||||
* @returns On success, this function returns the @p line read from the
|
||||
* file, with any trailing '\n' chomp()ed out. On error, @c NULL.
|
||||
*/
|
||||
char *readsnf(char *line, size_t len, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *ln;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ln = vreadsnf(line, len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return ln;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a string buffer to a file composed from fmt and optional args.
|
||||
* @param str Pointer to string buffer, may be multiple lines.
|
||||
* @param mode An fopen() mode string, e.g. "w+".
|
||||
* @param fmt Formatted string to be composed into a pathname.
|
||||
*
|
||||
* @returns result of operation, with @a errno set on error.
|
||||
*/
|
||||
int writesf(const char *str, const char *mode, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
FILE *fp;
|
||||
|
||||
va_start(ap, fmt);
|
||||
fp = vfopenf(mode, fmt, ap);
|
||||
va_end(ap);
|
||||
if (!fp)
|
||||
return -1;
|
||||
|
||||
fprintf(fp, "%s\n", str);
|
||||
return fclose(fp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as readllf() except it takes a @a va_list argument.
|
||||
*/
|
||||
int vreadllf(long long *value, const char *fmt, va_list ap)
|
||||
{
|
||||
char line[0x100];
|
||||
|
||||
if (!vreadsnf(line, sizeof(line), fmt, ap))
|
||||
return -1;
|
||||
|
||||
errno = 0;
|
||||
*value = strtoll(line, NULL, 0);
|
||||
|
||||
return errno ? -1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read 64-bit integer value from a file composed from fmt and optional args.
|
||||
* @param value Pointer to where to store read 64-bit integer value.
|
||||
* @param mode An fopen() mode string, e.g. "w+".
|
||||
* @param fmt Formatted string to be composed into a pathname.
|
||||
*
|
||||
* @returns result of operation, with @a errno set on error.
|
||||
*/
|
||||
int readllf(long long *value, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int rc;
|
||||
|
||||
va_start(ap, fmt);
|
||||
rc = vreadllf(value, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read integer value from a file composed from fmt and optional args.
|
||||
* @param value Pointer to where to store read integer value.
|
||||
* @param mode An fopen() mode string, e.g. "w+".
|
||||
* @param fmt Formatted string to be composed into a pathname.
|
||||
*
|
||||
* @returns result of operation, with @a errno set on error.
|
||||
*/
|
||||
int readdf(int *value, const char *fmt, ...)
|
||||
{
|
||||
long long tmp;
|
||||
va_list ap;
|
||||
int rc;
|
||||
|
||||
va_start(ap, fmt);
|
||||
rc = vreadllf(&tmp, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (tmp < INT_MIN || tmp > INT_MAX) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*value = tmp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write 64-bit integer value to a file composed from fmt and optional args.
|
||||
* @param value 64-bit integer value to write.
|
||||
* @param mode An fopen() mode string, e.g. "w+".
|
||||
* @param fmt Formatted string to be composed into a pathname.
|
||||
*
|
||||
* @returns result of operation, with @a errno set on error.
|
||||
*/
|
||||
int writellf(long long value, const char *mode, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
FILE *fp;
|
||||
|
||||
va_start(ap, fmt);
|
||||
fp = vfopenf(mode, fmt, ap);
|
||||
va_end(ap);
|
||||
if (!fp)
|
||||
return -1;
|
||||
|
||||
fprintf(fp, "%lld\n", value);
|
||||
return fclose(fp);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write integer value to a file composed from fmt and optional args.
|
||||
* @param value Integer value to write.
|
||||
* @param mode An fopen() mode string, e.g. "w+".
|
||||
* @param fmt Formatted string to be composed into a pathname.
|
||||
*
|
||||
* @returns result of operation, with @a errno set on error.
|
||||
*/
|
||||
int writedf(int value, const char *mode, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
FILE *fp;
|
||||
|
||||
va_start(ap, fmt);
|
||||
fp = vfopenf(mode, fmt, ap);
|
||||
va_end(ap);
|
||||
if (!fp)
|
||||
return -1;
|
||||
|
||||
fprintf(fp, "%d\n", value);
|
||||
return fclose(fp);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
+5
-3
@@ -77,7 +77,9 @@ int rsync(char *src, char *dst, int opt, int (*filter)(const char *file))
|
||||
char **files; /* Array of file names. */
|
||||
struct stat st;
|
||||
|
||||
if (!fisdir(dst))
|
||||
errno = 0;
|
||||
|
||||
if (stat(dst, &st) && fisslashdir(dst))
|
||||
makedir(dst, 0755);
|
||||
|
||||
if (!fisdir(src)) {
|
||||
@@ -85,9 +87,9 @@ int rsync(char *src, char *dst, int opt, int (*filter)(const char *file))
|
||||
return 1;
|
||||
|
||||
if (copy(src, dst, keep_mtim))
|
||||
result++;
|
||||
return 1;
|
||||
|
||||
return errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy dir as well? */
|
||||
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/* Run a command in the background: fork() + usleep() + execvp()
|
||||
*
|
||||
* Copyright (c) 2023 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file runbg.c
|
||||
* @author Joachim Wiberg
|
||||
* @date 2023
|
||||
* @copyright ISC License
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/**
|
||||
* Run command in the background
|
||||
* @param cmd NULL terminated list of command and optional arguments
|
||||
* @param delay Microseconds after fork() to wait before calling cmd
|
||||
*
|
||||
* This function forks to run the given command @p cmd in the background.
|
||||
* To ensure there are no lingering zombies the function actuall forks
|
||||
* twice, and also calls setsid(), before it calls usleep() with the @p
|
||||
* delay argument. The command @p cmd is handed over to execvp().
|
||||
*
|
||||
* Since it runs in the background it is not possible to get the return
|
||||
* code of the command.
|
||||
*
|
||||
* @returns on successful (first) fork(), this function returns POSIX
|
||||
* OK(0), otherwise -1 and @a errno is set to indicate the error.
|
||||
*/
|
||||
int runbg(char *const cmd[], int delay)
|
||||
{
|
||||
int pid = fork();
|
||||
int rc;
|
||||
|
||||
if (!pid) {
|
||||
int fd, maxfd;
|
||||
|
||||
if (setsid() == -1)
|
||||
_exit(errno);
|
||||
|
||||
/* reparent to init */
|
||||
pid = fork();
|
||||
if (pid == -1)
|
||||
_exit(errno);
|
||||
if (pid > 0)
|
||||
_exit(0);
|
||||
|
||||
maxfd = sysconf(_SC_OPEN_MAX);
|
||||
if (maxfd == -1)
|
||||
maxfd = 8192;
|
||||
for (fd = 0; fd < maxfd; fd++)
|
||||
close(fd);
|
||||
|
||||
usleep(delay);
|
||||
_exit(execvp(cmd[0], cmd));
|
||||
}
|
||||
|
||||
if (pid == -1)
|
||||
return -1;
|
||||
|
||||
if (waitpid(pid, &rc, 0) == -1)
|
||||
return -1;
|
||||
|
||||
if (WIFEXITED(rc)) {
|
||||
errno = WEXITSTATUS(rc);
|
||||
if (errno)
|
||||
rc = -1;
|
||||
else
|
||||
rc = 0;
|
||||
} else if (WIFSIGNALED(rc)) {
|
||||
errno = EINTR;
|
||||
rc = -1;
|
||||
} else
|
||||
rc = -1;
|
||||
|
||||
return rc;
|
||||
}
|
||||
+9
-6
@@ -53,8 +53,9 @@ static char *strip_args(char *path)
|
||||
*/
|
||||
char *which(const char *cmd)
|
||||
{
|
||||
char *ptr, *env, *path = NULL;
|
||||
size_t pathlen = 0;
|
||||
char *ptr, *tok, *env, *path = NULL;
|
||||
const char *tok;
|
||||
|
||||
if (!cmd) {
|
||||
errno = EINVAL;
|
||||
@@ -69,9 +70,7 @@ char *which(const char *cmd)
|
||||
if (!access(path, X_OK))
|
||||
return path;
|
||||
|
||||
if (path)
|
||||
free(path);
|
||||
|
||||
free(path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -88,11 +87,15 @@ char *which(const char *cmd)
|
||||
size_t len = strlen(tok) + strlen(cmd) + 2;
|
||||
|
||||
if (pathlen < len) {
|
||||
path = realloc(path, len);
|
||||
if (!path) {
|
||||
char *tmp = realloc(path, len);
|
||||
|
||||
if (!tmp) {
|
||||
free(path);
|
||||
free(env);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
path = tmp;
|
||||
pathlen = len;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
/printhdr
|
||||
/progress
|
||||
/rsync
|
||||
/runbg
|
||||
/str
|
||||
/strmatch
|
||||
/systemf
|
||||
|
||||
@@ -30,6 +30,7 @@ TESTS += pidfile
|
||||
TESTS += printhdr
|
||||
TESTS += progress
|
||||
TESTS += rsync
|
||||
TESTS += runbg
|
||||
TESTS += str
|
||||
TESTS += strmatch
|
||||
TESTS += systemf
|
||||
|
||||
+147
-48
@@ -2,54 +2,153 @@
|
||||
#include <errno.h>
|
||||
#include "check.h"
|
||||
|
||||
#define ERR(fmt, args...) { printf(fmt ": %s\n", ##args, strerror(errno)); rc = 1; }
|
||||
#define ERRX(fmt, args...) { printf(fmt "\n", ##args); rc = 1; }
|
||||
|
||||
static char *files[] = {
|
||||
"/etc/passwd", "/tmp/mypwd", "/tmp/mypwd",
|
||||
"/etc/passwd", "/tmp/", "/tmp/passwd",
|
||||
"/etc/passwd", "/tmp", "/tmp/passwd",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int one_sz(const char *src, const char *dst, int sz)
|
||||
{
|
||||
struct stat st;
|
||||
ssize_t len;
|
||||
int rc = 0;
|
||||
|
||||
len = copyfile(src, dst, sz, 0);
|
||||
if (!len) {
|
||||
ERR("failed copying any bytes from %s", src);
|
||||
} else {
|
||||
if (stat(dst, &st))
|
||||
ERR("copied but cannot find destination %s", dst);
|
||||
|
||||
if (st.st_size != sz)
|
||||
ERR("file only %ld bytes, expected %d", st.st_size, sz);
|
||||
|
||||
if (len != st.st_size)
|
||||
ERRX("copied expected data %d, but copyfile() says %ld", sz, len);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int _sz()
|
||||
{
|
||||
const int sz = 32768;
|
||||
|
||||
return test(one_sz("/dev/zero", "/tmp/zeroes", sz), "copyfile(/dev/zero, %d)", sz);
|
||||
}
|
||||
|
||||
static int fcopyfile_one(const char *src, const char *dst, const char *expected)
|
||||
{
|
||||
FILE *from, *to;
|
||||
int rc;
|
||||
|
||||
from = fopen(src, "r");
|
||||
to = fopen(dst, "w");
|
||||
|
||||
rc = fcopyfile(from, to);
|
||||
|
||||
if (from)
|
||||
fclose(from);
|
||||
if (to)
|
||||
fclose(to);
|
||||
|
||||
if (rc) {
|
||||
if (!src || !dst)
|
||||
rc = 0; /* expected */
|
||||
else if (fisdir(dst))
|
||||
rc = 0; /* expected */
|
||||
} else {
|
||||
if (fexist(expected)) {
|
||||
if (systemf("diff -q %s %s", src, expected))
|
||||
rc = 1;
|
||||
} else
|
||||
ERR("cannot find %s", expected);
|
||||
}
|
||||
|
||||
erase(expected);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int _fcopyfile()
|
||||
{
|
||||
int i, rc = 0;
|
||||
|
||||
for (i = 0; files[i]; i += 3) {
|
||||
char *src = files[i];
|
||||
char *dst = files[i + 1];
|
||||
char *res = files[i + 2];
|
||||
|
||||
rc += test(fcopyfile_one(src, dst, res), "fcopyfile(%s, %s)", src, dst);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* only checks success, correct file size verified by _sz() */
|
||||
static int copyfile_one(const char *src, const char *dst, const char *expected)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = copyfile(src, dst, 0, 0);
|
||||
if (!rc)
|
||||
rc = 1;
|
||||
else if (!fexist(expected))
|
||||
rc = 1;
|
||||
else
|
||||
rc = 0;
|
||||
|
||||
erase(expected);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int _copyfile()
|
||||
{
|
||||
int i, rc = 0;
|
||||
|
||||
for (i = 0; files[i]; i += 3) {
|
||||
char *src = files[i];
|
||||
char *dst = files[i + 1];
|
||||
char *res = files[i + 2];
|
||||
|
||||
rc += test(copyfile_one(src, dst, res), "copyfile(%s, %s)", src, dst);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* copyfile() must preserve source mode, even with a restrictive umask */
|
||||
static int _mode(void)
|
||||
{
|
||||
const char *src = "/tmp/libite-mode-src", *dst = "/tmp/libite-mode-dst";
|
||||
struct stat st;
|
||||
mode_t old;
|
||||
int rc = 1;
|
||||
|
||||
if (touch(src) || chmod(src, 0644))
|
||||
return test(1, "copyfile() mode, prepare %s", src);
|
||||
|
||||
old = umask(0077);
|
||||
if (copyfile(src, dst, 0, 0) >= 0 && !stat(dst, &st))
|
||||
rc = (st.st_mode & 07777) != 0644;
|
||||
umask(old);
|
||||
|
||||
erase(src);
|
||||
erase(dst);
|
||||
|
||||
return test(rc, "copyfile() preserves mode 0644 with umask 0077");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i = 0;
|
||||
char *files[] = {
|
||||
"/etc/passwd", "/tmp/mypwd", "/tmp/mypwd",
|
||||
"/etc/passwd", "/tmp/", "/tmp/passwd",
|
||||
"/etc/passwd", "/tmp", "/tmp/passwd",
|
||||
NULL
|
||||
};
|
||||
FILE *src, *dst;
|
||||
|
||||
printf("=>Start testing fcopyfile()\n");
|
||||
while (files[i]) {
|
||||
printf("fcopyfile(%s, %s)\t", files[i], files[i + 1]);
|
||||
src = fopen(files[i], "r");
|
||||
dst = fopen(files[i + 1], "w");
|
||||
if (fcopyfile(src, dst)) {
|
||||
if (!fisdir(files[i + 1]))
|
||||
err(1, "Failed fcopyfile(%s, %s)", files[i], files[i + 1]);
|
||||
}
|
||||
|
||||
if (src)
|
||||
fclose(src);
|
||||
if (dst)
|
||||
fclose(dst);
|
||||
|
||||
if (fexist(files[i + 2]))
|
||||
printf("OK => %s", files[i + 2]);
|
||||
printf("\n");
|
||||
|
||||
erase(files[i + 2]);
|
||||
i += 3;
|
||||
}
|
||||
|
||||
printf("\n=>Start testing copyfile()\n");
|
||||
i = 0;
|
||||
while (files[i]) {
|
||||
printf("copyfile(%s, %s)\t", files[i], files[i + 1]);
|
||||
if (!copyfile(files[i], files[i + 1], 0, 0))
|
||||
err(1, "Failed copyfile(%s, %s)", files[i], files[i + 1]);
|
||||
|
||||
if (fexist(files[i + 2]))
|
||||
printf("OK => %s", files[i + 2]);
|
||||
printf("\n");
|
||||
|
||||
erase(files[i + 2]);
|
||||
i += 3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return _fcopyfile() ||
|
||||
_copyfile() ||
|
||||
_sz() ||
|
||||
_mode();
|
||||
}
|
||||
+34
-2
@@ -50,6 +50,34 @@ int test_fmkpath(const char *subdir)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* mkpath() must apply mode as given, not mode & ~umask */
|
||||
int test_umask(void)
|
||||
{
|
||||
const char *dirs[] = { BASEDIR "/um", BASEDIR "/um/sub", NULL };
|
||||
mode_t old = umask(0077);
|
||||
struct stat sb;
|
||||
int i, ret;
|
||||
|
||||
ret = mkpath(dirs[1], 0755);
|
||||
umask(old);
|
||||
if (ret) {
|
||||
perror("Failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; dirs[i]; i++) {
|
||||
if (checkpath(dirs[i]) || stat(dirs[i], &sb))
|
||||
return 1;
|
||||
if ((sb.st_mode & 07777) != 0755) {
|
||||
fprintf(stderr, "Failed: %s mode %04o, expected 0755\n",
|
||||
dirs[i], sb.st_mode & 07777);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i, ret = 0;
|
||||
@@ -66,14 +94,18 @@ int main(void)
|
||||
|
||||
mkdir(BASEDIR, 0755);
|
||||
|
||||
printf("Pass 1/2: makepath() =========================\n");
|
||||
printf("Pass 1/3: makepath() =========================\n");
|
||||
for (i = 0; list[i] && !ret; i++)
|
||||
ret |= test_makepath(list[i]);
|
||||
|
||||
printf("Pass 2/2: fmkpath() ==========================\n");
|
||||
printf("Pass 2/3: fmkpath() ==========================\n");
|
||||
for (i = 0; list[i] && !ret; i++)
|
||||
ret |= test_fmkpath(list[i] + strlen(BASEDIR) + 1);
|
||||
|
||||
printf("Pass 3/3: mkpath() with umask ================\n");
|
||||
if (!ret)
|
||||
ret |= test_umask();
|
||||
|
||||
printf("Done: Cleaning up ============================\n");
|
||||
system("rm -rf " BASEDIR);
|
||||
|
||||
|
||||
+65
-35
@@ -48,52 +48,82 @@ void setup_test(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void check_tree(char *heading, char *dir)
|
||||
int check_dir_to_dir(void)
|
||||
{
|
||||
if (verbose) {
|
||||
if (heading)
|
||||
puts(heading);
|
||||
int rc = 0;
|
||||
|
||||
rc += rsync(SRC, DST, LITE_FOPT_KEEP_MTIME, NULL);
|
||||
rc += systemf("diff -rq %s %s", SRC, DST);
|
||||
systemf("rm -rf %s/*", DST);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int check_file_to_file(void)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
touch(SRC "foo.txt");
|
||||
PRINT("SRC ==========================\n");
|
||||
if (verbose) system("ls -l " SRC);
|
||||
rc += rsync(SRC "foo.txt", DST "foo.txt", LITE_FOPT_KEEP_MTIME, NULL);
|
||||
if (!fexist(DST "foo.txt") || fisdir(DST "foo.txt")) {
|
||||
PRINT("No dst file or it's a directory\n");
|
||||
rc++;
|
||||
}
|
||||
|
||||
// XXX: Fixme, add code to list tree, nftw() possibly
|
||||
PRINT("DST ==========================\n");
|
||||
if (verbose) system("ls -l " DST);
|
||||
systemf("rm -rf %s %s/*", SRC "foo.txt" , DST);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int check_file_to_dir(void)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
touch(SRC "foo.txt");
|
||||
PRINT("SRC ==========================\n");
|
||||
if (verbose) system("ls -l " SRC);
|
||||
rc += rsync(SRC "foo.txt", DST, LITE_FOPT_KEEP_MTIME, NULL);
|
||||
if (!fexist(DST "foo.txt") || fisdir(DST "foo.txt"))
|
||||
rc++;
|
||||
PRINT("DST ==========================\n");
|
||||
if (verbose) system("ls -l " DST);
|
||||
systemf("rm -rf %s %s/*", SRC "foo.txt" , DST);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int check_file_to_nodir(void)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
touch(SRC "foo.txt");
|
||||
PRINT("SRC ==========================\n");
|
||||
if (verbose) system("ls -l " SRC);
|
||||
system("rm -rf " DST);
|
||||
rc += rsync(SRC "foo.txt", DST, LITE_FOPT_KEEP_MTIME, NULL);
|
||||
if (!fexist(DST "foo.txt") || fisdir(DST "foo.txt"))
|
||||
rc++;
|
||||
PRINT("DST ==========================\n");
|
||||
if (verbose) system("ls -l " DST);
|
||||
systemf("rm -rf %s %s/*", SRC "foo.txt" , DST);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int run_test(void)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
#if 0
|
||||
setup_test();
|
||||
check_tree("Before:", BASE);
|
||||
|
||||
result += rsync(SRC, DST, 0, NULL);
|
||||
check_tree("After:", BASE);
|
||||
cleanup_test();
|
||||
#endif
|
||||
|
||||
setup_test();
|
||||
sleep(1);
|
||||
result += rsync(BASE "src", DST, LITE_FOPT_KEEP_MTIME, NULL);
|
||||
check_tree("Only partial rsync of src <-- No slash!", BASE);
|
||||
#if 0
|
||||
cleanup_test();
|
||||
setup_test();
|
||||
result += rsync(BASE "src/sub1", BASE "dst", 0, NULL);
|
||||
check_tree("Only partial rsync of src/sub1 <-- No slashes!!", BASE);
|
||||
|
||||
cleanup_test();
|
||||
setup_test();
|
||||
result += rsync(BASE "src/sub1/", DST, 0, NULL);
|
||||
check_tree("Only partial rsync of src/sub1/", BASE);
|
||||
|
||||
cleanup_test();
|
||||
setup_test();
|
||||
result += rsync(BASE "src/sub1", DST, 0, NULL);
|
||||
check_tree("Only partial rsync of src/sub1 <-- No slash!", BASE);
|
||||
|
||||
result += rsync("/etc", "/var/tmp", 0, NULL);
|
||||
check_tree("Real life test:", "/var/tmp");
|
||||
#endif
|
||||
result += test(check_dir_to_dir(), "Verifying src/ -> dst/");
|
||||
result += test(check_file_to_file(), "Verifying src/foo.txt -> dst/foo.txt");
|
||||
result += test(check_file_to_dir(), "Verifying src/foo.txt -> dst/");
|
||||
result += test(check_file_to_nodir(),"Verifying src/foo.txt -> dst/ (non-existing target dir)");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#include "check.h"
|
||||
|
||||
#define file "/tmp/runbg.txt"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char *cmd[] = {
|
||||
"sh", "-c", "echo 'hello world' > " file, NULL
|
||||
};
|
||||
|
||||
erase(file);
|
||||
test(runbg(cmd, 100000), "Calling runbg");
|
||||
|
||||
if (test(fexist(file), "Verifying %s does not yet exist", file))
|
||||
return 1;
|
||||
|
||||
test(sleep(1), "Waiting for runbg");
|
||||
|
||||
if (test(!fexist(file), "Verifying %s has been created", file))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user