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