summary refs log tree commit diff
path: root/extrace.c
diff options
context:
space:
mode:
authorLeah Neukirchen <leah@vuxu.org>2017-07-14 19:08:10 +0200
committerLeah Neukirchen <leah@vuxu.org>2017-07-14 19:08:10 +0200
commit3ba01b7fdaf7f68c756ebb0ded2829575afec497 (patch)
tree74de877718041a241e7513e373854b80d8fca663 /extrace.c
parent91b81929ea84209cd82aa2a02b9b63174577a5b1 (diff)
downloadextrace-3ba01b7fdaf7f68c756ebb0ded2829575afec497.tar.gz
extrace-3ba01b7fdaf7f68c756ebb0ded2829575afec497.tar.xz
extrace-3ba01b7fdaf7f68c756ebb0ded2829575afec497.zip
extrace.c: KNF
Diffstat (limited to 'extrace.c')
-rw-r--r--extrace.c667
1 files changed, 339 insertions, 328 deletions
diff --git a/extrace.c b/extrace.c
index b82a6a0..7dad447 100644
--- a/extrace.c
+++ b/extrace.c
@@ -14,7 +14,7 @@
  * -l       print full path of argv[0]
  * -q       don't print exec() arguments
  *
- * Copyright (C) 2014-2016 Leah Neukirchen <leah@vuxu.org>
+ * Copyright (C) 2014-2017 Leah Neukirchen <leah@vuxu.org>
  *
  * hacked from sources of:
  */
@@ -76,8 +76,8 @@
 #define RECV_MESSAGE_LEN (NLMSG_LENGTH(sizeof (struct cn_msg) + \
                                        sizeof (struct proc_event)))
 
-#define SEND_MESSAGE_SIZE    (NLMSG_SPACE(SEND_MESSAGE_LEN))
-#define RECV_MESSAGE_SIZE    (NLMSG_SPACE(RECV_MESSAGE_LEN))
+#define SEND_MESSAGE_SIZE (NLMSG_SPACE(SEND_MESSAGE_LEN))
+#define RECV_MESSAGE_SIZE (NLMSG_SPACE(RECV_MESSAGE_LEN))
 
 #define BUFF_SIZE (max(max(SEND_MESSAGE_SIZE, RECV_MESSAGE_SIZE), 1024))
 #define MIN_RECV_SIZE (min(SEND_MESSAGE_SIZE, RECV_MESSAGE_SIZE))
