Adding who, chroot, env and split.

Thanks "Galos, David" <galosd83@students.rowan.edu>!
This commit is contained in:
Christoph Lohmann 2013-06-14 18:55:25 +02:00
parent b0898c605d
commit 9df408f8c6
10 changed files with 410 additions and 4 deletions

View File

@ -25,6 +25,7 @@ SRC = \
chgrp.c \
chmod.c \
chown.c \
chroot.c \
chvt.c \
cksum.c \
cmp.c \
@ -32,6 +33,7 @@ SRC = \
date.c \
dirname.c \
echo.c \
env.c \
false.c \
fold.c \
grep.c \
@ -53,6 +55,7 @@ SRC = \
rmdir.c \
sleep.c \
sort.c \
split.c \
sync.c \
tail.c \
tee.c \
@ -65,6 +68,7 @@ SRC = \
unlink.c \
seq.c \
wc.c \
who.c \
yes.c
OBJ = $(SRC:.c=.o) $(LIB)

4
TODO
View File

@ -10,8 +10,6 @@ diff [-ru] file1 file2
du [-hdi] [path]
env [-u] [name=value...] [command]
expand [-i] [-t N] [file...]
expr [expression]
@ -32,8 +30,6 @@ seq [-s string] [N [N]] N
sha1sum [-c] [file...]
split [-a N] [-b N] [-l N] [input [prefix]]
test [expression...]
tr string1 [string2]

26
chroot.1 Normal file
View File

@ -0,0 +1,26 @@
.TH CHROOT 1 sbase\-VERSION
.SH NAME
chroot \- invoke a command with a different root directory
.SH SYNOPSIS
.B chroot
.IR dir
.RI [ command
.RI [ arg ...]]
.SH DESCRIPTION
.B chroot
runs
.IR command
after changing the root directory to
.IR dir
with the
.B chroot
system call, and changing the working directory to the new root.
If
.IR command
is not specified, an interactive shell is started in the new root.
.SH SEE ALSO
.IR chroot (2)
.IR chdir (2)

38
chroot.c Normal file
View File

@ -0,0 +1,38 @@
#include <stdlib.h>
#include <unistd.h>
#include "util.h"
static void usage(void);
int
main(int argc, char **argv)
{
char *shell[] = {"/bin/sh", "-i", NULL};
if(getenv("SHELL"))
shell[0] = getenv("SHELL");
if(argc < 2)
usage();
if(chroot(argv[1]) == -1)
eprintf("chroot: '%s':", argv[1]);
if(chdir("/") == -1)
eprintf("chroot:");
if(argc == 2) {
execvp(*shell, shell);
} else {
execvp(argv[2], argv+2);
}
eprintf("chroot: '%s':", argv[2]);
return 1;
}
void
usage(void)
{
eprintf("usage: chroot dir [command [arg...]]\n");
}

41
env.1 Normal file
View File

@ -0,0 +1,41 @@
.TH ENV 1 sbase\-VERSION
.SH NAME
env \- modify the environment, then print it or run a command.
.SH SYNOPSIS
.B env
.RB [ \-i ]
.RB [ \-u
.IR name ]...
.RI [ name=value ]...
.RI [ cmd
.RI [ arg ...]]
.SH DESCRIPTION
.B env
removes part of the environment according to the flags, then adds or
sets each variable specified by
.IR name
to equal
.IR value .
If
.IR cmd
is given, it is executed in this new environment; otherwise, the
modified environment is printed to standard out.
.SH OPTIONS
.TP
.B \-i
Comptetely ignore the existing environment; start fresh.
.TP
.B \-u name
Unsets
.IR name
from the environment.
.SH SEE ALSO
.IR printenv (1)
.IR putenv (3)
.IR environ (7)

44
env.c Normal file
View File

@ -0,0 +1,44 @@
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "util.h"
extern char **environ;
static void usage(void);
int
main(int argc, char **argv)
{
ARGBEGIN {
case 'i':
clearenv();
break;
case 'u':
unsetenv(EARGF(usage()));
break;
default:
usage();
} ARGEND;
for(; *argv && strchr(*argv, '='); argv++)
putenv(*argv);
if(*argv) {
execvp(*argv, argv);
enprintf(127-(errno!=EEXIST), "env: '%s':", *argv);
}
while(environ && *environ)
printf("%s\n", *environ++);
return 0;
}
void
usage(void)
{
eprintf("usage: env [-i] [-u name]... [name=value]... [cmd [arg...]]\n");
}

58
split.1 Normal file
View File

