1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /*
26  * poolbind - bind processes, tasks, and projects to pools, and query process
27  * pool bindings
28  */
29 
30 #include <libgen.h>
31 #include <pool.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <strings.h>
36 #include <unistd.h>
37 
38 #include <locale.h>
39 #include <libintl.h>
40 
41 #include <sys/procset.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <errno.h>
45 #include <project.h>
46 #include <zone.h>
47 
48 #include "utils.h"
49 
50 #ifndef	TEXT_DOMAIN
51 #define	TEXT_DOMAIN	"SYS_TEST"
52 #endif
53 
54 #define	eFLAG	0x1
55 #define	iFLAG	0x2
56 #define	pFLAG	0x4
57 #define	qFLAG	0x8
58 #define	QFLAG	0x10
59 
60 static const char OPTS[] = "Qei:p:q";
61 static struct {
62 	idtype_t idtype;
63 	char *str;
64 } idtypes[] = {
65 	{ P_PID, "pid" },
66 	{ P_TASKID, "taskid" },
67 	{ P_PROJID, "projid" },
68 	{ P_PROJID, "project" },
69 	{ P_ZONEID, "zoneid" },
70 	{ -1, NULL }
71 };
72 
73 int error = E_PO_SUCCESS;
74 
75 void exec_cmd(char *, char *[]);
76 void process_ids(char *, uint_t, idtype_t, char *, int, char *[]);
77 
78 void
usage(void)79 usage(void)
80 {
81 	(void) fprintf(stderr,
82 	    gettext("Usage:\n"
83 	    "    poolbind -p pool_name -e command [arguments...]\n"
84 	    "    poolbind -p pool_name "
85 	    "[-i pid | -i taskid | -i projid | -i zoneid] id ...\n"
86 	    "    poolbind -q pid ...\n"
87 	    "    poolbind -Q pid ... \n"));
88 	exit(E_USAGE);
89 }
90 
91 int
print_resource_binding(const char * type,pid_t pid)92 print_resource_binding(const char *type, pid_t pid)
93 {
94 	char *resource_name;
95 
96 	if ((resource_name = pool_get_resource_binding(type, pid)) == NULL)
97 		warn(gettext("getting '%s' binding for %d: %s\n"), type,
98 		    (int)pid, get_errstr());
99 	else
100 		(void) printf("%d\t%s\t%s\n", (int)pid, type, resource_name);
101 	free(resource_name);
102 	return (PO_SUCCESS);
103 }
104 
105 int
main(int argc,char * argv[])106 main(int argc, char *argv[])
107 {
108 	int c;
109 	int i;
110 	idtype_t idtype = P_PID;
111 	char *idstr = "pid";
112 	char *pool_name = NULL;
113 	uint_t flags = 0;
114 	int status;
115 
116 	(void) getpname(argv[0]);
117 	(void) setlocale(LC_ALL, "");
118 	(void) textdomain(TEXT_DOMAIN);
119 
120 	while ((c = getopt(argc, argv, OPTS)) != EOF) {
121 		switch (c) {
122 		case 'Q':
123 			if (flags & (qFLAG | iFLAG | pFLAG))
124 				usage();
125 			flags |= QFLAG;
126 			break;
127 		case 'e':
128 			if (flags & (iFLAG | qFLAG | QFLAG))
129 				usage();
130 			flags |= eFLAG;
131 			break;
132 		case 'i':
133 			for (i = 0; idtypes[i].str != NULL; i++) {
134 				if (strcmp(optarg, idtypes[i].str) == 0) {
135 					idtype = idtypes[i].idtype;
136 					idstr = idtypes[i].str;
137 					break;
138 				}
139 			}
140 			if ((flags & (iFLAG | qFLAG | QFLAG)) ||
141 			    idtypes[i].str == NULL)
142 				usage();
143 			flags |= iFLAG;
144 			break;
145 		case 'p':
146 			if (flags & (pFLAG | qFLAG | QFLAG))
147 				usage();
148 			flags |= pFLAG;
149 			pool_name = optarg;
150 			break;
151 		case 'q':
152 			if (flags & (pFLAG | iFLAG | QFLAG))
153 				usage();
154 			flags |= qFLAG;
155 			break;
156 		case '?':
157 		default:
158 			usage();
159 		}
160 	}
161 
162 	argc -= optind;
163 	argv += optind;
164 
165 	if (flags & eFLAG && pool_name == NULL)
166 		usage();
167 	if (argc < 1 || (flags & (pFLAG | qFLAG | QFLAG)) == 0)
168 		usage();
169 
170 	/*
171 	 * Check to see that the pools facility is enabled
172 	 */
173 	if (pool_get_status(&status) != PO_SUCCESS)
174 		die((ERR_OPEN_DYNAMIC), get_errstr());
175 	if (status == POOL_DISABLED)
176 		die((ERR_OPEN_DYNAMIC), strerror(ENOTACTIVE));
177 
178 	if (flags & eFLAG)
179 		exec_cmd(pool_name, argv);
180 		/*NOTREACHED*/
181 	else
182 		process_ids(pool_name, flags, idtype, idstr, argc, argv);
183 
184 	return (error);
185 }
186 
187 void
exec_cmd(char * pool_name,char * argv[])188 exec_cmd(char *pool_name, char *argv[])
189 {
190 	if (pool_set_binding(pool_name, P_PID, getpid()) != PO_SUCCESS) {
191 		warn(gettext("binding to pool '%s': %s\n"), pool_name,
192 		    get_errstr());
193 		error = E_ERROR;
194 		return;
195 	}
196 
197 	if (execvp(argv[0], argv) == -1)
198 		die(gettext("exec of %s failed"), argv[0]);
199 	/*NOTREACHED*/
200 }
201 
202 void
process_ids(char * pool_name,uint_t flags,idtype_t idtype,char * idstr,int argc,char * argv[])203 process_ids(char *pool_name, uint_t flags, idtype_t idtype, char *idstr,
204     int argc, char *argv[])
205 {
206 	int i;
207 	id_t id;
208 
209 	for (i = 0; i < argc; i++) {
210 		char *endp;
211 		char *poolname;
212 
213 		errno = 0;
214 		id = (id_t)strtol(argv[i], &endp, 10);
215 		if (errno != 0 ||
216 		    (endp && endp != argv[i] + strlen(argv[i])) ||
217 		    (idtype == P_ZONEID &&
218 		    getzonenamebyid(id, NULL, 0) == -1)) {
219 			/*
220 			 * The string does not completely parse to
221 			 * an integer, or it represents an invalid
222 			 * zone id.
223 			 */
224 
225 			/*
226 			 * It must be a project or zone name.
227 			 */
228 			if (idtype == P_ZONEID) {
229 				if (zone_get_id(argv[i], &id) != 0) {
230 					warn(gettext("invalid zone '%s'\n"),
231 					    argv[i]);
232 					error = E_ERROR;
233 					continue;
234 				}
235 				/* make sure the zone is booted */
236 				if (id == -1) {
237 					warn(gettext("zone '%s' is not "
238 					    "active\n"), argv[i]);
239 					error = E_ERROR;
240 					continue;
241 				}
242 			} else if (idtype == P_PROJID) {
243 				if ((id = getprojidbyname(argv[i])) < 0) {
244 					warn(gettext("failed to get project "
245 					    "id for project: '%s'"), argv[i]);
246 					error = E_ERROR;
247 					continue;
248 				}
249 			} else {
250 				warn(gettext("invalid %s '%s'\n"),
251 				    idstr, argv[i]);
252 				error = E_ERROR;
253 				continue;
254 			}
255 		}
256 
257 		if (flags & pFLAG) {
258 			if (pool_set_binding(pool_name, idtype, id) !=
259 			    PO_SUCCESS) {
260 				warn(gettext("binding %s %ld to pool '%s': "
261 				    "%s\n"), idstr, id, pool_name,
262 				    get_errstr());
263 				error = E_ERROR;
264 			}
265 			continue;
266 		}
267 
268 		if (flags & qFLAG) {
269 			if ((poolname = pool_get_binding(id)) == NULL) {
270 				warn(gettext("couldn't determine binding for "
271 				    "pid %ld: %s\n"), id, get_errstr());
272 				error = E_ERROR;
273 			} else {
274 				(void) printf("%ld\t%s\n", id, poolname);
275 				free(poolname);
276 			}
277 		}
278 		if (flags & QFLAG) {
279 			uint_t j, count;
280 			const char **resource_types;
281 			(void) pool_resource_type_list(NULL, &count);
282 
283 			if ((resource_types = malloc(count *
284 			    sizeof (const char *))) == NULL) {
285 				warn(gettext("couldn't allocate query memory "
286 				    "for pid %ld: %s\n"), id, get_errstr());
287 				error = E_ERROR;
288 			}
289 			(void) pool_resource_type_list(resource_types, &count);
290 
291 			for (j = 0; j < count; j++)
292 				(void) print_resource_binding(resource_types[j],
293 				    (pid_t)id);
294 			free(resource_types);
295 		}
296 	}
297 }
298