/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
* 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 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wait.h>
#include <search.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/priocntl.h>
#include <procfs.h>
#include <macros.h>
#include <libgen.h>
#include <limits.h>
#include <errno.h>
#include "priocntl.h"
/*
* This file contains the code implementing the class independent part
* of the priocntl command. Most of the useful work for the priocntl
* command is done by the class specific sub-commands, the code for
* which is elsewhere. The class independent part of the command is
* responsible for executing the appropriate class specific sub-commands
* and providing any necessary input to the sub-commands.
* Code in this file should never assume any knowledge of any specific
* scheduler class (other than the SYS class).
*/
typedef struct classpids {
int clp_pidlistsz;
int clp_npids;
} classpids_t;
static char usage[] =
"usage: priocntl -l\n\
priocntl -d [-i idtype] [idlist]\n\
priocntl -s [-c class] [c.s.o.] [-i idtype] [idlist]\n\
priocntl -e [-c class] [c.s.o.] command [argument(s)]\n";
static int print_classlist(void);
static void exec_cmd(char *, char **);
static int print_procs(idtype_t, int, char *[]);
static void increase_pidlist(classpids_t *);
/*
* These variables are defined to be used in prio_getopt() below.
*/
static int prio_getopt();
/* LINTED static unused */
static int prio_optopt = 0;
static char *prio_optarg = 0;
int
{
int c;
char *clname;
char *idtypnm;
int idargc;
char **idargv;
switch (c) {
case 'l':
lflag++;
break;
case 'd':
dflag++;
break;
case 's':
sflag++;
break;
case 'e':
eflag++;
break;
case 'c':
cflag++;
break;
case 'i':
iflag++;
break;
case '?':
/*
* getopt() will return ? if either
* of these appear without an argument.
*/
}
/*
* We assume for now that any option that
* getopt() doesn't recognize (with the
* exception of c and i) is intended for a
* class specific subcommand. For now we also
* require that all class specific options
* take an argument (until we can get smarter
* about parsing our options).
*/
csoptsflag++;
prio_optind++;
prio_sp = 1;
break;
default:
break;
}
}
if (lflag) {
return (print_classlist());
} else if (dflag) {
if (iflag) {
idtypnm);
} else {
}
if (prio_optind < argc) {
} else {
idargc = 0;
}
} else if (sflag) {
if (iflag) {
idtypnm);
} else {
}
if (cflag == 0)
if (prio_optind < argc) {
} else {
idargc = 0;
}
} else if (eflag) {
if (cflag == 0)
if (prio_optind >= argc)
} else {
}
return (0);
}
/*
* Print the heading for the class list and execute the class
* specific sub-command with the -l option for each configured class.
*/
static int
print_classlist(void)
{
int nclass;
int status;
int error = 0;
/*
* No special privileges required for this operation.
* Set the effective UID back to the real UID.
*/
fatalerr("%s: Can't set effective UID back to real UID\n",
cmdpath);
fatalerr("%s: Can't get number of configured classes, priocntl"
(void) printf("CONFIGURED CLASSES\n==================\n\n");
(void) printf("SYS (System Class)\n");
(void) printf("\n");
fatalerr("%s: can't get class name (class ID = %ld)\n",
sizeof (subcmdpath))
fatalerr("%s: can't generate %s specific subcommand\n",
fatalerr("\tCan't execute %s specific subcommand\n",
"Can't execute %s specific subcommand)\n",
error = 1;
} else {
if (status)
error = 1;
}
}
return (error);
}
/*
* For each class represented within the set of processes specified by
* with the -d option. We pipe to each sub-command a list of pids in
* the set belonging to that class.
*/
static int
{
int i;
int nids;
int nclass;
int pidexists;
int error = 0;
/*
* Build a list of ids eliminating any duplicates in idargv.
*/
/*
* No idlist should be specified. If one is specified,
* it is ignored.
*/
nids = 0;
} else if (idargc == 0) {
/*
* No ids supplied by user; use current id.
*/
fatalerr("%s: Can't get ID for current process,"
nids = 1;
} else {
nids = 0;
" unconfigured class %s in idlist"
error = 1;
}
} else {
if (errno) {
"%s: Invalid id \"%s\"\n",
error = 1;
}
}
/*
* lsearch(3C) adds ids to the idlist,
* eliminating duplicates.
*/
}
}
fatalerr("%s: Can't get number of configured classes, priocntl"
NULL)
fatalerr("%s: Can't get class name, cid = %ld\n",
/*
* The memory allocation for the pidlist uses realloc().
* A realloc() call is required, when "clp_npids" is
* equal to "clp_pidlistsz".
*/
}
/*
* Build the pidlist.
*/
/*
* No need for special privileges any more.
* Set the effective UID back to the real UID.
*/
fatalerr("%s: Can't set effective UID back to real UID\n",
cmdpath);
pidexists = 0;
continue;
pidexists = 1;
"Can't generate %s specific subcommand\n",
error = 1;
continue;
}
"Can't execute %s specific subcommand\n",
error = 1;
continue;
}
if (pclose(pipe_to_subcmd))
error = 1;
}
if (pidexists == 0)
return (error);
}
/*
* Execute the appropriate class specific sub-command with the arguments
* pointed to by subcmdargv. If the user specified a class we simply
* exec the sub-command for that class. If no class was specified we
* all in the same class and then execute the sub-command for that class.
*/
static void
char *clname;
int idargc;
char **idargv;
char **subcmdargv;
{
char *fname;
int procfd;
int saverr;
/*
* No class specified by user but only one process
* in specified set. Get the class the easy way.
*/
if (idargc == 0) {
fatalerr("%s: Process not found.\n",
cmdpath);
else
fatalerr("%s: Can't get class of"
" current process\npriocntl"
" system call failed with"
} else {
/* idargc == 1 */
if (errno)
idargv[0]);
fatalerr("%s: Process not found.\n",
cmdpath);
else
fatalerr("%s: Can't get class of "
" specified process\npriocntl"
" system call failed with"
}
/*
* No class specified by user and potentially more
* than one process in specified set. Verify that
* all procs in set are in the same class.
*/
/*
* No ids supplied by user; use current id.
*/
fatalerr("%s: Can't get ID string for current"
}
fatalerr("%s: Can't open PROC directory %s\n",
continue;
/* Really max(sizeof ("psinfo"), sizeof ("cred")) */
"%s: skipping %s, name too long.\n",
continue;
}
continue;
sizeof (prinfo)) {
goto retry;
"%s: Can't get process info for"
}
continue;
}
sizeof (prcred)) {
if (procfd >= 0)
goto retry;
"%s: Can't get process"
" credentials for %s\n",
}
continue;
}
}
continue;
switch (idtype) {
case P_PID:
break;
case P_PPID:
break;
case P_PGID:
break;
case P_SID:
break;
case P_CID:
break;
case P_UID:
break;
case P_GID:
break;
case P_PROJID:
break;
case P_TASKID:
break;
case P_ZONEID:
break;
case P_CTID:
break;
case P_ALL:
break;
default:
fatalerr("%s: Bad idtype %d in set_procs()\n",
}
/*
* First proc found in set.
*/
fatalerr("%s: Specified processes"
" from different classes.\n",
cmdpath);
}
}
}
} else {
/*
* User specified class. Check it for validity.
*/
fatalerr("%s: Invalid or unconfigured class %s\n",
}
/*
* No need for special privileges any more.
* Set the effective UID back to the real UID.
*/
fatalerr("%s: Can't set effective UID back to real UID\n",
cmdpath);
fatalerr("%s: can't generate %s specific subcommand\n",
subcmdargv[0] = subcmdpath;
}
/*
* Execute the appropriate class specific sub-command with the arguments
* pointed to by subcmdargv. If the user specified a class we simply
* exec the sub-command for that class. If no class was specified we
* execute the sub-command for our own current class.
*/
static void
char *clname;
char **subcmdargv;
{
/*
* No special privileges required for this operation.
* Set the effective UID back to the real UID.
*/
fatalerr("%s: Can't set effective UID back to real UID\n",
cmdpath);
fatalerr("%s: Can't get class name of current process\n"
"priocntl system call failed with errno %d\n",
} else {
/*
* User specified class. Check it for validity.
*/
fatalerr("%s: Invalid or unconfigured class %s\n",
}
fatalerr("%s: can't generate %s specific subcommand\n",
subcmdargv[0] = subcmdpath;
}
/*
* Fill in the classpids structures in the array pointed to by clpids
* We read the /proc/<pid>/psinfo file to get the necessary process
* information.
*/
static void
int nids;
int nclass;
{
char *fname;
int procfd;
int saverr;
int i;
char *clname;
fatalerr("%s: Can't open PROC directory %s\n",
continue;
/* Really max(sizeof ("psinfo"), sizeof ("cred")) */
"%s: skipping %s, name too long.\n",
continue;
}
continue;
goto retry;
"%s: Can't get process info for %s\n",
}
continue;
}
sizeof (prcred)) {
goto retry;
"%s: Can't get process credentials"
" for %s\n",
}
continue;
}
}
continue;
switch (idtype) {
case P_PID:
for (i = 0; i < nids; i++) {
}
break;
case P_PPID:
for (i = 0; i < nids; i++) {
}
break;
case P_PGID:
for (i = 0; i < nids; i++) {
}
break;
case P_SID:
for (i = 0; i < nids; i++) {
}
break;
case P_CID:
for (i = 0; i < nids; i++) {
}
break;
case P_UID:
for (i = 0; i < nids; i++) {
}
break;
case P_GID:
for (i = 0; i < nids; i++) {
}
break;
case P_PROJID:
for (i = 0; i < nids; i++) {
}
break;
case P_TASKID:
for (i = 0; i < nids; i++) {
}
break;
case P_ZONEID:
for (i = 0; i < nids; i++) {
}
break;
case P_CTID:
for (i = 0; i < nids; i++) {
}
break;
case P_ALL:
break;
default:
fatalerr("%s: Bad idtype %d in ids2pids()\n",
}
}
}
/*
* Search the array pointed to by clpids for the classpids
* structure corresponding to clname and add pid to its
* pidlist.
*/
static void
int nclass;
char *clname;
{
return;
}
}
}
static void
{
/*
* The pidlist is filled up and we cannot increase the size.
*/
}
/*
* Compare id strings for equality. If idargv contains ids
* (idargc > 0) compare idstr to each id in idargv, otherwise
* just compare to curidstr.
*/
static boolean_t
char *idstr;
char *curidstr;
int idargc;
char **idargv;
{
int i;
if (idargc == 0) {
return (B_TRUE);
} else {
for (i = 0; i < idargc; i++) {
return (B_TRUE);
}
}
return (B_FALSE);
}
/*
* This is a copy of the getopt() function found in libc:getopt.c. A separate
* copy is required to fix the bug id #1114636. To fix the problem we need to
* reset the _sp to 1. Since _sp in libc:getopt() is not exposed, a copy of
* the getopt() is kept so that prio_sp can be reset to 1.
*/
static int
int argc;
#ifdef __STDC__
#else
#endif
{
register char c;
register char *cp;
if (prio_sp == 1)
if (prio_optind >= argc ||
return (EOF);
prio_optind++;
return (EOF);
}
prio_optind++;
prio_sp = 1;
}
return ('?');
}
if (*++cp == ':') {
else if (++prio_optind >= argc) {
prio_sp = 1;
return ('?');
} else
prio_sp = 1;
} else {
prio_sp = 1;
prio_optind++;
}
prio_optarg = NULL;
}
return (c);
}