Various fixes, add renice command.

This commit adds the renice command and its man page,
it also introduces some fixes:
* Makes nice command more solid, it also makes it respect POSIX return values.
* Fixes estrtol, which produced a misleading error on out of range errors.
* Fixes chgrp.1 NAME section.

Signed-off-by: Christoph Lohmann <20h@r-36.net>
This commit is contained in:
Lorenzo Cogotti 2013-06-11 20:33:52 +02:00 committed by Christoph Lohmann
parent c3b771d682
commit 75c97de593
6 changed files with 245 additions and 23 deletions

View File

@ -51,6 +51,7 @@ SRC = \
paste.c \ paste.c \
printenv.c \ printenv.c \
pwd.c \ pwd.c \
renice.c \
rm.c \ rm.c \
rmdir.c \ rmdir.c \
sleep.c \ sleep.c \

View File

@ -1,6 +1,6 @@
.TH CHGRP 1 sbase\-VERSION .TH CHGRP 1 sbase\-VERSION
.SH NAME .SH NAME
nice \- invoke a utility with an altered nice value chgrp \- change the file group ownership
.SH SYNOPSIS .SH SYNOPSIS
.B chgrp .B chgrp
.RB [ \-R ] .RB [ \-R ]

42
nice.c
View File

@ -1,38 +1,44 @@
/* See LICENSE file for copyright and license details. */ /* See LICENSE file for copyright and license details. */
#include <unistd.h> #include <errno.h>
#include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <unistd.h>
#include <string.h>
#include "util.h" #include "util.h"
static void static void eusage(void);
usage(void)
{
eprintf("usage: nice [-n inc] command [options ...]\n");
}
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
int inc = 10; long val = 10;
ARGBEGIN { ARGBEGIN {
case 'n': case 'n':
inc = atoi(EARGF(usage())); val = estrtol(EARGF(eusage()), 10);
break; break;
default: default:
usage(); eusage();
break;
} ARGEND; } ARGEND;
nice(inc); /* POSIX specifies the nice failure still invokes the command. */ if(argc == 0)
eusage();
if(!*argv) errno = 0;
usage(); nice((int)MAX(INT_MIN, MIN(val, INT_MAX)));
if(errno != 0)
perror("can't adjust niceness");
execvp(*argv, argv); /* POSIX specifies the nice failure still invokes the command */
eprintf("nice: '%s': %s\n", *argv, strerror(errno)); execvp(argv[0], argv);
/* reached only on failure */
return EXIT_FAILURE; perror(argv[0]);
return (errno == ENOENT)? 127 : 126;
} }
static void
eusage(void)
{
eprintf("usage: nice [-n inc] command [options ...]\n");
}

97
renice.1 Normal file
View File

@ -0,0 +1,97 @@
.TH PASTE 1 renice-VERSION "Jun 2013"
.SH NAME
renice \- set nice values of running processes
.SH "SYNOPSIS"
.PP
.B renice
.B \-n
.I increment
[
.B \-g
|
.B \-p
|
.B \-u
]
.I ID...
.SH DESCRIPTION
The
.B renice
utility requests that the nice values of one or more
running processes be changed. By default, the applicable processes
are specified by their process IDs. When a process group is specified
(see
.B -g
), the request applies to all processes in the process group. If the
requested increment would raise or lower the nice value of the
executed utility beyond its limits, then the limit whose value was
exceeded is used. When a user is reniced, the request applies to all
processes whose saved set-user-ID matches the user ID corresponding to
the user. Regardless of which options are supplied or any other factor,
renice does not alter the nice values of any process unless the user
requesting such a change has appropriate privileges to do so for the
specified process. If the user lacks appropriate privileges to perform
the requested action, the utility returns an error status.
The saved set-user-ID of the user's process is checked instead of its
effective user ID when renice attempts to determine the user ID of the
process in order to determine whether the user has appropriate privileges.
.SH OPTIONS
.TP
.B \-g
interpret all operands as unsigned decimal integer process group IDs.
.TP
.B \-n
.I increment
specify how the nice value of the specified process or processes
is to be adjusted. The increment option-argument is a positive or
negative decimal integer used to modify the nice value of the
specified process or processes. positive increment values cause a
lower nice value. Negative increment values may require appropriate
privileges and cause a higher nice value.
.TP
.B \-p
interpret all operands as unsigned decimal integer process IDs.
The
.B \-p
option is the default if no options are specified.
.TP
.B \-u
interpret all operands as users. If a user exists with a user name
equal to the operand, then the user ID of that user is used in further
processing. Otherwise, if the operand represents an unsigned decimal
integer, used as the numeric user ID of the user.
.SH EXIT VALUES
On successful completion 0 is returned, a value which is >0 is
returned on error.
.SH FILES
.TP
.I /etc/passwd
used to map user names to user ID's.
.SH CONFORMING TO
The
.B renice
utility is IEEE Std 1003.1-2001 (POSIX.1) compatible.
.SH EXAMPLES
.TP
.I "renice -n 5 -p 987 32"
.PP
Adjust the nice value so that process IDs 987 and 32 would have a
lower nice value.
.TP
.I "renice -n -4 -g 324 76"
.PP
Adjust the nice value so that group IDs 324 and 76 would have a
higher nice value, if the user has the appropriate privileges to do so.
.TP
.I "renice -n 4 -u 8 sas"
.PP
Adjust the nice value so that numeric user ID 8 and user sas would
have a lower nice value.
Useful nice value increments on historical systems include
19 or 20 (the affected processes run only when nothing else in the
system attempts to run) and any negative number
(to make processes run faster).
.SH AUTHOR
Written by Lorenzo Cogotti.
.SH SEE ALSO
.BR nice(1)

