From 9df408f8c6cfb323a1dad871241361e2692e1e57 Mon Sep 17 00:00:00 2001 From: Christoph Lohmann <20h@r-36.net> Date: Fri, 14 Jun 2013 18:55:25 +0200 Subject: [PATCH] Adding who, chroot, env and split. Thanks "Galos, David" ! --- Makefile | 4 ++ TODO | 4 -- chroot.1 | 26 +++++++++++ chroot.c | 38 +++++++++++++++ env.1 | 41 +++++++++++++++++ env.c | 44 ++++++++++++++++++ split.1 | 58 +++++++++++++++++++++++ split.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ who.1 | 24 ++++++++++ who.c | 37 +++++++++++++++ 10 files changed, 410 insertions(+), 4 deletions(-) create mode 100644 chroot.1 create mode 100644 chroot.c create mode 100644 env.1 create mode 100644 env.c create mode 100644 split.1 create mode 100644 split.c create mode 100644 who.1 create mode 100644 who.c diff --git a/Makefile b/Makefile index d90d690..05c12dd 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/TODO b/TODO index 217829f..00d3839 100644 --- a/TODO +++ b/TODO @@ -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] diff --git a/chroot.1 b/chroot.1 new file mode 100644 index 0000000..48cbe19 --- /dev/null +++ b/chroot.1 @@ -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) diff --git a/chroot.c b/chroot.c new file mode 100644 index 0000000..3abab0f --- /dev/null +++ b/chroot.c @@ -0,0 +1,38 @@ +#include +#include +#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"); +} diff --git a/env.1 b/env.1 new file mode 100644 index 0000000..b77fb2f --- /dev/null +++ b/env.1 @@ -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) + diff --git a/env.c b/env.c new file mode 100644 index 0000000..718b13e --- /dev/null +++ b/env.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include +#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"); +} diff --git a/split.1 b/split.1 new file mode 100644 index 0000000..e615168 --- /dev/null +++ b/split.1 @@ -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) diff --git a/split.c b/split.c new file mode 100644 index 0000000..87e1099 --- /dev/null +++ b/split.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include +#include +#include +#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; +} + diff --git a/who.1 b/who.1 new file mode 100644 index 0000000..68ca7f1 --- /dev/null +++ b/who.1 @@ -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) + diff --git a/who.c b/who.c new file mode 100644 index 0000000..08c3c2b --- /dev/null +++ b/who.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include +#include +#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"); +} +