/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
* poolbind - bind processes, tasks, and projects to pools, and query process
* pool bindings
*/
#include <libgen.h>
#include <pool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <locale.h>
#include <libintl.h>
#include <sys/procset.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <project.h>
#include <zone.h>
#include "utils.h"
#ifndef TEXT_DOMAIN
#define TEXT_DOMAIN "SYS_TEST"
#endif
#define eFLAG 0x1
#define iFLAG 0x2
#define pFLAG 0x4
#define qFLAG 0x8
#define QFLAG 0x10
static const char OPTS[] = "Qei:p:q";
static struct {
idtype_t idtype;
char *str;
} idtypes[] = {
{ P_PID, "pid" },
{ P_TASKID, "taskid" },
{ P_PROJID, "projid" },
{ P_PROJID, "project" },
{ P_ZONEID, "zoneid" },
{ -1, NULL }
};
int error = E_PO_SUCCESS;
void exec_cmd(char *, char *[]);
void process_ids(char *, uint_t, idtype_t, char *, int, char *[]);
void
usage(void)
{
(void) fprintf(stderr,
gettext("Usage:\n"
" poolbind -p pool_name -e command [arguments...]\n"
" poolbind -p pool_name "
"[-i pid | -i taskid | -i projid | -i zoneid] id ...\n"
" poolbind -q pid ...\n"
" poolbind -Q pid ... \n"));
exit(E_USAGE);
}
int
print_resource_binding(const char *type, pid_t pid)
{
char *resource_name;
if ((resource_name = pool_get_resource_binding(type, pid)) == NULL)
warn(gettext("getting '%s' binding for %d: %s\n"), type,
(int)pid, get_errstr());
else
(void) printf("%d\t%s\t%s\n", (int)pid, type, resource_name);
free(resource_name);
return (PO_SUCCESS);
}
int
main(int argc, char *argv[])
{
char c;
int i;
idtype_t idtype = P_PID;
char *idstr = "pid";
char *pool_name = NULL;
uint_t flags = 0;
int status;
(void) getpname(argv[0]);
(void) setlocale(LC_ALL, "");
(void) textdomain(TEXT_DOMAIN);
while ((c = getopt(argc, argv, OPTS)) != EOF) {
switch (c) {
case 'Q':
if (flags & (qFLAG | iFLAG | pFLAG))
usage();
flags |= QFLAG;
break;
case 'e':
if (flags & (iFLAG | qFLAG | QFLAG))
usage();
flags |= eFLAG;
break;
case 'i':
for (i = 0; idtypes[i].str != NULL; i++) {
if (strcmp(optarg, idtypes[i].str) == 0) {
idtype = idtypes[i].idtype;
idstr = idtypes[i].str;
break;
}
}
if ((flags & (iFLAG | qFLAG | QFLAG)) ||
idtypes[i].str == NULL)
usage();
flags |= iFLAG;
break;
case 'p':
if (flags & (pFLAG | qFLAG | QFLAG))
usage();
flags |= pFLAG;
pool_name = optarg;
break;
case 'q':
if (flags & (pFLAG | iFLAG | QFLAG))
usage();
flags |= qFLAG;
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
if (flags & eFLAG && pool_name == NULL)
usage();
if (argc < 1 || (flags & (pFLAG | qFLAG | QFLAG)) == 0)
usage();
/*
* Check to see that the pools facility is enabled
*/
if (pool_get_status(&status) != PO_SUCCESS)
die((ERR_OPEN_DYNAMIC), get_errstr());
if (status == POOL_DISABLED)
die((ERR_OPEN_DYNAMIC), strerror(ENOTACTIVE));
if (flags & eFLAG)
exec_cmd(pool_name, argv);
/*NOTREACHED*/
else
process_ids(pool_name, flags, idtype, idstr, argc, argv);
return (error);
}
void
exec_cmd(char *pool_name, char *argv[])
{
if (pool_set_binding(pool_name, P_PID, getpid()) != PO_SUCCESS) {
warn(gettext("binding to pool '%s': %s\n"), pool_name,
get_errstr());
error = E_ERROR;
return;
}
if (execvp(argv[0], argv) == -1)
die(gettext("exec of %s failed"), argv[0]);
/*NOTREACHED*/
}
void
process_ids(char *pool_name, uint_t flags, idtype_t idtype, char *idstr,
int argc, char *argv[])
{
int i;
id_t id;
for (i = 0; i < argc; i++) {
char *endp;
char *poolname;
errno = 0;
id = (id_t)strtol(argv[i], &endp, 10);
if (errno != 0 ||
(endp && endp != argv[i] + strlen(argv[i])) ||
(idtype == P_ZONEID &&
getzonenamebyid(id, NULL, 0) == -1)) {
/*
* The string does not completely parse to
* an integer, or it represents an invalid
* zone id.
*/
/*
* It must be a project or zone name.
*/
if (idtype == P_ZONEID) {
if (zone_get_id(argv[i], &id) != 0) {
warn(gettext("invalid zone '%s'\n"),
argv[i]);
error = E_ERROR;
continue;
}
/* make sure the zone is booted */
if (id == -1) {
warn(gettext("zone '%s' is not "
"active\n"), argv[i]);
error = E_ERROR;
continue;
}
} else if (idtype == P_PROJID) {
if ((id = getprojidbyname(argv[i])) < 0) {
warn(gettext("failed to get project "
"id for project: '%s'"), argv[i]);
error = E_ERROR;
continue;
}
} else {
warn(gettext("invalid %s '%s'\n"),
idstr, argv[i]);
error = E_ERROR;
continue;
}
}
if (flags & pFLAG) {
if (pool_set_binding(pool_name, idtype, id) !=
PO_SUCCESS) {
warn(gettext("binding %s %ld to pool '%s': "
"%s\n"), idstr, id, pool_name,
get_errstr());
error = E_ERROR;
}
continue;
}
if (flags & qFLAG) {
if ((poolname = pool_get_binding(id)) == NULL) {
warn(gettext("couldn't determine binding for "
"pid %ld: %s\n"), id, get_errstr());
error = E_ERROR;
} else {
(void) printf("%ld\t%s\n", id, poolname);
free(poolname);
}
}
if (flags & QFLAG) {
uint_t j, count;
const char **resource_types;
(void) pool_resource_type_list(NULL, &count);
if ((resource_types = malloc(count *
sizeof (const char *))) == NULL) {
warn(gettext("couldn't allocate query memory "
"for pid %ld: %s\n"), id, get_errstr());
error = E_ERROR;
}
(void) pool_resource_type_list(resource_types, &count);
for (j = 0; j < count; j++)
(void) print_resource_binding(resource_types[j],
(pid_t)id);
free(resource_types);
}
}
}