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