Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
com.redhat.resolver/src/service.c
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
154 lines (115 sloc)
4.26 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "service.h" | |
#include "util.h" | |
#include <assert.h> | |
#include <errno.h> | |
#include <fcntl.h> | |
#include <string.h> | |
#include <signal.h> | |
#include <sys/prctl.h> | |
#include <sys/stat.h> | |
#include <unistd.h> | |
long service_new(Service **servicep, | |
const char *address, | |
const char **interfaces, unsigned long n_interfaces, | |
const char *executable, | |
uid_t uid, | |
gid_t gid, | |
bool activate, | |
const char *config) { | |
_cleanup_(service_freep) Service *service = NULL; | |
service = calloc(1, sizeof(Service)); | |
service->pid = -1; | |
service->address = strdup(address); | |
service->interfaces = calloc(n_interfaces, sizeof(char *)); | |
for (unsigned long i = 0; i < n_interfaces; i += 1) | |
service->interfaces[i] = strdup(interfaces[i]); | |
service->n_interfaces = n_interfaces; | |
if (executable) { | |
int listen_fd; | |
service->executable = strdup(executable); | |
service->argv = calloc(3, sizeof(char *)); | |
service->argv[0] = strdup(service->executable); | |
asprintf(&service->argv[1], "--varlink=%s", service->address); | |
if (config) { | |
service->config = strdup(config); | |
asprintf(&service->argv[2], "--config=%s", service->config); | |
} | |
listen_fd = varlink_listen(service->address, &service->path_to_unlink); | |
if (listen_fd < 0) | |
return listen_fd; | |
service->listen_fd = listen_fd; | |
} | |
service->activate_at_startup = activate; | |
*servicep = service; | |
service = NULL; | |
return 0; | |
} | |
long service_reset(Service *service) { | |
int listen_fd; | |
close(service->listen_fd); | |
service->listen_fd = -1; | |
if (service->path_to_unlink) { | |
unlink(service->path_to_unlink); | |
free(service->path_to_unlink); | |
service->path_to_unlink = NULL; | |
} | |
listen_fd = varlink_listen(service->address, &service->path_to_unlink); | |
if (listen_fd < 0) | |
return listen_fd; | |
service->listen_fd = listen_fd; | |
return 0; | |
} | |
Service *service_free(Service *service) { | |
if (service->pid >= 0) | |
kill(service->pid, SIGTERM); | |
if (service->listen_fd >= 0) | |
close(service->listen_fd); | |
if (service->path_to_unlink) { | |
unlink(service->path_to_unlink); | |
free(service->path_to_unlink); | |
} | |
for (unsigned long i = 0; i < service->n_interfaces; i += 1) | |
free(service->interfaces[i]); | |
free(service->interfaces); | |
for (char *arg = *service->argv; arg ; arg++) | |
free(arg); | |
free(service->argv); | |
free(service->address); | |
free(service->executable); | |
free(service->config); | |
free(service); | |
return NULL; | |
} | |
void service_freep(Service **servicep) { | |
if (*servicep) | |
service_free(*servicep); | |
} | |
long service_activate(Service *service, sigset_t *mask) { | |
char s[32]; | |
assert(service->executable); | |
assert(service->pid < 0); | |
service->pid = fork(); | |
if (service->pid < 0) | |
return -errno; | |
if (service->pid > 0) | |
return 0; | |
sigprocmask(SIG_SETMASK, mask, NULL); | |
sprintf(s, "%d", getpid()); | |
setenv("LISTEN_PID", s, true); | |
setenv("LISTEN_FDS", "1", true); | |
/* Move activator fd to fd 3. All other fds have CLOEXEC set. */ | |
if (dup2(service->listen_fd, 3) < 0) | |
return -errno; | |
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) | |
return -errno; | |
if (service->executable[0] == '/' && chdir("/") < 0) | |
return -errno; | |
if (setsid() < 0) | |
return -errno; | |
if (service->gid > 0 && setresgid(service->gid, service->gid, service->gid) < 0) | |
return -errno; | |
if (service->uid > 0 && setresuid(service->uid, service->uid, service->uid) < 0) | |
return -errno; | |
execve(service->argv[0], service->argv, environ); | |
_exit(errno); | |
} |