#include <sys/types.h>
#include <stdio.h>
#include <err.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <stdbool.h>
#include "top.h"
#include "utils.h"
#include "machine.h"
static char *next_field(char *);
static int scan_arg(char *, int *, char *);
static char *err_string(void);
static size_t str_adderr(char *, size_t, int);
static size_t str_addarg(char *, size_t, char *, int);
static int err_compar(const void *, const void *);
static char *
next_field(char *str)
{
char *spaces = " \t";
size_t span;
span = strcspn(str, spaces);
if (span == strlen(str))
return (NULL);
str += span;
*str++ = '\0';
while (strcspn(str, spaces) == 0)
str++;
if (*str == '\0')
return (NULL);
return(str);
}
static int
scan_arg(char *str, int *intp, char *nptr)
{
int val = 0, bad_flag = 0;
char ch;
*nptr = '\0';
if (*str == '\0')
return (-1);
while ((ch = *str++) != '\0') {
if (isspace((unsigned char)ch))
break;
else if (!isdigit((unsigned char)ch))
bad_flag = 1;
else
val = val * 10 + (ch - '0');
*(nptr++) = ch;
}
*nptr = '\0';
if (bad_flag == 1)
return(-1);
*intp = val;
return (0);
}
#define ERRMAX 20
struct errs errs[ERRMAX];
int errcnt;
static char *err_toomany = " too many errors occurred";
static char *err_listem =
" Many errors occurred. Press `e' to display the list of errors.";
#define ERR_RESET errcnt = 0
#define ERROR(p, e) \
if (errcnt >= ERRMAX) { \
return(err_toomany); \
} else { \
free(errs[errcnt].arg); \
if ((errs[errcnt].arg = strdup(p)) == NULL) \
err(1, "strdup"); \
errs[errcnt++].err = (e); \
}
#define STRMAX 80
static char *
err_string(void)
{
int cnt = 0, first = true, currerr = -1;
static char string[STRMAX];
struct errs *errp;
if (errcnt == 0)
return (NULL);
qsort(errs, errcnt, sizeof(struct errs), err_compar);
string[0] = ' ';
string[1] = '\0';
while (cnt < errcnt) {
errp = &(errs[cnt++]);
if (errp->err != currerr) {
if (currerr != -1) {
if (str_adderr(string, sizeof string, currerr) >
sizeof string - 2)
return (err_listem);
(void) strlcat(string, "; ", sizeof string);
}
currerr = errp->err;
first = true;
}
if (str_addarg(string, sizeof string, errp->arg, first) >=
sizeof string)
return (err_listem);
first = false;
}
if (str_adderr(string, sizeof string, currerr) >= sizeof string)
return (err_listem);
return (string);
}
static size_t
str_adderr(char *str, size_t len, int err)
{
size_t msglen;
char *msg;
msg = err == 0 ? "Not a number" : strerror(err);
if ((msglen = strlcat(str, ": ", len)) >= len)
return (msglen);
return (strlcat(str, msg, len));
}
static size_t
str_addarg(char *str, size_t len, char *arg, int first)
{
size_t msglen;
if (!first) {
if ((msglen = strlcat(str, ", ", len)) >= len)
return (msglen);
}
return (strlcat(str, arg, len));
}
static int
err_compar(const void *e1, const void *e2)
{
const struct errs *p1 = (const struct errs *) e1;
const struct errs *p2 = (const struct errs *) e2;
int result;
if ((result = p1->err - p2->err) == 0)
return (strcmp(p1->arg, p2->arg));
return (result);
}
int
error_count(void)
{
return (errcnt);
}
char *
kill_procs(char *str)
{
int signum = SIGTERM, procnum;
uid_t uid, puid;
char tempbuf[TEMPBUFSIZE];
char *nptr, *tmp;
tmp = tempbuf;
ERR_RESET;
uid = getuid();
while (isspace((unsigned char)*str))
str++;
if (*str == '-') {
str++;
if ((nptr = next_field(str)) == NULL)
return (" kill: no processes specified");
if (isdigit((unsigned char)*str)) {
(void) scan_arg(str, &signum, tmp);
if (signum <= 0 || signum >= NSIG)
return (" invalid signal number");
} else {
for (signum = 0; signum < NSIG; signum++) {
if (strcasecmp(sys_signame[signum],
str) == 0)
break;
}
if (signum == NSIG)
return (" bad signal name");
}
str = nptr;
}
nptr = tempbuf;
do {
if (scan_arg(str, &procnum, nptr) == -1) {
ERROR(nptr, 0);
} else {
puid = proc_owner(procnum);
if (puid == (uid_t)(-1)) {
ERROR(nptr, ESRCH);
} else if (uid && (uid != puid)) {
ERROR(nptr, EACCES);
} else if (kill(procnum, signum) == -1) {
ERROR(nptr, errno);
}
}
} while ((str = next_field(str)) != NULL);
return (err_string());
}
char *
renice_procs(char *str)
{
uid_t uid;
char negate;
int prio, procnum;
char tempbuf[TEMPBUFSIZE];
char *nptr;
ERR_RESET;
uid = getuid();
while (isspace((unsigned char)*str))
str++;
if ((negate = (*str == '-')) != 0) {
str++;
}
nptr = tempbuf;
procnum = scan_arg(str, &prio, nptr);
if (negate)
prio = -prio;
#if defined(PRIO_MIN) && defined(PRIO_MAX)
if (procnum == -1 || prio < PRIO_MIN || prio > PRIO_MAX)
return (" bad priority value");
#endif
if ((str = next_field(str)) == NULL)
return (" no processes specified");
do {
if (scan_arg(str, &procnum, nptr) == -1) {
ERROR(nptr, 0);
}
else if (uid && (uid != proc_owner(procnum))) {
ERROR(nptr, EACCES);
} else if (setpriority(PRIO_PROCESS, procnum, prio) == -1) {
ERROR(nptr, errno);
}
} while ((str = next_field(str)) != NULL);
return (err_string());
}