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. */
 }

Reply via email to