1 /******************************************************************************/ 2 /* */ 3 /* Copyright (c) 2008 FUJITSU LIMITED */ 4 /* */ 5 /* This program is free software; you can redistribute it and/or modify */ 6 /* it under the terms of the GNU General Public License as published by */ 7 /* the Free Software Foundation; either version 2 of the License, or */ 8 /* (at your option) any later version. */ 9 /* */ 10 /* This program is distributed in the hope that it will be useful, */ 11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ 13 /* the GNU General Public License for more details. */ 14 /* */ 15 /* You should have received a copy of the GNU General Public License */ 16 /* along with this program; if not, write to the Free Software */ 17 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 18 /* */ 19 /* Author: Li Zefan <lizf (at) cn.fujitsu.com> */ 20 /* */ 21 /******************************************************************************/ 22 23 #include <sys/socket.h> 24 #include <sys/poll.h> 25 #include <sys/types.h> 26 #include <unistd.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <errno.h> 31 #include <signal.h> 32 #include <linux/types.h> 33 #include <linux/netlink.h> 34 35 #ifndef NETLINK_CONNECTOR 36 37 int main(void) 38 { 39 return 2; 40 } 41 42 #else 43 44 #include <linux/connector.h> 45 46 #ifndef CN_IDX_PROC 47 48 int main(void) 49 { 50 return 2; 51 } 52 53 #else 54 55 #define _LINUX_TIME_H 56 #include <linux/cn_proc.h> 57 58 #define PEC_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct proc_event)) 59 #define PEC_CTRL_MSG_SIZE (sizeof(struct cn_msg) + sizeof(enum proc_cn_mcast_op)) 60 61 #define MAX_MSG_SIZE 256 62 63 static __u32 seq; 64 65 static int exit_flag; 66 static struct sigaction sigint_action; 67 68 struct nlmsghdr *nlhdr; 69 70 /* 71 * Handler for signal int. Set exit flag. 72 * 73 * @signo: the signal number, not used 74 */ 75 static void sigint_handler(int __attribute__ ((unused)) signo) 76 { 77 exit_flag = 1; 78 } 79 80 /* 81 * Send netlink package. 82 * 83 * @sd: socket descripor 84 * @to: the destination sockaddr 85 * @cnmsg: the pec control message 86 */ 87 static int netlink_send(int sd, struct sockaddr_nl *to, struct cn_msg *cnmsg) 88 { 89 int ret; 90 struct iovec iov; 91 struct msghdr msg; 92 93 memset(nlhdr, 0, NLMSG_SPACE(MAX_MSG_SIZE)); 94 95 nlhdr->nlmsg_seq = seq++; 96 nlhdr->nlmsg_pid = getpid(); 97 nlhdr->nlmsg_type = NLMSG_DONE; 98 nlhdr->nlmsg_len = NLMSG_LENGTH(sizeof(*cnmsg) + cnmsg->len); 99 nlhdr->nlmsg_flags = 0; 100 memcpy(NLMSG_DATA(nlhdr), cnmsg, sizeof(*cnmsg) + cnmsg->len); 101 102 memset(&iov, 0, sizeof(struct iovec)); 103 iov.iov_base = (void *)nlhdr; 104 iov.iov_len = nlhdr->nlmsg_len; 105 106 memset(&msg, 0, sizeof(struct msghdr)); 107 msg.msg_name = (void *)to; 108 msg.msg_namelen = sizeof(*to); 109 msg.msg_iov = &iov; 110 msg.msg_iovlen = 1; 111 112 ret = sendmsg(sd, &msg, 0); 113 114 return ret; 115 } 116 117 /* 118 * Receive package from netlink. 119 * 120 * @sd: socket descripor 121 * @from: source sockaddr 122 */ 123 static int netlink_recv(int sd, struct sockaddr_nl *from) 124 { 125 int ret; 126 struct iovec iov; 127 struct msghdr msg; 128 129 memset(nlhdr, 0, NLMSG_SPACE(MAX_MSG_SIZE)); 130 memset(&iov, 0, sizeof(iov)); 131 memset(&msg, 0, sizeof(msg)); 132 133 iov.iov_base = (void *)nlhdr; 134 iov.iov_len = NLMSG_SPACE(MAX_MSG_SIZE); 135 136 msg.msg_name = (void *)from; 137 msg.msg_namelen = sizeof(*from); 138 msg.msg_iov = &iov; 139 msg.msg_iovlen = 1; 140 141 ret = recvmsg(sd, &msg, 0); 142 143 return ret; 144 } 145 146 /* 147 * Send control message to PEC. 148 * 149 * @sd: socket descriptor 150 * @to: the destination sockaddr 151 * @op: control flag 152 */ 153 static int control_pec(int sd, struct sockaddr_nl *to, enum proc_cn_mcast_op op) 154 { 155 int ret; 156 char buf[PEC_CTRL_MSG_SIZE]; 157 struct cn_msg *cnmsg; 158 enum proc_cn_mcast_op *pec_op; 159 160 memset(buf, 0, sizeof(buf)); 161 162 cnmsg = (struct cn_msg *)buf; 163 cnmsg->id.idx = CN_IDX_PROC; 164 cnmsg->id.val = CN_VAL_PROC; 165 cnmsg->seq = seq++; 166 cnmsg->ack = 0; 167 cnmsg->len = sizeof(op); 168 169 pec_op = (enum proc_cn_mcast_op *)cnmsg->data; 170 *pec_op = op; 171 172 ret = netlink_send(sd, to, cnmsg); 173 174 return ret; 175 } 176 177 /* 178 * Process PEC event. 179 * 180 * @nlhdr: the netlinke pacakge 181 */ 182 static void process_event(struct nlmsghdr *nlhdr) 183 { 184 struct cn_msg *msg; 185 struct proc_event *pe; 186 187 msg = (struct cn_msg *)NLMSG_DATA(nlhdr); 188 189 pe = (struct proc_event *)msg->data; 190 191 switch (pe->what) { 192 case PROC_EVENT_NONE: 193 printf("none err: %u\n", pe->event_data.ack.err); 194 break; 195 case PROC_EVENT_FORK: 196 printf("fork parent: %d, child: %d\n", 197 pe->event_data.fork.parent_pid, 198 pe->event_data.fork.child_pid); 199 break; 200 case PROC_EVENT_EXEC: 201 printf("exec pid: %d\n", pe->event_data.exec.process_pid); 202 break; 203 case PROC_EVENT_UID: 204 printf("uid pid: %d euid: %d ruid: %d\n", 205 pe->event_data.id.process_pid, 206 pe->event_data.id.e.euid, pe->event_data.id.r.ruid); 207 break; 208 case PROC_EVENT_GID: 209 printf("gid pid: %d egid: %d rgid: %d\n", 210 pe->event_data.id.process_pid, 211 pe->event_data.id.e.egid, pe->event_data.id.r.rgid); 212 break; 213 case PROC_EVENT_EXIT: 214 printf("exit pid: %d exit_code: %d exit_signal: %d\n", 215 pe->event_data.exit.process_pid, 216 pe->event_data.exit.exit_code, 217 pe->event_data.exit.exit_signal); 218 break; 219 default: 220 printf("unknown event\n"); 221 break; 222 } 223 } 224 225 int main(int argc, char **argv) 226 { 227 int ret; 228 int sd; 229 struct sockaddr_nl l_local; 230 struct sockaddr_nl src_addr; 231 struct pollfd pfd; 232 233 sigint_action.sa_flags = SA_RESETHAND; 234 sigint_action.sa_handler = &sigint_handler; 235 sigaction(SIGINT, &sigint_action, NULL); 236 237 nlhdr = malloc(NLMSG_SPACE(MAX_MSG_SIZE)); 238 if (!nlhdr) { 239 fprintf(stderr, "lack of memory\n"); 240 exit(1); 241 } 242 243 sd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); 244 if (sd == -1) { 245 fprintf(stderr, "failed to create socket\n"); 246 exit(1); 247 } 248 249 memset(&src_addr, 0, sizeof(src_addr)); 250 src_addr.nl_family = AF_NETLINK; 251 src_addr.nl_pid = 0; 252 src_addr.nl_groups = 0; 253 254 memset(&l_local, 0, sizeof(l_local)); 255 l_local.nl_family = AF_NETLINK; 256 l_local.nl_pid = getpid(); 257 l_local.nl_groups = CN_IDX_PROC; 258 259 ret = bind(sd, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)); 260 if (ret == -1) { 261 fprintf(stderr, "failed to bind socket\n"); 262 exit(1); 263 } 264 265 /* Open PEC listening */ 266 ret = control_pec(sd, &src_addr, PROC_CN_MCAST_LISTEN); 267 if (!ret) { 268 fprintf(stderr, "failed to open PEC listening\n"); 269 exit(1); 270 } 271 272 /* Receive msg from PEC */ 273 pfd.fd = sd; 274 pfd.events = POLLIN; 275 pfd.revents = 0; 276 while (!exit_flag) { 277 278 ret = poll(&pfd, 1, -1); 279 if (ret == 0 || (ret == -1 && errno != EINTR)) { 280 control_pec(sd, &src_addr, PROC_CN_MCAST_IGNORE); 281 fprintf(stderr, "failed to poll\n"); 282 exit(1); 283 } else if (ret == -1 && errno == EINTR) 284 break; 285 286 ret = netlink_recv(sd, &src_addr); 287 288 if (ret == 0) 289 break; 290 else if (ret == -1 && errno == EINTR) 291 break; 292 else if (ret == -1 && errno != EINTR) { 293 control_pec(sd, &src_addr, PROC_CN_MCAST_IGNORE); 294 fprintf(stderr, "failed to receive from netlink\n"); 295 exit(1); 296 } else { 297 switch (nlhdr->nlmsg_type) { 298 case NLMSG_ERROR: 299 fprintf(stderr, "err message recieved.\n"); 300 exit(1); 301 break; 302 case NLMSG_DONE: 303 /* message sent from kernel */ 304 if (nlhdr->nlmsg_pid == 0) 305 process_event(nlhdr); 306 break; 307 default: 308 break; 309 } 310 } 311 } 312 313 /* Close PEC listening */ 314 ret = control_pec(sd, &src_addr, PROC_CN_MCAST_IGNORE); 315 if (!ret) { 316 fprintf(stderr, "failed to close PEC listening\n"); 317 exit(1); 318 } 319 320 close(sd); 321 free(nlhdr); 322 323 while (fsync(STDOUT_FILENO) == -1) { 324 if (errno != EIO) 325 break; 326 /* retry once every 10 secodns */ 327 sleep(10); 328 } 329 330 return 0; 331 } 332 333 #endif /* CN_IDX_PROC */ 334 335 #endif /* NETLINK_CONNECTOR */ 336