commit: dec0f2d45ce2f5eb98e0555c4a94334b289d23ee
Author: Mike Gilbert <floppym <AT> gentoo <DOT> org>
AuthorDate: Sun Feb 22 01:56:42 2026 +0000
Commit: Mike Gilbert <floppym <AT> gentoo <DOT> org>
CommitDate: Tue Feb 24 03:34:36 2026 +0000
URL: https://gitweb.gentoo.org/proj/install-xattr.git/commit/?id=dec0f2d4
Replace fork/exec with posix_spawn
Signed-off-by: Mike Gilbert <floppym <AT> gentoo.org>
install-xattr.c | 148 +++++++++++++++++++++++++++++---------------------------
1 file changed, 78 insertions(+), 70 deletions(-)
diff --git a/install-xattr.c b/install-xattr.c
index 294dfe2..cbc4277 100644
--- a/install-xattr.c
+++ b/install-xattr.c
@@ -29,6 +29,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
+#include <spawn.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -179,6 +180,21 @@ copyxattr(const char *source, const char *target)
}
+extern char **environ;
+
+static pid_t
+spawn(char *path, char *argv[])
+{
+ pid_t pid;
+ int r = posix_spawn(&pid, path, NULL, NULL, argv, environ);
+ if (r) {
+ errno = r;
+ return -1;
+ }
+ return pid;
+}
+
+
int
main(int argc, char* argv[])
{
@@ -292,82 +308,74 @@ main(int argc, char* argv[])
if (!oldpwd || chdir(oldpwd) != 0)
err(1, "failed to chdir %s", oldpwd);
- switch (fork()) {
- case -1:
- err(1, "fork() failed");
+ argv[0] = getenv("REAL_INSTALL") ?: REAL_INSTALL;
+
+ if (spawn(argv[0], argv) < 0)
+ err(1, "failed to spawn install");
- case 0: {
- argv[0] = getenv("REAL_INSTALL") ?: REAL_INSTALL;
- execv(argv[0], argv);
- err(1, "execv() failed");
+ wait(&status);
+
+ /* Are there enough files/directories on the cmd line to
+ * proceed? This can happen if install is called with no
+ * arguments or with just --help. In which case there is
+ * nothing for the parent to do.
+ */
+ if (first >= last)
+ goto done;
+
+ /* If all the targets are directories, do nothing. */
+ if (opts_directory)
+ goto done;
+
+ if (!opts_target_directory) {
+ target = argv_copy[last];
+ if (stat(target, &s) != 0) {
+ err(1, "failed to stat %s", target);
+ return EXIT_FAILURE;
}
+ target_is_directory = S_ISDIR(s.st_mode);
+ } else {
+ /* target was set above with the -t option */
+ target_is_directory = 1;
+ }
- default:
- wait(&status);
-
- /* Are there enough files/directories on the cmd line to
- * proceed? This can happen if install is called with
no
- * arguments or with just --help. In which case there
is
- * nothing for the parent to do.
- */
- if (first >= last)
- goto done;
-
- /* If all the targets are directories, do nothing. */
- if (opts_directory)
- goto done;
-
- if (!opts_target_directory) {
- target = argv_copy[last];
- if (stat(target, &s) != 0) {
- err(1, "failed to stat %s", target);
- return EXIT_FAILURE;
- }
- target_is_directory = S_ISDIR(s.st_mode);
- } else {
- /* target was set above with the -t option */
- target_is_directory = 1;
+ if (target_is_directory) {
+ /* If -t was passed, then the last argv *is*
+ * a file, so we include it for copyxattr().
+ */
+ if (opts_target_directory)
+ last++;
+
+ for (i = first; i < last; i++) {
+ if (stat(argv_copy[i], &s) != 0) {
+ err(1, "failed to stat %s", argv_copy[i]);
+ return EXIT_FAILURE;
}
+ /* We reproduce install's behavior and skip
+ * all extra directories on the command line
+ * that are not the final target directory.
+ */
+ if (S_ISDIR(s.st_mode))
+ continue;
- if (target_is_directory) {
- /* If -t was passed, then the last argv *is*
- * a file, so we include it for copyxattr().
- */
- if (opts_target_directory)
- last++;
-
- for (i = first; i < last; i++) {
- if (stat(argv_copy[i], &s) != 0) {
- err(1, "failed to stat %s",
argv_copy[i]);
- return EXIT_FAILURE;
- }
- /* We reproduce install's behavior and
skip
- * all extra directories on the command
line
- * that are not the final target
directory.
- */
- if (S_ISDIR(s.st_mode))
- continue;
-
- path = path_join(target,
basename(argv_copy[i]));
- copyxattr(argv_copy[i], path);
- free(path);
- }
- } else
- copyxattr(argv_copy[first], target);
+ path = path_join(target, basename(argv_copy[i]));
+ copyxattr(argv_copy[i], path);
+ free(path);
+ }
+ } else
+ copyxattr(argv_copy[first], target);
done:
- /* Do the right thing and pass the signal back up. See:
- * http://www.cons.org/cracauer/sigint.html
- */
- if (WIFSIGNALED(status)) {
- int signum = WTERMSIG(status);
- kill(getpid(), signum);
- return 128 + signum;
- } else if (WIFEXITED(status))
- return WEXITSTATUS(status);
- else
- return EXIT_FAILURE; /* We should never get
here. */
-
- }
+ /* Do the right thing and pass the signal back up. See:
+ * http://www.cons.org/cracauer/sigint.html
+ */
+ if (WIFSIGNALED(status)) {
+ int signum = WTERMSIG(status);
+ kill(getpid(), signum);
+ return 128 + signum;
+ } else if (WIFEXITED(status))
+ return WEXITSTATUS(status);
+ else
+ return EXIT_FAILURE; /* We should never get here. */
}