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