117
renice.c Normal file
View File

@ -0,0 +1,117 @@
/* See LICENSE file for copyright and license details. */
#include <errno.h>
#include <limits.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include "util.h"
static int strtop(const char *);
static bool renice(int, int, long);
static void eusage(void);
int
main(int argc, char **argv)
{
const char *adj = NULL;
long val;
int i, which = PRIO_PROCESS, status = 0;
ARGBEGIN {
case 'n':
adj = EARGF(eusage());
break;
case 'g':
which = PRIO_PGRP;
break;
case 'p':
which = PRIO_PROCESS;
break;
case 'u':
which = PRIO_USER;
break;
default:
eusage();
break;
} ARGEND;
if(argc == 0 || !adj)
eusage();
val = estrtol(adj, 10);
for(i = 0; i < argc; i++) {
int who = -1;
if(which == PRIO_USER) {
const struct passwd *pwd;
errno = 0;
do pwd = getpwnam(argv[i]); while(errno == EINTR);
if(pwd)
who = pwd->pw_uid;
else if(errno != 0) {
perror("can't read passwd");
status = 1;
continue;
}
}
if(who < 0)
who = strtop(argv[i]);
if(who < 0 || !renice(which, who, val))
status = 1;
}
return status;
}
static int
strtop(const char *s)
{
char *end;
long n;
errno = 0;
n = strtol(s, &end, 10);
if(*end != '\0') {
fprintf(stderr, "%s: not an integer\n", s);
return -1;
}
if(errno != 0 || n <= 0 || n > INT_MAX) {
fprintf(stderr, "%s: invalid value\n", s);
return -1;
}
return (int)n;
}
static bool
renice(int which, int who, long adj)
{
errno = 0;
adj += getpriority(which, who);
if(errno != 0) {
fprintf(stderr, "can't get %d nice level: %s\n",
who, strerror(errno));
return false;
}
adj = MAX(PRIO_MIN, MIN(adj, PRIO_MAX));
if(setpriority(which, who, (int)adj) == -1) {
fprintf(stderr, "can't set %d nice level: %s\n",
who, strerror(errno));
return false;
}
return true;
}
static void
eusage(void)
{
eprintf("renice -n inc [-g | -p | -u] ID ...\n");
}

View File

@ -13,13 +13,14 @@ estrtol(const char *s, int base)
errno = 0; errno = 0;
n = strtol(s, &end, base); n = strtol(s, &end, base);
if(*end != '\0' || errno != 0) { if(*end != '\0') {
if(base == 0) { if(base == 0)
eprintf("%s: not an integer\n", s); eprintf("%s: not an integer\n", s);
} else { else
eprintf("%s: not a base %d integer\n", s, base); eprintf("%s: not a base %d integer\n", s, base);
}
} }
if(errno != 0)
eprintf("%s:", s);
return n; return n;
} }