after

Echo a string after process dies
git clone _git@git.zakaria.org/after.git
Log | Files | Refs | README | LICENSE

after.c (2981B)


      1 #include <sys/types.h>
      2 #include <sys/sysctl.h>
      3 
      4 #include <err.h>
      5 #include <fcntl.h>
      6 #include <kvm.h>
      7 #include <limits.h>
      8 #include <stdio.h>
      9 #include <stdlib.h>
     10 #include <string.h>
     11 #include <unistd.h>
     12 
     13 int verbose;
     14 
     15 void
     16 usage(void)
     17 {
     18 	fprintf(stderr, "usage: %s [-h] [-v] [-p pid | -n process_name] -e string\n",
     19 	        getprogname());
     20 }
     21 
     22 void
     23 debug_print(const char *message)
     24 {
     25 	if (verbose)
     26 		fprintf(stderr, "%s: %s\n", getprogname(), message);
     27 }
     28 
     29 
     30 int
     31 pid_is_in(int pid, struct kinfo_proc **kinfo, int entries)
     32 {
     33 	int i;
     34 	for (i = 0; i < entries; i++) {
     35 		if (kinfo[i]->p_pid == pid)
     36 			return 1;
     37 	}
     38 	return 0;
     39 }
     40 
     41 int
     42 pname_is_in(char *pname, struct kinfo_proc **kinfo, int entries)
     43 {
     44 	int i;
     45 	for (i = 0; i < entries; i++) {
     46 		if (strcmp(kinfo[i]->p_comm, pname) == 0)
     47 			return 1;
     48 	}
     49 	return 0;
     50 }
     51 
     52 void
     53 update_proc_list(struct kinfo_proc ***kinfo, kvm_t *kd, int *entries)
     54 {
     55 	int i;
     56 	struct kinfo_proc *kp;
     57 
     58 	kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(*kp), entries);
     59 	if (kp == NULL)
     60 		errx(1, "%s", kvm_geterr(kd));
     61 
     62 	if (((*kinfo) = reallocarray((*kinfo), *entries, sizeof(*(*kinfo)))) == NULL)
     63 		err(1, "failed to allocate memory for proc pointers");
     64 
     65 	for (i = 0; i < *entries; i++)
     66 		(*kinfo)[i] = &kp[i];
     67 }
     68 
     69 int
     70 main(int argc, char **argv)
     71 {
     72 	int i, ch, entries;
     73 	int pid = 0;
     74 	int found = 0;
     75 	char *pname = NULL, *string = NULL;
     76 	char errbuf[_POSIX2_LINE_MAX];
     77 
     78 	kvm_t *kd;
     79 	struct kinfo_proc **kinfo = NULL;
     80 
     81 	verbose = 0;
     82 
     83 	if (pledge("stdio ps", NULL) == -1)
     84 		err(1, "pledge");
     85 
     86 	// argument parsing...
     87 	while((ch = getopt(argc, argv, "e:hn:p:v")) != -1)
     88 		switch(ch) {
     89 		case 'e':
     90 			string = optarg;
     91 			break;
     92 		case 'n':
     93 			pname = optarg;
     94 			break;
     95 		case 'p':
     96 			sscanf(optarg, "%d", &pid);
     97 			break;
     98 		case 'v':
     99 			verbose = 1;
    100 			break;
    101 		case 'h':
    102 			usage();
    103 			return 0;
    104 		default:
    105 			usage();
    106 			exit(1);
    107 		}
    108 
    109 	// argument checking...
    110 	// show usage if neither a pid nor a pname are given
    111 	if (!(pname != NULL || pid != 0)) {
    112 		usage();
    113 		exit(1);
    114 	}
    115 	// show usage if no output string is given
    116 	if (string == NULL) {
    117 		usage();
    118 		exit(1);
    119 	}
    120 
    121 	// initialise virtual memory access
    122 	kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
    123 	if (kd == NULL)
    124 		errx(1, "%s", errbuf);
    125 
    126 	// get initial process list
    127 	update_proc_list(&kinfo, kd, &entries);
    128 
    129 	// if a process name is given use that function, otherwise use pid function
    130 	while (
    131 		(pname != NULL)
    132 		? pname_is_in(pname, kinfo, entries)
    133 		: pid_is_in(pid, kinfo, entries)
    134 	) {
    135 		found = 1; // mark the process as existing
    136 		update_proc_list(&kinfo, kd, &entries);
    137 		debug_print("waiting...");
    138 		sleep(1);
    139 	}
    140 
    141 	// free kinfo and close off access to kernel vmem
    142 	free(kinfo);
    143 	int kd_error;
    144 	if ((kd_error = kvm_close(kd)) < 0) {
    145 		errx(1, "failed to close kernel memory descriptor (%d)", kd_error);
    146 	}
    147 
    148 	// if the process existed at some stage
    149 	if (found) {
    150 		debug_print("process died.");
    151 		printf("%s\n", string);
    152 	} else {
    153 		errx(1, "process not in process list.");
    154 	}
    155 
    156 	return 0;
    157 }