Wait for an arbitrary process.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

183 lines
4.2 KiB

/*
* wait4pid - Wait for an arbitrary process
* Copyright (C) 2013 Damien Goutte-Gattat
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_LINUX_NETLINK_H
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/connector.h>
#include <linux/cn_proc.h>
int sock = 0;
int listener_set = 0;
static int
set_proc_listen(int sock, int enable)
{
struct nlmsghdr *hdr;
struct __attribute__ ((__packed__)) payload_t {
struct cn_msg msg;
enum proc_cn_mcast_op op;
} *payload;
char buf[NLMSG_SPACE(sizeof(struct payload_t))];
hdr = (struct nlmsghdr *)buf;
hdr->nlmsg_type = NLMSG_DONE;
hdr->nlmsg_flags = NLM_F_REQUEST;
hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*payload));
hdr->nlmsg_pid = getpid();
payload = (struct payload_t *) NLMSG_DATA(hdr);
payload->msg.id.idx = CN_IDX_PROC;
payload->msg.id.val = CN_VAL_PROC;
payload->op = enable ? PROC_CN_MCAST_LISTEN : PROC_CN_MCAST_IGNORE;
return send(sock, hdr, NLMSG_SPACE(sizeof(*payload)), 0);
}
static void
wait4pid_close(void)
{
if ( listener_set ) {
set_proc_listen(sock, 0);
listener_set = 0;
}
if ( sock ) {
close(sock);
sock = 0;
}
}
static int
wait4pid_init(void)
{
struct sockaddr_nl sa;
if ( (sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR)) == -1 )
return -1;
atexit(wait4pid_close);
memset(&sa, 0, sizeof(sa));
sa.nl_family = AF_NETLINK;
sa.nl_groups = CN_IDX_PROC;
sa.nl_pid = getpid();
if ( bind(sock, (struct sockaddr *)&sa, sizeof(sa)) == -1 )
return -1;
if ( setgid(getgid()) == -1 || setuid(getuid()) == -1 )
return -1;
if ( set_proc_listen(sock, 1) == -1 )
return -1;
return 0;
}
static int
do_recv(int sock, void *buf, size_t len, int flags)
{
int ret;
do {
ret = recv(sock, buf, len, flags);
} while ( ret == -1 && errno == EINTR );
return ret;
}
int
wait4all(pid_t *pids, size_t len)
{
int ec, nproc, i;
struct __attribute__ ((__packed__ )) payload_t {
struct cn_msg msg;
struct proc_event evt;
} *payload;
char buf[NLMSG_SPACE(sizeof(struct payload_t))];
if ( ! listener_set && wait4pid_init() == -1 )
return -1;
for ( i = 0; i < len; i++ ) {
if ( kill(pids[i], 0) == -1 && errno == ESRCH )
return -1;
}
nproc = len;
while ( nproc > 0 ) {
if ( do_recv(sock, buf, sizeof(buf), 0) <= 0 )
return -1;
payload = (struct payload_t *) NLMSG_DATA(buf);
if ( payload->evt.what != PROC_EVENT_EXIT )
continue;
for ( i = 0; i < len; i++ ) {
if ( pids[i] != -1
&& pids[i] == payload->evt.event_data.exit.process_pid ) {
pids[i] = -1;
nproc -= 1;
if ( i == len - 1 )
ec = payload->evt.event_data.exit.exit_code / 256;
}
}
}
return ec;
}
#else /* HAVE_LINUX_NETLINK_H */
#include <time.h>
#include <signal.h>
int
wait4all(pid_t *pids, size_t len)
{
int nproc, i;
struct timespec ts = { 1, 0 };
nproc = len;
while ( nproc > 0 ) {
for ( i = 0; i < len; i++ ) {
if ( pids[i] == -1 )
continue;
if ( kill(pids[i], 0) == -1 && errno == ESRCH ) {
pids[i] = -1;
nproc -= 1;
}
}
nanosleep(&ts, NULL);
}
return 0;
}
#endif /* ! HAVE_LINUX_NETLINK_H */