net_server: Replace fork+exec with posix_spawn.

Uses POSIX_SPAWN_SETSID, so needs the previous commit to work.
This commit is contained in:
Augustin Cavalier
2026-02-27 10:16:21 -05:00
parent 27e95c346a
commit 23ef8b89c6
+44 -37
View File
@@ -13,12 +13,14 @@
#include <errno.h> #include <errno.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <spawn.h>
#include <stdlib.h> #include <stdlib.h>
#include <strings.h> #include <strings.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <Autolock.h> #include <Autolock.h>
#include <AutoDeleter.h>
#include <NetworkAddress.h> #include <NetworkAddress.h>
#include <NetworkSettings.h> #include <NetworkSettings.h>
@@ -426,51 +428,56 @@ Services::_LaunchService(struct service& service, int socket)
return errno; return errno;
} }
pid_t child = fork(); posix_spawnattr_t attr;
if (child == 0) { status_t status = posix_spawnattr_init(&attr);
setsid(); if (status != 0)
// make sure we're in our own session, and don't accidently quit return status;
// the net_server CObjectDeleter<posix_spawnattr_t, int, posix_spawnattr_destroy>
attrDeleter(&attr);
if (socket != -1) { posix_spawn_file_actions_t fileActions;
// We're the child, replace standard input/output status = posix_spawn_file_actions_init(&fileActions);
dup2(socket, STDIN_FILENO); if (status != 0)
dup2(socket, STDOUT_FILENO); return status;
dup2(socket, STDERR_FILENO); CObjectDeleter<posix_spawn_file_actions_t, int, posix_spawn_file_actions_destroy>
close(socket); actionsDeleter(&fileActions);
}
// build argument array // make sure the child has its own session, and doesn't accidentally quit
// the net_server
posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSID);
const char** args = (const char**)malloc( // replace standard input/output in the child
(service.arguments.size() + 1) * sizeof(char*)); posix_spawn_file_actions_adddup2(&fileActions, socket, STDIN_FILENO);
if (args == NULL) posix_spawn_file_actions_adddup2(&fileActions, socket, STDOUT_FILENO);
exit(1); posix_spawn_file_actions_adddup2(&fileActions, socket, STDERR_FILENO);
posix_spawn_file_actions_addclose(&fileActions, socket);
for (size_t i = 0; i < service.arguments.size(); i++) { // build argument array
args[i] = service.arguments[i].c_str(); const char** args = (const char**)malloc(
} (service.arguments.size() + 1) * sizeof(char*));
args[service.arguments.size()] = NULL; if (args == NULL)
return ENOMEM;
MemoryDeleter argsDeleter(args);
if (execv(service.arguments[0].c_str(), (char* const*)args) < 0) { for (size_t i = 0; i < service.arguments.size(); i++)
free(args); args[i] = service.arguments[i].c_str();
exit(1); args[service.arguments.size()] = NULL;
}
// we'll never trespass here // spawn
} else { pid_t child;
// the server does not need the socket anymore status = posix_spawn(&child, service.arguments[0].c_str(),
if (socket != -1) &fileActions, &attr, (char* const*)args, NULL);
close(socket);
if (child < 0) { if (status != 0 || child < 0) {
fprintf(stderr, "Could not start service %s\n", fprintf(stderr, "Could not start service %s\n",
service.name.c_str()); service.name.c_str());
} else if (service.stand_alone) } else if (service.stand_alone)
service.process = child; service.process = child;
}
// the server does not need the socket anymore
if (socket != -1)
close(socket);
// TODO: make sure child started successfully...
return B_OK; return B_OK;
} }