@@ -97,370 +97,381 @@ sig_atomic_t quit = 0;
 
 #define PID_DB_SIZE 1024
 struct {
-  pid_t pid;
-  int depth;
-  struct timespec start;
-  char cmdline[CMDLINE_DB_MAX];
+	pid_t pid;
+	int depth;
+	struct timespec start;
+	char cmdline[CMDLINE_DB_MAX];
 } pid_db[PID_DB_SIZE];
 
 static int
 pid_depth(pid_t pid)
 {
-  pid_t ppid = 0;
-  FILE *f;
-  char name[PATH_MAX];
-  int d;
+	pid_t ppid = 0;
+	FILE *f;
+	char name[PATH_MAX];
+	int d;
 
-  snprintf(name, sizeof name, "/proc/%d/stat", pid);
+	snprintf(name, sizeof name, "/proc/%d/stat", pid);
 
-  if ((f = fopen(name, "r"))) {
-    if (fscanf(f, "%*d (%*[^)]) %*c %d", &ppid) < 0)
-      ppid = 0;
-    fclose(f);
-  }
+	if ((f = fopen(name, "r"))) {
+		if (fscanf(f, "%*d (%*[^)]) %*c %d", &ppid) < 0)
+			ppid = 0;
+		fclose(f);
+	}
 
-  if (ppid == parent)
-    return 0;
+	if (ppid == parent)
+		return 0;
 
-  if (ppid == 0)
-    return -1;  /* a parent we are not interested in */
+	if (ppid == 0)
+		return -1;  /* a parent we are not interested in */
 
-  d = pid_depth(ppid);
-  if (d == -1)
-    return -1;
+	d = pid_depth(ppid);
+	if (d == -1)
+		return -1;
 
-  return d+1;
+	return d+1;
 }
 
 static void
 sigint(int sig)
 {
-  (void)sig;
-  quit = 1;
+	(void)sig;
+	quit = 1;
 }
 
 static void
 sigchld(int sig)
 {
-  (void)sig;
-  while (waitpid(-1, NULL, WNOHANG) > 0)
-    ;
-  quit = 1;
+	(void)sig;
+	while (waitpid(-1, NULL, WNOHANG) > 0)
+		;
+	quit = 1;
 }
 
 static void
 print_shquoted(const char *s)
 {
-  if (*s && !strpbrk(s,
-                     "\001\002\003\004\005\006\007\010"
-                     "\011\012\013\014\015\016\017\020"
-                     "\021\022\023\024\025\026\027\030"
-                     "\031\032\033\034\035\036\037\040"
-                     "`^#*[]=|\\?${}()'\"<>&;\177")) {
-    fprintf(output, "%s", s);
-    return;
-  }
+	if (*s && !strpbrk(s,
+	    "\001\002\003\004\005\006\007\010"
+	    "\011\012\013\014\015\016\017\020"
+	    "\021\022\023\024\025\026\027\030"
+	    "\031\032\033\034\035\036\037\040"
+	    "`^#*[]=|\\?${}()'\"<>&;\177")) {
+		fprintf(output, "%s", s);
+		return;
+	}
+
+	putc('\'', output);
+	for (; *s; s++)
+		if (*s == '\'')
+			fprintf(output, "'\\''");
+		else if (*s == '\n')
+			fprintf(output, "'$'\\n''");
+		else
+			putc(*s, output);
+	putc('\'', output);
+}
 
