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.
 
 
 

195 lines
4.6 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 <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;
}
int
wait4pid(pid_t pid)
{
int ec;
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;
while ( 1 ) {
if ( (ec = recv(sock, buf, sizeof(buf), 0)) <= 0 ) {
if ( ec == -1 && errno == EINTR )
continue;
else
return -1;
}
payload = (struct payload_t *) NLMSG_DATA(buf);
if ( payload->evt.what == PROC_EVENT_EXIT
&& payload->evt.event_data.exit.process_pid == pid ) {
ec = payload->evt.event_data.exit.exit_code / 256;
break;
}
}
return ec;
}
int
wait4all(pid_t *pids, size_t len)
{
int ec, nproc;
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;
nproc = len;
while ( nproc > 0 ) {
int ret, i;
if ( (ret = recv(sock, buf, sizeof(buf), 0)) <= 0 ) {
if ( ret == -1 && errno == EINTR )
continue;
else
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 <string.h>
#include <sys/stat.h>
#include <unistd.h>
int
wait4pid(pid_t pid)
{
struct stat st_buf;
char path[20];
snprintf(path, sizeof(path), "/proc/%d", pid);
while ( stat(path, &st_buf) != -1 )
sleep(1);
/* Anything else than ENOENT is an error. */
return errno == ENOENT ? 0 : -1;
}
#endif /* ! HAVE_LINUX_NETLINK_H */