mirror of
https://github.com/troglobit/finit.git
synced 2026-10-12 10:12:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70a44d3860 | ||
|
|
f29a3db86c | ||
|
|
f6b394e0a2 | ||
|
|
ccaa4caf48 | ||
|
|
77d199f1a4 | ||
|
|
0448151c0a | ||
|
|
75739fbeef | ||
|
|
3a72d1263c | ||
|
|
7e2b154f9b | ||
|
|
547e59b2ad | ||
|
|
7f37d0c4e9 | ||
|
|
dd77f63ad3 | ||
|
|
e0f9df1f27 |
@@ -1,12 +1,13 @@
|
|||||||
name: Bob the Builder
|
name: Bob the Builder
|
||||||
|
|
||||||
# Run on all branches, including all pull requests, except the 'dev'
|
# Run on push to release branches (master and maintenance N.x), and
|
||||||
# branch since that's where we run Coverity Scan (limited tokens/day)
|
# on all pull requests. The 'dev' branch is where we run Coverity
|
||||||
|
# Scan (limited tokens/day)
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- '**'
|
- master
|
||||||
- '!dev'
|
- '[0-9]+.x'
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, synchronize, reopened, labeled]
|
types: [opened, synchronize, reopened, labeled]
|
||||||
|
|
||||||
@@ -22,8 +23,6 @@ jobs:
|
|||||||
# Verify we can build on latest Ubuntu with both gcc and clang
|
# Verify we can build on latest Ubuntu with both gcc and clang
|
||||||
name: ${{ matrix.compiler }}
|
name: ${{ matrix.compiler }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
# Skip redundant builds for PRs - prefer PR builds over push builds
|
|
||||||
if: github.event_name != 'push' || github.ref == 'refs/heads/master'
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
compiler: [gcc, clang]
|
compiler: [gcc, clang]
|
||||||
@@ -43,7 +42,7 @@ jobs:
|
|||||||
(cd libuev-2.4.1 && ./configure && make -j9 && sudo make install-strip)
|
(cd libuev-2.4.1 && ./configure && make -j9 && sudo make install-strip)
|
||||||
(cd libite-2.6.2 && ./configure && make -j9 && sudo make install-strip)
|
(cd libite-2.6.2 && ./configure && make -j9 && sudo make install-strip)
|
||||||
sudo ldconfig
|
sudo ldconfig
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v7
|
||||||
- name: Static Finit
|
- name: Static Finit
|
||||||
run: |
|
run: |
|
||||||
./autogen.sh
|
./autogen.sh
|
||||||
@@ -81,7 +80,7 @@ jobs:
|
|||||||
make -j1 check || (cat test/test-suite.log; false)
|
make -j1 check || (cat test/test-suite.log; false)
|
||||||
- name: Upload Test Results
|
- name: Upload Test Results
|
||||||
if: always()
|
if: always()
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: finit-test-${{ matrix.compiler }}
|
name: finit-test-${{ matrix.compiler }}
|
||||||
path: test/*.log
|
path: test/*.log
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ jobs:
|
|||||||
coverity:
|
coverity:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v7
|
||||||
- name: Fetch latest Coverity Scan MD5
|
- name: Fetch latest Coverity Scan MD5
|
||||||
id: var
|
id: var
|
||||||
env:
|
env:
|
||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
--post-data "token=$TOKEN&project=${COVERITY_PROJ}&md5=1" \
|
--post-data "token=$TOKEN&project=${COVERITY_PROJ}&md5=1" \
|
||||||
-O coverity-latest.tar.gz.md5
|
-O coverity-latest.tar.gz.md5
|
||||||
echo "md5=$(cat coverity-latest.tar.gz.md5)" | tee -a $GITHUB_OUTPUT
|
echo "md5=$(cat coverity-latest.tar.gz.md5)" | tee -a $GITHUB_OUTPUT
|
||||||
- uses: actions/cache@v4
|
- uses: actions/cache@v6
|
||||||
id: cache
|
id: cache
|
||||||
with:
|
with:
|
||||||
path: coverity-latest.tar.gz
|
path: coverity-latest.tar.gz
|
||||||
@@ -86,7 +86,7 @@ jobs:
|
|||||||
--form description="${PROJECT_NAME} $(git rev-parse HEAD)" \
|
--form description="${PROJECT_NAME} $(git rev-parse HEAD)" \
|
||||||
https://scan.coverity.com/builds?project=${COVERITY_PROJ}
|
https://scan.coverity.com/builds?project=${COVERITY_PROJ}
|
||||||
- name: Upload build.log
|
- name: Upload build.log
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: coverity-build.log
|
name: coverity-build.log
|
||||||
path: cov-int/build-log.txt
|
path: cov-int/build-log.txt
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- 4.x
|
- '[0-9]+.x'
|
||||||
paths:
|
paths:
|
||||||
- 'doc/**'
|
- 'doc/**'
|
||||||
- 'README.md'
|
- 'README.md'
|
||||||
@@ -30,7 +30,7 @@ jobs:
|
|||||||
version: ${{ steps.version.outputs.version }}
|
version: ${{ steps.version.outputs.version }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # Needed for git-revision-date-localized plugin
|
fetch-depth: 0 # Needed for git-revision-date-localized plugin
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ jobs:
|
|||||||
echo "version=$version" >> $GITHUB_OUTPUT
|
echo "version=$version" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v7
|
||||||
with:
|
with:
|
||||||
python-version: '3.x'
|
python-version: '3.x'
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ jobs:
|
|||||||
run: mkdocs build --clean
|
run: mkdocs build --clean
|
||||||
|
|
||||||
- name: Upload site artifact
|
- name: Upload site artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: site
|
name: site
|
||||||
path: site/
|
path: site/
|
||||||
@@ -72,13 +72,13 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Download site artifact
|
- name: Download site artifact
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v8
|
||||||
with:
|
with:
|
||||||
name: site
|
name: site
|
||||||
path: site/
|
path: site/
|
||||||
|
|
||||||
- name: Checkout pages repo
|
- name: Checkout pages repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
repository: finit-project/finit-project.github.io
|
repository: finit-project/finit-project.github.io
|
||||||
path: pages
|
path: pages
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ jobs:
|
|||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v7
|
||||||
- name: Installing dependencies ...
|
- name: Installing dependencies ...
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get -y update
|
sudo apt-get -y update
|
||||||
@@ -31,12 +31,17 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
ver=${GITHUB_REF#refs/tags/}
|
ver=${GITHUB_REF#refs/tags/}
|
||||||
echo "ver=${ver}" >> $GITHUB_OUTPUT
|
echo "ver=${ver}" >> $GITHUB_OUTPUT
|
||||||
if echo $ver | grep -qE '^[0-9]+\.[0-9]+(\.[0-9]+)?(-alpha|-beta|-rc)[0-9]*$'; then
|
stable='[0-9]+\.[0-9]+(\.[0-9]+)?'
|
||||||
|
if echo $ver | grep -qE "^${stable}(-alpha|-beta|-rc)[0-9]*$"; then
|
||||||
echo "pre=true" >> $GITHUB_OUTPUT
|
echo "pre=true" >> $GITHUB_OUTPUT
|
||||||
else
|
else
|
||||||
echo "pre=false" >> $GITHUB_OUTPUT
|
echo "pre=false" >> $GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
if echo $ver | grep -qE '^[0-9.]+\.[0-9.]+(\.[0-9]+)?$'; then
|
# Mark as latest release only if this is the highest stable
|
||||||
|
# tag, so a 4.x maintenance release doesn't outrank 5.x
|
||||||
|
newest=$(git ls-remote --tags --refs origin | awk -F/ '{print $NF}' \
|
||||||
|
| grep -E "^${stable}$" | sort -V | tail -1)
|
||||||
|
if [ "$ver" = "$newest" ]; then
|
||||||
echo "latest=true" >> $GITHUB_OUTPUT
|
echo "latest=true" >> $GITHUB_OUTPUT
|
||||||
else
|
else
|
||||||
echo "latest=false" >> $GITHUB_OUTPUT
|
echo "latest=false" >> $GITHUB_OUTPUT
|
||||||
@@ -64,7 +69,7 @@ jobs:
|
|||||||
mv ../*.tar.* artifacts/
|
mv ../*.tar.* artifacts/
|
||||||
- name: Upload Test Results
|
- name: Upload Test Results
|
||||||
if: always()
|
if: always()
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: finit-release-test-logs
|
name: finit-release-test-logs
|
||||||
path: finit-*/_build/sub/test/*.log
|
path: finit-*/_build/sub/test/*.log
|
||||||
|
|||||||
@@ -14,22 +14,31 @@ jobs:
|
|||||||
schedule:
|
schedule:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
run: ${{ steps.schedule.outputs.run }}
|
branches: ${{ steps.schedule.outputs.branches }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v7
|
||||||
- name: Check for any commits since last week
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Check for branches with no commits since last week
|
||||||
id: schedule
|
id: schedule
|
||||||
run: |
|
run: |
|
||||||
commits="$(git log --format=%H --since='1 week ago')"
|
branches=
|
||||||
if [ -z "$commits" ]; then
|
maint=$(git branch -r --format='%(refname:lstrip=3)' | grep -E '^[0-9]+\.x$')
|
||||||
echo "run=true" >> $GITHUB_OUTPUT
|
for branch in master $maint; do
|
||||||
else
|
commits="$(git log --format=%H --since='1 week ago' origin/$branch)"
|
||||||
echo "run=false" >> $GITHUB_OUTPUT
|
if [ -z "$commits" ]; then
|
||||||
fi
|
branches="$branches\"$branch\","
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "branches=[${branches%,}]" >> $GITHUB_OUTPUT
|
||||||
distcheck:
|
distcheck:
|
||||||
needs: schedule
|
needs: schedule
|
||||||
if: ${{ needs.schedule.outputs.run == 'true' }}
|
if: ${{ needs.schedule.outputs.branches != '[]' }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
branch: ${{ fromJSON(needs.schedule.outputs.branches) }}
|
||||||
|
fail-fast: false
|
||||||
steps:
|
steps:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -42,7 +51,9 @@ jobs:
|
|||||||
(cd libuev-2.4.1 && ./configure && make -j9 && sudo make install-strip)
|
(cd libuev-2.4.1 && ./configure && make -j9 && sudo make install-strip)
|
||||||
(cd libite-2.6.2 && ./configure && make -j9 && sudo make install-strip)
|
(cd libite-2.6.2 && ./configure && make -j9 && sudo make install-strip)
|
||||||
sudo ldconfig
|
sudo ldconfig
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
ref: ${{ matrix.branch }}
|
||||||
- name: Base run
|
- name: Base run
|
||||||
run: |
|
run: |
|
||||||
./autogen.sh
|
./autogen.sh
|
||||||
@@ -61,7 +72,7 @@ jobs:
|
|||||||
make -j1 distcheck || (cat $dir/test/test-suite.log; false)
|
make -j1 distcheck || (cat $dir/test/test-suite.log; false)
|
||||||
- name: Upload Test Results
|
- name: Upload Test Results
|
||||||
if: always()
|
if: always()
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: finit-weekly-test-logs
|
name: finit-weekly-test-logs-${{ matrix.branch }}
|
||||||
path: finit-*/_build/sub/test/*.log
|
path: finit-*/_build/sub/test/*.log
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
AC_INIT([Finit], [4.17], [https://github.com/finit-project/finit/issues],
|
AC_INIT([Finit], [4.18-pre], [https://github.com/finit-project/finit/issues],
|
||||||
[finit], [https://http://finit-project.github.io/])
|
[finit], [https://http://finit-project.github.io/])
|
||||||
AC_CONFIG_AUX_DIR(aux)
|
AC_CONFIG_AUX_DIR(aux)
|
||||||
AM_INIT_AUTOMAKE([1.11 foreign subdir-objects])
|
AM_INIT_AUTOMAKE([1.11 foreign subdir-objects])
|
||||||
|
|||||||
@@ -12,6 +12,14 @@ All relevant changes are documented in this file.
|
|||||||
e.g. `killed by SIGKILL` or `killed by SIGSEGV, core dumped`, in
|
e.g. `killed by SIGKILL` or `killed by SIGSEGV, core dumped`, in
|
||||||
place of the bare numeric `by signal: N`. Gives operators a much
|
place of the bare numeric `by signal: N`. Gives operators a much
|
||||||
stronger breadcrumb when a daemon dies unexpectedly
|
stronger breadcrumb when a daemon dies unexpectedly
|
||||||
|
- Service `user:` and `group:` names, including supplementary groups,
|
||||||
|
can now be up to 63 characters, up from 15. Longer names were
|
||||||
|
silently truncated before the lookup, so the service never started.
|
||||||
|
By Anees Rehman
|
||||||
|
- Shutdown now stops after the first successful remount of `/` read
|
||||||
|
only. The plain `mount -n -o remount,ro /`, which reads
|
||||||
|
`/etc/fstab`, is only used when both device-agnostic forms fail,
|
||||||
|
the same order as Debian's `umountroot`. By Anees Rehman
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|
||||||
@@ -27,6 +35,19 @@ All relevant changes are documented in this file.
|
|||||||
- Fix misspelled `SIGUNKOWN` returned by `sig_name()` for unknown
|
- Fix misspelled `SIGUNKOWN` returned by `sig_name()` for unknown
|
||||||
signal numbers, now spelled correctly as `SIGUNKNOWN`. Surfaced by
|
signal numbers, now spelled correctly as `SIGUNKNOWN`. Surfaced by
|
||||||
the new restart log above
|
the new restart log above
|
||||||
|
- Fix mode of existing `d`/`D` directories in tmpfiles, the chmod branch
|
||||||
|
never ran because the directory creation swallowed `EEXIST`. Mode and
|
||||||
|
owner of `d`/`D`, `e`, and `f`/`F` entries, and of the directories
|
||||||
|
`mksubsys()` creates for the dbus plugin, are now set through an open fd
|
||||||
|
and only when they differ, so an immutable directory like `/var/empty`
|
||||||
|
no longer warns on every boot. By Sam Brkopac
|
||||||
|
- Fix crash at config load for a `stop:` or `reload:` script written
|
||||||
|
with a timeout, e.g. `stop:5,/bin/true`, which took PID 1 down
|
||||||
|
- Fix a lost reload for a service paused mid-reload by a condition in
|
||||||
|
flux. A second reload arriving meanwhile re-parsed the unchanged .conf
|
||||||
|
and cleared the pending mark, so the service resumed without ever being
|
||||||
|
reloaded. Seen on Infix, where sshd kept its old listen addresses after
|
||||||
|
a change that landed as two reloads in a row
|
||||||
|
|
||||||
[4.17][] - 2026-04-28
|
[4.17][] - 2026-04-28
|
||||||
---------------------
|
---------------------
|
||||||
|
|||||||
+6
-2
@@ -121,15 +121,19 @@ void unmount_tmpfs(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void unmount_regular(void)
|
int unmount_regular(void)
|
||||||
{
|
{
|
||||||
const struct mntent *mnt;
|
const struct mntent *mnt;
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
while ((mnt = iterator("/proc/mounts", &fp))) {
|
while ((mnt = iterator("/proc/mounts", &fp))) {
|
||||||
if (!unmount(mnt->mnt_dir))
|
rc = unmount(mnt->mnt_dir);
|
||||||
|
if (!rc)
|
||||||
iterator_end(&fp); /* Restart iteration */
|
iterator_end(&fp); /* Restart iteration */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return !!rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+8
-4
@@ -1654,7 +1654,8 @@ static void parse_script(svc_t *svc, char *type, char *script, int *tmo, char *b
|
|||||||
script, errstr);
|
script, errstr);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
*tmo = (int)(sec * 1000);
|
if (tmo)
|
||||||
|
*tmo = (int)(sec * 1000);
|
||||||
} else {
|
} else {
|
||||||
path = script;
|
path = script;
|
||||||
if (tmo)
|
if (tmo)
|
||||||
@@ -2336,11 +2337,14 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
|||||||
if (cgroup)
|
if (cgroup)
|
||||||
parse_cgroup(svc, cgroup);
|
parse_cgroup(svc, cgroup);
|
||||||
|
|
||||||
/* New, recently modified or unchanged ... used on reload. */
|
/*
|
||||||
|
* New or modified since the last reload. The mark is cleared when
|
||||||
|
* the change has been applied, on start or reload, so one that is
|
||||||
|
* still set here is a change that has not been applied yet, e.g.
|
||||||
|
* the service is paused waiting for a condition. Leave it.
|
||||||
|
*/
|
||||||
if ((file && conf_changed(file)) || conf_changed(svc_getenv(svc)) || svc->args_dirty)
|
if ((file && conf_changed(file)) || conf_changed(svc_getenv(svc)) || svc->args_dirty)
|
||||||
svc_mark_dirty(svc);
|
svc_mark_dirty(svc);
|
||||||
else
|
|
||||||
svc_mark_clean(svc);
|
|
||||||
|
|
||||||
svc_enable(svc);
|
svc_enable(svc);
|
||||||
|
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ static struct sigmap {
|
|||||||
|
|
||||||
void mdadm_wait(void);
|
void mdadm_wait(void);
|
||||||
void unmount_tmpfs(void);
|
void unmount_tmpfs(void);
|
||||||
void unmount_regular(void);
|
int unmount_regular(void);
|
||||||
|
|
||||||
static void fs_swapoff(void)
|
static void fs_swapoff(void)
|
||||||
{
|
{
|
||||||
@@ -302,6 +302,7 @@ void do_shutdown(shutop_t op)
|
|||||||
struct sched_param sched_param = { .sched_priority = 99 };
|
struct sched_param sched_param = { .sched_priority = 99 };
|
||||||
int in_cont = in_container();
|
int in_cont = in_container();
|
||||||
int signo = SIGTERM;
|
int signo = SIGTERM;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (SHUTDOWN_DEBUG) cprintf("do_shutdown: entered, op=%d\n", op);
|
if (SHUTDOWN_DEBUG) cprintf("do_shutdown: entered, op=%d\n", op);
|
||||||
|
|
||||||
@@ -372,12 +373,13 @@ void do_shutdown(shutop_t op)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Unmount any tmpfs before unmounting swap ... */
|
/* Unmount any tmpfs before unmounting swap ... */
|
||||||
print(0, "Unmounting filesystems ...");
|
print(-1, "Unmounting filesystems ...");
|
||||||
unmount_tmpfs();
|
unmount_tmpfs();
|
||||||
fs_swapoff();
|
fs_swapoff();
|
||||||
|
|
||||||
/* ... unmount remaining regular file systems. */
|
/* ... unmount remaining regular file systems. */
|
||||||
unmount_regular();
|
rc = unmount_regular();
|
||||||
|
print(rc, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We sit on / so we must remount it ro, try all the things!
|
* We sit on / so we must remount it ro, try all the things!
|
||||||
@@ -386,9 +388,9 @@ void do_shutdown(shutop_t op)
|
|||||||
* - https://bugs.launchpad.net/ubuntu/+source/util-linux/+bug/29187
|
* - https://bugs.launchpad.net/ubuntu/+source/util-linux/+bug/29187
|
||||||
*/
|
*/
|
||||||
sync();
|
sync();
|
||||||
run("mount -n -o remount,ro -t dummytype dummydev /", NULL);
|
if (run("mount -n -o remount,ro -t dummytype dummydev /", NULL) &&
|
||||||
run("mount -n -o remount,ro dummydev /", NULL);
|
run("mount -n -o remount,ro dummydev /", NULL))
|
||||||
run("mount -n -o remount,ro /", "mount");
|
run("mount -n -o remount,ro /", "mount");
|
||||||
|
|
||||||
/* Call mdadm to mark any RAID array(s) as clean before halting. */
|
/* Call mdadm to mark any RAID array(s) as clean before halting. */
|
||||||
mdadm_wait();
|
mdadm_wait();
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ typedef enum {
|
|||||||
#define MAX_IDENT_LEN (MAX_ARG_LEN + MAX_ID_LEN + 1)
|
#define MAX_IDENT_LEN (MAX_ARG_LEN + MAX_ID_LEN + 1)
|
||||||
#define MAX_STR_LEN 64
|
#define MAX_STR_LEN 64
|
||||||
#define MAX_COND_LEN (MAX_ARG_LEN * 3)
|
#define MAX_COND_LEN (MAX_ARG_LEN * 3)
|
||||||
#define MAX_USER_LEN 16
|
#define MAX_USER_LEN MAX_ARG_LEN
|
||||||
#define MAX_NUM_SUPGROUPS 4
|
#define MAX_NUM_SUPGROUPS 4
|
||||||
#define MAX_NUM_FDS 64 /* Max number of I/O plugins */
|
#define MAX_NUM_FDS 64 /* Max number of I/O plugins */
|
||||||
#define MAX_NUM_SVC_ARGS 64
|
#define MAX_NUM_SVC_ARGS 64
|
||||||
|
|||||||
+50
-42
@@ -24,6 +24,7 @@
|
|||||||
#include "config.h" /* Generated by configure script */
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <ftw.h>
|
#include <ftw.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
@@ -586,67 +587,74 @@ static void tmpfiles(char *line)
|
|||||||
if (gid < 0)
|
if (gid < 0)
|
||||||
gid = 0;
|
gid = 0;
|
||||||
|
|
||||||
rc = makedir(path, mode ?: 0755);
|
if (!mode)
|
||||||
if (rc && errno == EEXIST)
|
mode = 0755;
|
||||||
rc = chmod(path, mode ?: 0755);
|
rc = makedir(path, mode);
|
||||||
if (chown(path, uid, gid))
|
if (!rc && dirperm(path, mode, uid, gid))
|
||||||
warn("Failed chown(%s, %d, %d)", path, uid, gid);
|
warn("Failed setting mode/owner on %s", path);
|
||||||
}
|
}
|
||||||
umask(omask);
|
umask(omask);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'e':
|
case 'e': {
|
||||||
|
int uid, gid;
|
||||||
|
|
||||||
if (glob(path, GLOB_NOESCAPE, NULL, &gl))
|
if (glob(path, GLOB_NOESCAPE, NULL, &gl))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
uid = parse_uid(user);
|
||||||
|
gid = parse_gid(group);
|
||||||
|
if (gid < 0)
|
||||||
|
gid = 0;
|
||||||
|
|
||||||
for (size_t i = 0; i < gl.gl_pathc; i++) {
|
for (size_t i = 0; i < gl.gl_pathc; i++) {
|
||||||
char *p = gl.gl_pathv[i];
|
char *p = gl.gl_pathv[i];
|
||||||
int uid, gid;
|
|
||||||
|
|
||||||
/* e only adjusts existing directories */
|
/* skip non-directories */
|
||||||
if (!fisdir(p))
|
if (dirperm(p, mode, uid, gid) && errno != ENOTDIR)
|
||||||
continue;
|
warn("Failed setting mode/owner on %s", p);
|
||||||
|
|
||||||
uid = parse_uid(user);
|
|
||||||
gid = parse_gid(group);
|
|
||||||
if (gid < 0)
|
|
||||||
gid = 0;
|
|
||||||
|
|
||||||
if (mode)
|
|
||||||
chmod(p, mode);
|
|
||||||
if (uid >= 0 && chown(p, uid, gid))
|
|
||||||
warn("Failed chown(%s, %d, %d)", p, uid, gid);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'f':
|
case 'f':
|
||||||
case 'F':
|
case 'F': {
|
||||||
mkparent(path, 0755);
|
int flags = O_WRONLY | O_CREAT | O_NOFOLLOW | O_CLOEXEC;
|
||||||
|
int fd, uid, gid;
|
||||||
|
|
||||||
if (type[1] == '+' || type[0] == 'F') {
|
if (type[1] == '+' || type[0] == 'F') {
|
||||||
/* f+/F will create or truncate the file */
|
flags |= O_TRUNC; /* create or truncate */
|
||||||
fp = fopen(path, "w+");
|
|
||||||
} else {
|
} else {
|
||||||
/* f will create the file if it doesn't exist */
|
if (!strc)
|
||||||
if (strc)
|
break; /* create only if missing */
|
||||||
fp = fopen(path, "w");
|
flags |= O_EXCL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fp) {
|
mkparent(path, 0755);
|
||||||
int uid, gid;
|
fd = open(path, flags, 0666);
|
||||||
|
if (fd < 0) {
|
||||||
write_arg(fp, arg);
|
if (errno != EEXIST)
|
||||||
rc = fclose(fp);
|
warn("Failed creating %s", path);
|
||||||
|
break;
|
||||||
/* Apply mode and ownership */
|
|
||||||
if (mode)
|
|
||||||
chmod(path, mode);
|
|
||||||
uid = parse_uid(user);
|
|
||||||
gid = parse_gid(group);
|
|
||||||
if (gid < 0)
|
|
||||||
gid = 0;
|
|
||||||
if (uid >= 0 && chown(path, uid, gid))
|
|
||||||
warn("Failed chown(%s, %d, %d)", path, uid, gid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fp = fdopen(fd, "w");
|
||||||
|
if (!fp) {
|
||||||
|
close(fd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_arg(fp, arg);
|
||||||
|
|
||||||
|
uid = parse_uid(user);
|
||||||
|
gid = parse_gid(group);
|
||||||
|
if (gid < 0)
|
||||||
|
gid = 0;
|
||||||
|
if (fdperm(fd, mode, uid, gid))
|
||||||
|
warn("Failed setting mode/owner on %s", path);
|
||||||
|
|
||||||
|
rc = fclose(fp);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'l': /* Finit extension, like 'L' but only if target exists */
|
case 'l': /* Finit extension, like 'L' but only if target exists */
|
||||||
if (!arg) {
|
if (!arg) {
|
||||||
paste(buf, sizeof(buf), "/usr/share/factory", path);
|
paste(buf, sizeof(buf), "/usr/share/factory", path);
|
||||||
|
|||||||
+40
-4
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <ctype.h> /* isprint() */
|
#include <ctype.h> /* isprint() */
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#ifdef HAVE_MNTENT_H
|
#ifdef HAVE_MNTENT_H
|
||||||
@@ -280,6 +281,43 @@ int getcgroup(char *buf, size_t len)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set mode and owner on an open fd, only what differs is touched, the
|
||||||
|
* file may be immutable. mode 0 skips the chmod, uid -1 the chown.
|
||||||
|
*/
|
||||||
|
int fdperm(int fd, mode_t mode, uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = fstat(fd, &st);
|
||||||
|
if (!rc && mode && (st.st_mode & 07777) != mode)
|
||||||
|
rc = fchmod(fd, mode);
|
||||||
|
if (!rc && uid != (uid_t)-1 && (st.st_uid != uid || st.st_gid != gid))
|
||||||
|
rc = fchown(fd, uid, gid);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Same for a directory that may already exist. Opened with
|
||||||
|
* O_NOFOLLOW | O_DIRECTORY, so the change lands on the directory
|
||||||
|
* itself and not on whatever a link at @path points to.
|
||||||
|
*/
|
||||||
|
int dirperm(const char *path, mode_t mode, uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
int fd, rc;
|
||||||
|
|
||||||
|
fd = open(path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
|
||||||
|
if (fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
rc = fdperm(fd, mode, uid, gid);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
int mksubsys(const char *dir, mode_t mode, char *user, char *group)
|
int mksubsys(const char *dir, mode_t mode, char *user, char *group)
|
||||||
{
|
{
|
||||||
mode_t omask;
|
mode_t omask;
|
||||||
@@ -295,10 +333,8 @@ int mksubsys(const char *dir, mode_t mode, char *user, char *group)
|
|||||||
gid = 0;
|
gid = 0;
|
||||||
|
|
||||||
rc = makedir(dir, mode);
|
rc = makedir(dir, mode);
|
||||||
if (rc && errno == EEXIST)
|
if (!rc && dirperm(dir, mode, uid, gid))
|
||||||
rc = chmod(dir, mode);
|
warn("Failed setting mode/owner on %s", dir);
|
||||||
if (chown(dir, uid, gid))
|
|
||||||
err(1, "Failed chown(%s, %d, %d)", dir, uid, gid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
umask(omask);
|
umask(omask);
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ int getgroup (const char *group);
|
|||||||
int getcuser (char *buf, size_t len);
|
int getcuser (char *buf, size_t len);
|
||||||
int getcgroup (char *buf, size_t len);
|
int getcgroup (char *buf, size_t len);
|
||||||
|
|
||||||
|
int fdperm (int fd, mode_t mode, uid_t uid, gid_t gid);
|
||||||
|
int dirperm (const char *path, mode_t mode, uid_t uid, gid_t gid);
|
||||||
int mksubsys (const char *dir, mode_t mode, char *user, char *group);
|
int mksubsys (const char *dir, mode_t mode, char *user, char *group);
|
||||||
|
|
||||||
int fnread (char *buf, size_t len, char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
|
int fnread (char *buf, size_t len, char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
|
||||||
|
|||||||
+4
-1
@@ -30,9 +30,10 @@ EXTRA_DIST += setup-sysroot.sh
|
|||||||
EXTRA_DIST += add-remove-dynamic-service.sh
|
EXTRA_DIST += add-remove-dynamic-service.sh
|
||||||
EXTRA_DIST += add-remove-dynamic-service-sub-config.sh
|
EXTRA_DIST += add-remove-dynamic-service-sub-config.sh
|
||||||
EXTRA_DIST += bootstrap-crash.sh
|
EXTRA_DIST += bootstrap-crash.sh
|
||||||
EXTRA_DIST += cond-start-task.sh
|
EXTRA_DIST += script-timeout.sh
|
||||||
EXTRA_DIST += crashing.sh
|
EXTRA_DIST += crashing.sh
|
||||||
EXTRA_DIST += dep-chain-reload.sh
|
EXTRA_DIST += dep-chain-reload.sh
|
||||||
|
EXTRA_DIST += reload-while-paused.sh
|
||||||
EXTRA_DIST += depserv.sh
|
EXTRA_DIST += depserv.sh
|
||||||
EXTRA_DIST += devmon.sh
|
EXTRA_DIST += devmon.sh
|
||||||
EXTRA_DIST += failing-sysv.sh
|
EXTRA_DIST += failing-sysv.sh
|
||||||
@@ -75,8 +76,10 @@ TESTS += add-remove-dynamic-service.sh
|
|||||||
TESTS += add-remove-dynamic-service-sub-config.sh
|
TESTS += add-remove-dynamic-service-sub-config.sh
|
||||||
TESTS += bootstrap-crash.sh
|
TESTS += bootstrap-crash.sh
|
||||||
TESTS += cond-start-task.sh
|
TESTS += cond-start-task.sh
|
||||||
|
TESTS += script-timeout.sh
|
||||||
TESTS += crashing.sh
|
TESTS += crashing.sh
|
||||||
TESTS += dep-chain-reload.sh
|
TESTS += dep-chain-reload.sh
|
||||||
|
TESTS += reload-while-paused.sh
|
||||||
TESTS += depserv.sh
|
TESTS += depserv.sh
|
||||||
TESTS += devmon.sh
|
TESTS += devmon.sh
|
||||||
TESTS += failing-sysv.sh
|
TESTS += failing-sysv.sh
|
||||||
|
|||||||
+17
-1
@@ -255,8 +255,12 @@ wdstart()
|
|||||||
|
|
||||||
wdkill()
|
wdkill()
|
||||||
{
|
{
|
||||||
|
[ -n "${wdpid:-}" ] || return 0
|
||||||
|
|
||||||
say "Stopping test watchdog, pid $wdpid"
|
say "Stopping test watchdog, pid $wdpid"
|
||||||
kill -KILL $wdpid
|
# Reap the sleep first, killing its subshell orphans it to PID 1.
|
||||||
|
pkill -KILL -P "$wdpid" 2>/dev/null || true
|
||||||
|
kill -KILL "$wdpid" 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
teardown()
|
teardown()
|
||||||
@@ -305,6 +309,18 @@ trap teardown EXIT
|
|||||||
SYSROOT="${SYSROOT:-$(pwd)/${TEST_DIR}/sysroot}"
|
SYSROOT="${SYSROOT:-$(pwd)/${TEST_DIR}/sysroot}"
|
||||||
export SYSROOT
|
export SYSROOT
|
||||||
|
|
||||||
|
# 'make check' refreshes the sysroot through the setup-chroot rule, but
|
||||||
|
# running a test script by hand does not, and then the test silently
|
||||||
|
# exercises whatever finit was installed last. Compare and refuse.
|
||||||
|
top_builddir="${top_builddir:-$TEST_DIR/..}"
|
||||||
|
sysroot_finit="$SYSROOT/sbin/finit"
|
||||||
|
built_finit="$top_builddir/src/finit"
|
||||||
|
[ -x "$top_builddir/src/.libs/finit" ] && built_finit="$top_builddir/src/.libs/finit"
|
||||||
|
|
||||||
|
if [ -x "$built_finit" ] && [ -e "$sysroot_finit" ] && ! cmp -s "$built_finit" "$sysroot_finit"; then
|
||||||
|
fail "Stale $sysroot_finit, run 'make -C test setup-chroot' or use 'make check'"
|
||||||
|
fi
|
||||||
|
|
||||||
TEST_TIMEOUT=300
|
TEST_TIMEOUT=300
|
||||||
|
|
||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
|
|||||||
Executable
+76
@@ -0,0 +1,76 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# A reload must not be lost on a service paused by a condition
|
||||||
|
#
|
||||||
|
# svc_s writes its PID file one second after a SIGHUP, so a service
|
||||||
|
# with <pid/svc_s> is paused for that second whenever svc_s reloads.
|
||||||
|
# svc_x counts the SIGHUPs it gets. Both .conf files are touched and
|
||||||
|
# two reloads are requested back to back, so the second one arrives
|
||||||
|
# while svc_x is paused with its own reload still pending. svc_x must
|
||||||
|
# get exactly one SIGHUP and keep its PID.
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
TEST_DIR=$(dirname "$0")
|
||||||
|
|
||||||
|
test_teardown()
|
||||||
|
{
|
||||||
|
say "Running test teardown."
|
||||||
|
run "rm -f $FINIT_RCSD/svc_s.conf $FINIT_RCSD/svc_x.conf /tmp/hup.sh /tmp/hup.log"
|
||||||
|
}
|
||||||
|
|
||||||
|
pidof()
|
||||||
|
{
|
||||||
|
texec initctl -j status "$1" | jq .pid
|
||||||
|
}
|
||||||
|
|
||||||
|
test_setup()
|
||||||
|
{
|
||||||
|
run "cat > /tmp/hup.sh" <<EOF
|
||||||
|
#!/bin/sh
|
||||||
|
trap 'echo HUP >> /tmp/hup.log' HUP
|
||||||
|
trap 'exit 0' TERM
|
||||||
|
while true; do
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
EOF
|
||||||
|
run "cat > $FINIT_RCSD/svc_s.conf" <<EOF
|
||||||
|
service log:stdout notify:pid pid:!/run/service.pid name:svc_s service.sh -- Slow to reassert
|
||||||
|
EOF
|
||||||
|
run "cat > $FINIT_RCSD/svc_x.conf" <<EOF
|
||||||
|
service log:stdout <pid/svc_s> name:svc_x /bin/sh /tmp/hup.sh -- Paused while svc_s reloads
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
. "$TEST_DIR/lib/setup.sh"
|
||||||
|
|
||||||
|
sep "Configuration"
|
||||||
|
run "cat $FINIT_RCSD/svc_s.conf"
|
||||||
|
run "cat $FINIT_RCSD/svc_x.conf"
|
||||||
|
|
||||||
|
say "Reload Finit to start both services"
|
||||||
|
run "initctl reload"
|
||||||
|
retry 'assert_status "svc_x" "running"' 10 1
|
||||||
|
|
||||||
|
pid_x=$(pidof svc_x)
|
||||||
|
say "svc_x PID before: $pid_x"
|
||||||
|
|
||||||
|
sep "Touch both, reload twice"
|
||||||
|
run "rm -f /tmp/hup.log"
|
||||||
|
run "initctl touch svc_s.conf"
|
||||||
|
run "initctl touch svc_x.conf"
|
||||||
|
run "initctl reload"
|
||||||
|
run "initctl reload"
|
||||||
|
|
||||||
|
say "Wait for services to settle"
|
||||||
|
retry 'assert_status "svc_x" "running"' 15 1
|
||||||
|
run "initctl status"
|
||||||
|
|
||||||
|
# shellcheck disable=SC2016
|
||||||
|
retry 'assert "svc_x got its SIGHUP" "$(texec sh -c "cat /tmp/hup.log 2>/dev/null | wc -l")" -eq 1' 10 1
|
||||||
|
|
||||||
|
new_pid_x=$(pidof svc_x)
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
assert "svc_x was not restarted" $new_pid_x -eq $pid_x
|
||||||
|
|
||||||
|
return 0
|
||||||
Executable
+36
@@ -0,0 +1,36 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# A timeout on a stop: or reload: script must not take PID 1 with it.
|
||||||
|
# Those two hooks passed a NULL timeout pointer to parse_script(),
|
||||||
|
# which wrote through it whenever the script was prefixed with a
|
||||||
|
# valid number. Only a valid number reached the store, so
|
||||||
|
# 'stop:abc,/bin/true' was harmless while 'stop:5,/bin/true' was not.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
TEST_DIR=$(dirname "$0")
|
||||||
|
|
||||||
|
test_teardown()
|
||||||
|
{
|
||||||
|
say "Running test teardown."
|
||||||
|
run "rm -f $FINIT_CONF"
|
||||||
|
}
|
||||||
|
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
. "$TEST_DIR/lib/setup.sh"
|
||||||
|
|
||||||
|
# shellcheck disable=SC2154
|
||||||
|
assert_alive()
|
||||||
|
{
|
||||||
|
assert "Finit survived $1" "$(kill -0 "$finit_pid" 2>/dev/null && echo yes)" = "yes"
|
||||||
|
}
|
||||||
|
|
||||||
|
for hook in stop reload post pre; do
|
||||||
|
say "Timeout on a $hook: script"
|
||||||
|
run "echo 'service $hook:5,/bin/true service.sh -- Timeout test' > $FINIT_CONF"
|
||||||
|
run "initctl reload" || true
|
||||||
|
assert_alive "$hook:5,/bin/true"
|
||||||
|
done
|
||||||
|
|
||||||
|
say 'The service still runs afterwards'
|
||||||
|
run "echo 'service stop:5,/bin/true service.sh -- Timeout test' > $FINIT_CONF"
|
||||||
|
run "initctl reload"
|
||||||
|
retry 'assert_num_children 1 service.sh'
|
||||||
Reference in New Issue
Block a user