xref: /freebsd/usr.bin/proccontrol/proccontrol.c (revision af6a5351a1fdb1130f18be6c782c4d48916eb971)
1 /*-
2  * Copyright (c) 2016 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
6  * under sponsorship from the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <sys/procctl.h>
34 #include <err.h>
35 #include <stdbool.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 enum {
42 	MODE_INVALID,
43 	MODE_TRACE,
44 	MODE_TRAPCAP,
45 };
46 
47 static pid_t
48 str2pid(const char *str)
49 {
50 	pid_t res;
51 	char *tail;
52 
53 	res = strtol(str, &tail, 0);
54 	if (*tail != '\0') {
55 		warnx("non-numeric pid");
56 		return (-1);
57 	}
58 	return (res);
59 }
60 
61 static void __dead2
62 usage(void)
63 {
64 
65 	fprintf(stderr, "Usage: proccontrol -m (trace|trapcap) [-q] "
66 	    "[-s (enable|disable)] [-p pid | command]\n");
67 	exit(1);
68 }
69 
70 int
71 main(int argc, char *argv[])
72 {
73 	int arg, ch, error, mode;
74 	pid_t pid;
75 	bool enable, do_command, query;
76 
77 	mode = MODE_INVALID;
78 	enable = true;
79 	pid = -1;
80 	query = false;
81 	while ((ch = getopt(argc, argv, "m:qs:p:")) != -1) {
82 		switch (ch) {
83 		case 'm':
84 			if (strcmp(optarg, "trace") == 0)
85 				mode = MODE_TRACE;
86 			else if (strcmp(optarg, "trapcap") == 0)
87 				mode = MODE_TRAPCAP;
88 			else
89 				usage();
90 			break;
91 		case 's':
92 			if (strcmp(optarg, "enable") == 0)
93 				enable = true;
94 			else if (strcmp(optarg, "disable") == 0)
95 				enable = false;
96 			else
97 				usage();
98 			break;
99 		case 'p':
100 			pid = str2pid(optarg);
101 			break;
102 		case 'q':
103 			query = true;
104 			break;
105 		case '?':
106 		default:
107 			usage();
108 			break;
109 		}
110 	}
111 	argc -= optind;
112 	argv += optind;
113 	do_command = argc != 0;
114 	if (do_command) {
115 		if (pid != -1 || query)
116 			usage();
117 		pid = getpid();
118 	} else if (pid == -1) {
119 		pid = getpid();
120 	}
121 
122 	if (query) {
123 		switch (mode) {
124 		case MODE_TRACE:
125 			error = procctl(P_PID, pid, PROC_TRACE_STATUS, &arg);
126 			break;
127 		case MODE_TRAPCAP:
128 			error = procctl(P_PID, pid, PROC_TRAPCAP_STATUS, &arg);
129 			break;
130 		default:
131 			usage();
132 			break;
133 		}
134 		if (error != 0)
135 			err(1, "procctl status");
136 		switch (mode) {
137 		case MODE_TRACE:
138 			if (arg == -1)
139 				printf("disabled\n");
140 			else if (arg == 0)
141 				printf("enabled, no debugger\n");
142 			else
143 				printf("enabled, traced by %d\n", arg);
144 			break;
145 		case MODE_TRAPCAP:
146 			switch (arg) {
147 			case PROC_TRAPCAP_CTL_ENABLE:
148 				printf("enabled\n");
149 				break;
150 			case PROC_TRAPCAP_CTL_DISABLE:
151 				printf("disabled\n");
152 				break;
153 			}
154 			break;
155 		}
156 	} else {
157 		switch (mode) {
158 		case MODE_TRACE:
159 			arg = enable ? PROC_TRACE_CTL_ENABLE :
160 			    PROC_TRACE_CTL_DISABLE;
161 			error = procctl(P_PID, pid, PROC_TRACE_CTL, &arg);
162 			break;
163 		case MODE_TRAPCAP:
164 			arg = enable ? PROC_TRAPCAP_CTL_ENABLE :
165 			    PROC_TRAPCAP_CTL_DISABLE;
166 			error = procctl(P_PID, pid, PROC_TRAPCAP_CTL, &arg);
167 			break;
168 		default:
169 			usage();
170 			break;
171 		}
172 		if (error != 0)
173 			err(1, "procctl ctl");
174 		if (do_command) {
175 			error = execvp(argv[0], argv);
176 			err(1, "exec");
177 		}
178 	}
179 	exit(0);
180 }
181