-  putc('\'', output);
-  for (; *s; s++)
-    if (*s == '\'')
-      fprintf(output, "'\\''");
-    else if (*s == '\n')
-      fprintf(output, "'$'\\n''");
-    else
-      putc(*s, output);
-  putc('\'', output);
+static void
+print_env(pid_t pid)
+{
+	char name[PATH_MAX];
+	FILE *env;
+
+	fprintf(output, "  ");
+	snprintf(name, sizeof name, "/proc/%d/environ", pid);
+	if ((env = fopen(name, "r"))) {
+		char *line = 0, *eq = 0;
+		size_t linelen = 0;
+		while (getdelim(&line, &linelen, '\0', env) >= 0) {
+			putc(' ', output);
+			if ((eq = strchr(line, '='))) {
+				/* print split so = doesn't trigger escaping.  */
+				*eq = 0;
+				print_shquoted(line);
+				putc('=', output);
+				print_shquoted(eq+1);
+			} else {
+				/* weird env entry without equal sign.  */
+				print_shquoted(line);
+			}
+		}
+		free(line);
+		fclose(env);
+	} else {
+		fprintf(output, " -");
+	}
 }
 
 static void
 handle_msg(struct cn_msg *cn_hdr)
 {
-  char cmdline[CMDLINE_MAX], name[PATH_MAX];
-  char exe[PATH_MAX];
-  char cwd[PATH_MAX];
-  char *argvrest;
-
-  int r = 0, r2 = 0, r3 = 0, fd, d;
-  struct proc_event *ev = (struct proc_event *)cn_hdr->data;
-
-  if (ev->what == PROC_EVENT_EXEC) {
-    pid_t pid = ev->event_data.exec.process_pid;
-    int i = 0;
-
-    d = pid_depth(pid);
-    if (d < 0)
-      return;
-
-    if (show_exit) {
-      for (i = 0; i < PID_DB_SIZE - 1; i++)
-        if (pid_db[i].pid == 0)
-           break;
-      if (i == PID_DB_SIZE - 1)
-        fprintf(stderr,
-          "extrace: warning pid_db of size %d overflowed\n", PID_DB_SIZE);
-
-      pid_db[i].pid = pid;
-      pid_db[i].depth = d;
-      clock_gettime(CLOCK_MONOTONIC_RAW, &pid_db[i].start);
-    }
-
-    snprintf(name, sizeof name, "/proc/%d/cmdline", pid);
-
-    memset(&cmdline, 0, sizeof cmdline);
-    fd = open(name, O_RDONLY);
-    if (fd > 0) {
-      r = read(fd, cmdline, sizeof cmdline);
-      close(fd);
-
-      if (r > 0)
-        cmdline[r] = 0;
-
-      if (full_path) {
-        snprintf(name, sizeof name, "/proc/%d/exe", pid);
-        r2 = readlink(name, exe, sizeof exe);
-        if (r2 > 0)
-          exe[r2] = 0;
-      }
-
-      argvrest = strchr(cmdline, 0) + 1;
-    }
-
-    if (show_cwd) {
-      snprintf(name, sizeof name, "/proc/%d/cwd", pid);
-      r3 = readlink(name, cwd, sizeof cwd);
-      if (r3 > 0)
-        cwd[r3] = 0;
-    }
-
-    if (!flat)
-      fprintf(output, "%*s", 2*d, "");
-    fprintf(output, "%d", pid);
-    if (show_exit) {
-      putc('+', output);
-      strncpy(pid_db[i].cmdline, cmdline, CMDLINE_DB_MAX-1);
-      pid_db[i].cmdline[CMDLINE_DB_MAX-1] = 0;
-    }
-    putc(' ', output);
-    if (show_cwd) {
-      print_shquoted(cwd);
-      fprintf(output, " %% ");
-    }
-
-    if (full_path)
-      print_shquoted(exe);
-    else
-      print_shquoted(cmdline);
-
-    if (show_args && r > 0) {
-      while (argvrest - cmdline < r) {
-        putc(' ', output);
-        print_shquoted(argvrest);
-        argvrest = strchr(argvrest, 0)+1;
-      }
-    }
-
-    if (r == sizeof cmdline)
-      fprintf(output, "... <truncated>");
-
-    if (show_env) {
-      FILE *env;
-      fprintf(output, "  ");
-      snprintf(name, sizeof name, "/proc/%d/environ", pid);
-      if ((env = fopen(name, "r"))) {
-        char *line = 0, *eq = 0;
-        size_t linelen = 0;
-        while (getdelim(&line, &linelen, '\0', env) >= 0) {
-          putc(' ', output);
-          if ((eq = strchr(line, '='))) {
-            /* print split so = doesn't trigger escaping.  */
-            *eq = 0;
-            print_shquoted(line);
-            putc('=', output);
-            print_shquoted(eq+1);
-          } else {
-            /* weird env entry without equal sign.  */
-            print_shquoted(line);
-          }
-        }
-        free(line);
-        fclose(env);
-      } else {
-        fprintf(output, " -");
-      }
-    }
-
-    fprintf(output, "\n");
-    fflush(output);
-  } else if (show_exit && ev->what == PROC_EVENT_EXIT) {
-    pid_t pid = ev->event_data.exit.process_pid;
-    int i;
-
-    for (i = 0; i < PID_DB_SIZE; i++)
-      if (pid_db[i].pid == pid) {
-        struct timespec now, diff;
-
-        pid_db[i].pid = 0;
-        if (!flat)
-          fprintf(output, "%*s", 2*pid_db[i].depth, "");
-        clock_gettime(CLOCK_MONOTONIC_RAW, &now);
-        
-        if ((now.tv_nsec - pid_db[i].start.tv_nsec) < 0) {
-          diff.tv_sec = now.tv_sec - pid_db[i].start.tv_sec - 1;
-          diff.tv_nsec = 1000000000 + now.tv_nsec - pid_db[i].start.tv_nsec;
-        } else {
-          diff.tv_sec = now.tv_sec - pid_db[i].start.tv_sec;
-          diff.tv_nsec = now.tv_nsec - pid_db[i].start.tv_nsec;
-        }
-
-        fprintf(output, "%d- ", pid);
-        print_shquoted(pid_db[i].cmdline);
-        fprintf(output, " exited %s=%d time=%ld.%03lds\n",
-            ev->event_data.exit.exit_code >= 256 ? "signal" : "status",
-            ev->event_data.exit.exit_code >= 256 ?
-              ev->event_data.exit.exit_signal :
-              ev->event_data.exit.exit_code,
-            diff.tv_sec,
-            diff.tv_nsec / 1000000);
-        fflush(output);
-        break;
-      }
-  }
+	char cmdline[CMDLINE_MAX], name[PATH_MAX];
+	char exe[PATH_MAX];
+	char cwd[PATH_MAX];
+	char *argvrest;
+
+	int r = 0, r2 = 0, r3 = 0, fd, d;
+	struct proc_event *ev = (struct proc_event *)cn_hdr->data;
+
+	if (ev->what == PROC_EVENT_EXEC) {
+		pid_t pid = ev->event_data.exec.process_pid;
+		int i = 0;
+
+		d = pid_depth(pid);
+		if (d < 0)
+			return;
+
+		if (show_exit) {
+			for (i = 0; i < PID_DB_SIZE - 1; i++)
+				if (pid_db[i].pid == 0)
+					break;
+			if (i == PID_DB_SIZE - 1)
+				fprintf(stderr, "extrace: warning pid_db of "
+				    "size %d overflowed\n", PID_DB_SIZE);
+			
+			pid_db[i].pid = pid;
+			pid_db[i].depth = d;
+			clock_gettime(CLOCK_MONOTONIC_RAW, &pid_db[i].start);
+		}
+
+		snprintf(name, sizeof name, "/proc/%d/cmdline", pid);
+
+		memset(&cmdline, 0, sizeof cmdline);
+		fd = open(name, O_RDONLY);
+		if (fd > 0) {
+			r = read(fd, cmdline, sizeof cmdline);
+			close(fd);
+
+			if (r > 0)
+				cmdline[r] = 0;
+
+			if (full_path) {
+				snprintf(name, sizeof name, "/proc/%d/exe", pid);
+				r2 = readlink(name, exe, sizeof exe);
+				if (r2 > 0)
+					exe[r2] = 0;
+			}
+
+			argvrest = strchr(cmdline, 0) + 1;
+		}
+
+		if (show_cwd) {
+			snprintf(name, sizeof name, "/proc/%d/cwd", pid);
+			r3 = readlink(name, cwd, sizeof cwd);
+			if (r3 > 0)
+				cwd[r3] = 0;
+		}
+
+		if (!flat)
+			fprintf(output, "%*s", 2*d, "");
+		fprintf(output, "%d", pid);
+		if (show_exit) {
+			putc('+', output);
+			strncpy(pid_db[i].cmdline, cmdline, CMDLINE_DB_MAX-1);
+			pid_db[i].cmdline[CMDLINE_DB_MAX-1] = 0;
+		}
+		putc(' ', output);
+		if (show_cwd) {
+			print_shquoted(cwd);
+			fprintf(output, " %% ");
+		}
+
+		if (full_path)
+			print_shquoted(exe);
+		else
+			print_shquoted(cmdline);
+
+		if (show_args && r > 0) {
+			while (argvrest - cmdline < r) {
+				putc(' ', output);
+				print_shquoted(argvrest);
+				argvrest = strchr(argvrest, 0)+1;
+			}
+		}
+
+		if (r == sizeof cmdline)
+			fprintf(output, "... <truncated>");
+
+		if (show_env) {
+			print_env(pid);
+		}
+
+		fprintf(output, "\n");
+		fflush(output);
+	} else if (show_exit && ev->what == PROC_EVENT_EXIT) {
+		pid_t pid = ev->event_data.exit.process_pid;
+		struct timespec now, diff;
+		int i;
+
+		for (i = 0; i < PID_DB_SIZE; i++)
+			if (pid_db[i].pid == pid)
+				break;
+		if (i == PID_DB_SIZE)
+			return;
+		
+		pid_db[i].pid = 0;
+		if (!flat)
+			fprintf(output, "%*s",
+			    2*pid_db[i].depth, "");
+		clock_gettime(CLOCK_MONOTONIC_RAW, &now);
+
+		if ((now.tv_nsec - pid_db[i].start.tv_nsec) < 0) {
+			diff.tv_sec = now.tv_sec - pid_db[i].start.tv_sec - 1;
+			diff.tv_nsec = 1000000000 + now.tv_nsec - pid_db[i].start.tv_nsec;
+		} else {
+			diff.tv_sec = now.tv_sec - pid_db[i].start.tv_sec;
+			diff.tv_nsec = now.tv_nsec - pid_db[i].start.tv_nsec;
+		}
+
+		fprintf(output, "%d- ", pid);
+		print_shquoted(pid_db[i].cmdline);
+		fprintf(output, " exited %s=%d time=%ld.%03lds\n",
+		    ev->event_data.exit.exit_code >= 256 ? "signal" : "status",
+		    ev->event_data.exit.exit_code >= 256 ?
+		    ev->event_data.exit.exit_signal :
+		    ev->event_data.exit.exit_code,
+		    diff.tv_sec,
+		    diff.tv_nsec / 1000000);
+		fflush(output);
+	}
 }
 
 int
 main(int argc, char *argv[])
 {
-  int sk_nl;
-  struct sockaddr_nl my_nla, kern_nla, from_nla;
-  socklen_t from_nla_len;
-  char buff[BUFF_SIZE];
-  struct nlmsghdr *nl_hdr, *nlh;
-  struct cn_msg *cn_hdr;
-  enum proc_cn_mcast_op *mcop_msg;
-  size_t recv_len = 0;
-  int rc = -1, opt;
-
-  output = stdout;
-
-  while ((opt = getopt(argc, argv, "+deflo:p:qtw")) != -1)
-    switch (opt) {
-    case 'd': show_cwd = 1; break;
-    case 'e': show_env = 1; break;
-    case 'f': flat = 1; break;
-    case 'l': full_path = 1; break;
-    case 'p': parent = atoi(optarg); break;
-    case 'q': show_args = 0; break;
-    case 't': show_exit = 1; break;
-    case 'o':
-      output = fopen(optarg, "w");
-      if (!output) {
-        perror("fopen");
-        exit(1);
-      }
-      break;
-    case 'w': /* obsoleted, ignore */; break;
-    default: goto usage;
-    }
-
-  if (parent != 1 && optind != argc) {
-usage:
-    fprintf(stderr, "Usage: extrace [-deflq] [-o FILE] [-p PID|CMD...]\n");
-    exit(1);
-  }
-
-  sk_nl = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
-  if (sk_nl == -1) {
-    perror("socket sk_nl error");
-    exit(1);
-  }
-
-  my_nla.nl_family = AF_NETLINK;
-  my_nla.nl_groups = CN_IDX_PROC;
-  my_nla.nl_pid = getpid();
-
-  kern_nla.nl_family = AF_NETLINK;
-  kern_nla.nl_groups = CN_IDX_PROC;
-  kern_nla.nl_pid = 1;
-
-  if (bind(sk_nl, (struct sockaddr *)&my_nla, sizeof my_nla) == -1) {
-    perror("binding sk_nl error");
-    goto close_and_exit;
-  }
-  nl_hdr = (struct nlmsghdr *)buff;
-  cn_hdr = (struct cn_msg *)NLMSG_DATA(nl_hdr);
-  mcop_msg = (enum proc_cn_mcast_op*)&cn_hdr->data[0];
-
-  memset(buff, 0, sizeof buff);
-  *mcop_msg = PROC_CN_MCAST_LISTEN;
-
-  nl_hdr->nlmsg_len = SEND_MESSAGE_LEN;
-  nl_hdr->nlmsg_type = NLMSG_DONE;
-  nl_hdr->nlmsg_flags = 0;
-  nl_hdr->nlmsg_seq = 0;
-  nl_hdr->nlmsg_pid = getpid();
-
-  cn_hdr->id.idx = CN_IDX_PROC;
-  cn_hdr->id.val = CN_VAL_PROC;
-  cn_hdr->seq = 0;
-  cn_hdr->ack = 0;
-  cn_hdr->len = sizeof (enum proc_cn_mcast_op);
-
-  if (send(sk_nl, nl_hdr, nl_hdr->nlmsg_len, 0) != nl_hdr->nlmsg_len) {
-    printf("failed to send proc connector mcast ctl op!\n");
-    goto close_and_exit;
+	int sk_nl;
+	struct sockaddr_nl my_nla, kern_nla, from_nla;
+	socklen_t from_nla_len;
+	char buff[BUFF_SIZE];
+	struct nlmsghdr *nl_hdr, *nlh;
+	struct cn_msg *cn_hdr;
+	enum proc_cn_mcast_op *mcop_msg;
+	size_t recv_len = 0;
+	int rc = -1, opt;
+
+	output = stdout;
+
+	while ((opt = getopt(argc, argv, "+deflo:p:qtw")) != -1)
+		switch (opt) {
+		case 'd': show_cwd = 1; break;
+		case 'e': show_env = 1; break;
+		case 'f': flat = 1; break;
+		case 'l': full_path = 1; break;
+		case 'p': parent = atoi(optarg); break;
+		case 'q': show_args = 0; break;
+		case 't': show_exit = 1; break;
+		case 'o':
+			output = fopen(optarg, "w");
+			if (!output) {
+				perror("fopen");
+				exit(1);
+			}
+			break;
+		case 'w': /* obsoleted, ignore */; break;
+		default: goto usage;
+		}
+
+	if (parent != 1 && optind != argc) {
+	usage:
+		fprintf(stderr, "Usage: extrace [-deflq] [-o FILE] [-p PID|CMD...]\n");
+		exit(1);
   }
 
-  if (*mcop_msg == PROC_CN_MCAST_IGNORE) {
-    rc = 0;
-    goto close_and_exit;
-  }
-
-  if (optind != argc) {
-    pid_t child;
-
-    parent = getpid();
-    signal(SIGCHLD, sigchld);
-
-    child = fork();
-    if (child == -1) {
-      perror("fork");
-      goto close_and_exit;
-    }
-    if (child == 0) {
-      execvp(argv[optind], argv+optind);
-      perror("execvp");
-      goto close_and_exit;
-    }
-  }
-
-  signal(SIGINT, sigint);
-
-  rc = 0;
-  while (!quit) {
-    memset(buff, 0, sizeof buff);
-    from_nla_len = sizeof from_nla;
-    nlh = (struct nlmsghdr *)buff;
-    memcpy(&from_nla, &kern_nla, sizeof from_nla);
-    recv_len = recvfrom(sk_nl, buff, BUFF_SIZE, 0,
-                        (struct sockaddr *)&from_nla, &from_nla_len);
-    if (from_nla.nl_pid != 0 || recv_len < 1)
-      continue;
-
-    while (NLMSG_OK(nlh, recv_len)) {
-      if (nlh->nlmsg_type == NLMSG_NOOP)
-        continue;
-      if (nlh->nlmsg_type == NLMSG_ERROR || nlh->nlmsg_type == NLMSG_OVERRUN)
-        break;
-
-      handle_msg(NLMSG_DATA(nlh));
-
-      if (nlh->nlmsg_type == NLMSG_DONE)
-        break;
-      nlh = NLMSG_NEXT(nlh, recv_len);
-    }
-  }
+	sk_nl = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
+	if (sk_nl == -1) {
+		perror("socket sk_nl error");
+		exit(1);
+	}
+
+	my_nla.nl_family = AF_NETLINK;
+	my_nla.nl_groups = CN_IDX_PROC;
+	my_nla.nl_pid = getpid();
+
+	kern_nla.nl_family = AF_NETLINK;
+	kern_nla.nl_groups = CN_IDX_PROC;
+	kern_nla.nl_pid = 1;
+
+	if (bind(sk_nl, (struct sockaddr *)&my_nla, sizeof my_nla) == -1) {
+		perror("binding sk_nl error");
+		goto close_and_exit;
+	}
+	nl_hdr = (struct nlmsghdr *)buff;
+	cn_hdr = (struct cn_msg *)NLMSG_DATA(nl_hdr);
+	mcop_msg = (enum proc_cn_mcast_op*)&cn_hdr->data[0];
+
+	memset(buff, 0, sizeof buff);
+	*mcop_msg = PROC_CN_MCAST_LISTEN;
+
+	nl_hdr->nlmsg_len = SEND_MESSAGE_LEN;
+	nl_hdr->nlmsg_type = NLMSG_DONE;
+	nl_hdr->nlmsg_flags = 0;
+	nl_hdr->nlmsg_seq = 0;
+	nl_hdr->nlmsg_pid = getpid();
+
+	cn_hdr->id.idx = CN_IDX_PROC;
+	cn_hdr->id.val = CN_VAL_PROC;
+	cn_hdr->seq = 0;
+	cn_hdr->ack = 0;
+	cn_hdr->len = sizeof (enum proc_cn_mcast_op);
+
+	if (send(sk_nl, nl_hdr, nl_hdr->nlmsg_len, 0) != nl_hdr->nlmsg_len) {
+		printf("failed to send proc connector mcast ctl op!\n");
+		goto close_and_exit;
+	}
+
+	if (*mcop_msg == PROC_CN_MCAST_IGNORE) {
+		rc = 0;
+		goto close_and_exit;
+	}
+
+	if (optind != argc) {
+		pid_t child;
+
+		parent = getpid();
+		signal(SIGCHLD, sigchld);
+
+		child = fork();
+		if (child == -1) {
+			perror("fork");
+			goto close_and_exit;
+		}
+		if (child == 0) {
+			execvp(argv[optind], argv+optind);
+			perror("execvp");
+			goto close_and_exit;
+		}
+	}
+
+	signal(SIGINT, sigint);
+
+	rc = 0;
+	while (!quit) {
+		memset(buff, 0, sizeof buff);
+		from_nla_len = sizeof from_nla;
+		nlh = (struct nlmsghdr *)buff;
+		memcpy(&from_nla, &kern_nla, sizeof from_nla);
+		recv_len = recvfrom(sk_nl, buff, BUFF_SIZE, 0,
+		    (struct sockaddr *)&from_nla, &from_nla_len);
+		if (from_nla.nl_pid != 0 || recv_len < 1)
+			continue;
+
+		while (NLMSG_OK(nlh, recv_len)) {
+			if (nlh->nlmsg_type == NLMSG_NOOP)
+				continue;
+			if (nlh->nlmsg_type == NLMSG_ERROR ||
+			    nlh->nlmsg_type == NLMSG_OVERRUN)
+				break;
+
+			handle_msg(NLMSG_DATA(nlh));
+
+			if (nlh->nlmsg_type == NLMSG_DONE)
+				break;
+			nlh = NLMSG_NEXT(nlh, recv_len);
+		}
+	}
 
 close_and_exit:
-  close(sk_nl);
-  return rc;
+	close(sk_nl);
+	return rc;
 }