@ -0,0 +1,58 @@
.TH SPLIT 1 sbase\-VERSION
.SH NAME
split \- split up a file
.SH SYNOPSIS
.B split
.RB [ \-d ]
.RB [ \-a
.IR len ]
.RB [ \-b
.RI [ bytes [k|m|g]]]
.RB [ \-l
.RI [ lines ]]
.RI [ input
.RI [ prefix ]]
.SH DESCRIPTION
.B split
Reads a file, splitting it into smaller files, every
.IR bytes
bytes
or
.IR lines
lines. If
.B split
runs out of filenames before all the data can be written, it stops at the
last valid filename, leaving all the written data on the disk.
The
.IR b
and
.IR l
flags are mutually exclusive. Only the last one specified will be obeyed.
.SH OPTIONS
.TP
.B \-d
Use decimal suffixes rather than alphabetical.
.TP
.B \-a "len"
Set the suffix length to
.IR len
characters long.
.TP
.B \-b [bytes[k|m|g]]
Start a new file every
.IR bytes
bytes. The units k, m, and g are case insensitive, and powers of 2, not 10.
.TP
.B \-l [lines]
Start a new file every
.IR lines
lines.
.SH SEE ALSO
.IR cat (1)

138
split.c Normal file
View File

@ -0,0 +1,138 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include "util.h"
static int itostr(char *, int, int);
static FILE *nextfile(FILE *, char *, int, int);
static void usage(void);
static int base = 26, start = 'a';
int
main(int argc, char **argv)
{
int plen, slen = 2;
int ch;
char name[NAME_MAX+1];
char *prefix = "x";
char *file = NULL;
char *tmp, *end;
uint64_t sizes['M'+1];
uint64_t size = 1000, scale, n;
int always = 0;
FILE *in=stdin, *out=NULL;
sizes['K'] = 1024;
sizes['M'] = 1024L*1024L;
sizes['G'] = 1024L*1024L*1024L;
ARGBEGIN {
case 'b':
always = 1;
tmp = ARGF();
if(tmp == NULL)
break;
size = strtoull(tmp, &end, 10);
if(*end == '\0')
break;
if(strchr("KMG", toupper(*end)) == NULL || end[1] != '\0')
usage();
scale = sizes[toupper(*end)];
if(size > (UINT64_MAX/scale))
eprintf("split: '%s': out of range\n", tmp);
size *= scale;
break;
case 'l':
always = 0;
tmp = ARGF();
if(tmp)
size = estrtol(tmp, 10);
break;
case 'a':
slen = estrtol(EARGF(usage()), 10);
break;
case 'd':
base = 10;
start = '0';
break;
default:
usage();
} ARGEND;
if(*argv)
file = *argv++;
if(*argv)
prefix = *argv++;
if(*argv)
usage();
plen = strlen(prefix);
if(plen+slen > NAME_MAX)
eprintf("split: names cannot exceed %d bytes", NAME_MAX);
strcpy(name, prefix);
if(file && strcmp(file, "-") != 0) {
in = fopen(file, "r");
if(!in)
eprintf("split: '%s':", file);
}
Nextfile:
while((out = nextfile(out, name, plen, slen))) {
n = 0;
while((ch = getc(in)) != EOF) {
putc(ch, out);
n += (always || ch == '\n');
if(n >= size)
goto Nextfile;
}
fclose(out);
break;
}
return 0;
}
void
usage(void)
{
eprintf("usage: split [-d] [-a len] [-b [bytes[k|m|g]]] [-l [lines]] [input [prefix]]\n");
}
int
itostr(char *str, int x, int n)
{
str[n] = '\0';
while(n-- > 0) {
str[n] = start + (x % base);
x /= base;
}
if(x)
return -1;
return 0;
}
FILE *
nextfile(FILE *f, char *buf, int plen, int slen)
{
static int n = 0;
int s;
if(f)
fclose(f);
s = itostr(buf+plen, n++, slen);
if(s == -1)
return NULL;
f = fopen(buf, "w");
if(!f)
eprintf("split: '%s':", buf);
return f;
}

24
who.1 Normal file
View File

@ -0,0 +1,24 @@
.TH WHO 1 sbase\-VERSION
.SH NAME
who \- print who has logged on
.SH SYNOPSIS
.B who
.SH DESCRIPTION
.B who
prints a list of who has logged on, their controlling tty, and the
time at which they logged on.
.SH BUGS
.B who
relies on the utmp file to be updated responsibly. This
doesn't always happen, which can cause who to print completely
bogus data.
musl\-libc currently implements all utmpx functions as stubs Obviously,
this command cannot work under such conditions.
.SH SEE ALSO
.IR getutxent (3)
.IR utmpx (5)

37
who.c Normal file
View File

@ -0,0 +1,37 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <utmpx.h>
#include "util.h"
static void usage(void);
int
main(int argc, char **argv)
{
struct utmpx *ut;
time_t t;
char timebuf[sizeof "yyyy-mm-dd hh:mm"];
if(argc!=1)
usage();
while((ut=getutxent())) {
if(ut->ut_type != USER_PROCESS)
continue;
t = ut->ut_tv.tv_sec;
strftime(timebuf, sizeof timebuf, "%Y-%m-%d %H:%M", localtime(&t));
printf("%-8s %-12s %-16s\n", ut->ut_user, ut->ut_line, timebuf);
}
endutxent();
return 0;
}
void
usage(void)
{
eprintf("usage: who\n");
}