From 7f0aa026e16989584f4d79e50fbe75f5558a00f8 Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Wed, 2 Jul 2025 21:57:16 +0000 Subject: s6-rc-repo-init: better error messages Signed-off-by: Laurent Bercot --- src/include/s6-rc/repo.h | 2 +- src/libs6rc/s6rc_repo_sync.c | 64 +++++++++++++++++++++++++++++++++++++++----- src/repo/s6-rc-repo-init.c | 23 ++++++++++++---- 3 files changed, 77 insertions(+), 12 deletions(-) diff --git a/src/include/s6-rc/repo.h b/src/include/s6-rc/repo.h index 874354f..4ae6077 100644 --- a/src/include/s6-rc/repo.h +++ b/src/include/s6-rc/repo.h @@ -6,6 +6,6 @@ #include extern int s6rc_repo_cleanup (char const *) ; -extern int s6rc_repo_sync (char const *, char const *const *, size_t) ; +extern int s6rc_repo_sync (char const *, char const *const *, size_t, unsigned int) ; #endif diff --git a/src/libs6rc/s6rc_repo_sync.c b/src/libs6rc/s6rc_repo_sync.c index 7ece55f..963ec3c 100644 --- a/src/libs6rc/s6rc_repo_sync.c +++ b/src/libs6rc/s6rc_repo_sync.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include @@ -23,19 +25,28 @@ static inline void cleanup (char const *fn) errno = e ; } -int s6rc_repo_sync (char const *repo, char const *const *sources, size_t sourceslen) +int s6rc_repo_sync (char const *repo, char const *const *sources, size_t sourceslen, unsigned int verbosity) { + stralloc sa = STRALLOC_ZERO ; size_t repolen = strlen(repo) ; char newdir[repolen + 24] ; memcpy(newdir, repo, repolen) ; memcpy(newdir + repolen, "/.everything:cur:XXXXXX", 24) ; - if (!mkdtemp(newdir)) return 0 ; + if (!mkdtemp(newdir)) + { + strerr_warnfu2sys("mkdtemp ", newdir) ; + return 0 ; + } for (size_t i = 0 ; i < sourceslen ; i++) { size_t srclen = strlen(sources[i]) ; DIR *dir = opendir(sources[i]) ; - if (!dir) goto err ; + if (!dir) + { + strerr_warnfu2sys("opendir ", sources[i]) ; + goto err ; + } for (;;) { size_t len ; @@ -46,6 +57,7 @@ int s6rc_repo_sync (char const *repo, char const *const *sources, size_t sources if (d->d_name[0] == '.') continue ; len = strlen(d->d_name) ; { + struct stat st ; char dst[repolen + 25 + len] ; char src[srclen + len + 2] ; memcpy(dst, newdir, repolen + 23) ; @@ -54,14 +66,52 @@ int s6rc_repo_sync (char const *repo, char const *const *sources, size_t sources memcpy(src, sources[i], srclen) ; src[srclen] = '/' ; memcpy(src + srclen + 1, d->d_name, len + 1) ; - if (symlink(src, dst) == -1) break ; + if (stat(src, &st) == -1) + { + if (verbosity) strerr_warnwu2sys("stat ", src) ; + continue ; + } + if (!S_ISDIR(st.st_mode)) + { + errno = ENOTDIR ; + if (verbosity) strerr_warnwu2sys("link ", src) ; + continue ; + } + if (symlink(src, dst) == -1) + { + if (errno != EEXIST) + { + strerr_warnfu4sys("symlink ", src, " to ", dst) ; + dir_close(dir) ; + goto err ; + } + if (verbosity) + { + sa.len = 0 ; + if (!sareadlink(&sa, dst) || !stralloc_0(&sa)) + { + strerr_warnwu2sys("readlink ", dst) ; + errno = EEXIST ; + strerr_warnwu4sys("symlink ", src, " to ", dst) ; + } + else + strerr_warnwu6x("symlink ", src, " to ", dst, ": service is already provided by ", sa.s) ; + } + } } } dir_close(dir) ; - if (errno) goto err ; + if (errno) + { + strerr_warnfu2sys("readdir ", sources[i]) ; + goto err ; + } } - if (chmod(newdir, 02755) == -1) goto err ; + if (chmod(newdir, 02755) == -1) + { + goto err ; + } { char curdir[repolen + 13] ; @@ -70,9 +120,11 @@ int s6rc_repo_sync (char const *repo, char const *const *sources, size_t sources if (!atomic_symlink(newdir + repolen + 1, curdir, "tmp")) goto err ; } + stralloc_free(&sa) ; return s6rc_repo_cleanup(repo) ; err: + stralloc_free(&sa) ; cleanup(newdir) ; return 0 ; } diff --git a/src/repo/s6-rc-repo-init.c b/src/repo/s6-rc-repo-init.c index d358e1a..14c34d7 100644 --- a/src/repo/s6-rc-repo-init.c +++ b/src/repo/s6-rc-repo-init.c @@ -41,22 +41,35 @@ static gol_bool const rgolb[1] = { .so = 'f', .lo = "force", .clear = 0, .set = 1 << GOLB_FORCE } } ; -static gol_arg const rgola[1] = +enum gola_e { - { .so = 'r', .lo = "repodir", .i = 0 } + GOLA_VERBOSITY, + GOLA_REPODIR, + GOLA_N +} ; + +static gol_arg const rgola[2] = +{ + { .so = 'v', .lo = "verbosity", .i = GOLA_VERBOSITY }, + { .so = 'r', .lo = "repodir", .i = GOLA_REPODIR } } ; int main (int argc, char const *const *argv) { size_t repolen ; char const *repo = S6RC_REPO_BASE ; + unsigned int verbosity = 1 ; + mode_t m ; + char const *wgola[2] = { 0 } ; uint64_t wgolb = 0 ; unsigned int golc ; - mode_t m ; PROG = "s6-rc-repo-init" ; - golc = gol_main(argc, argv, rgolb, 1, rgola, 1, &wgolb, &repo) ; + golc = gol_main(argc, argv, rgolb, 1, rgola, 2, &wgolb, wgola) ; argc -= golc ; argv += golc ; + if (wgola[GOLA_VERBOSITY] && !uint0_scan(wgola[GOLA_VERBOSITY], &verbosity)) + strerr_dief1x(100, "verbosity needs to be an unsigned integer") ; + if (wgola[GOLA_REPODIR]) repo = wgola[GOLA_REPODIR] ; if (repo[0] != '/') strerr_dief2x(100, repo, " is not an absolute path") ; for (unsigned int i = 0 ; i < argc ; i++) @@ -103,7 +116,7 @@ int main (int argc, char const *const *argv) umask(m) ; - if (!s6rc_repo_sync(repotmp, argv, argc)) + if (!s6rc_repo_sync(repotmp, argv, argc, verbosity)) { cleanup(repotmp) ; strerr_diefu2sys(111, "sync ", repotmp) ; -- cgit v1.3.1