├── LICENSE ├── Makefile ├── README ├── TODO ├── arg.h ├── blkdiscard.8 ├── blkdiscard.c ├── chvt.1 ├── chvt.c ├── clear.1 ├── clear.c ├── config.def.h ├── config.mk ├── ctrlaltdel.8 ├── ctrlaltdel.c ├── df.1 ├── df.c ├── dmesg.1 ├── dmesg.c ├── eject.1 ├── eject.c ├── fallocate.1 ├── fallocate.c ├── free.1 ├── free.c ├── freeramdisk.8 ├── freeramdisk.c ├── fsfreeze.8 ├── fsfreeze.c ├── getty.8 ├── getty.c ├── halt.8 ├── halt.c ├── hwclock.8 ├── hwclock.c ├── id.1 ├── id.c ├── insmod.8 ├── insmod.c ├── killall5.8 ├── killall5.c ├── last.c ├── lastlog.8 ├── lastlog.c ├── libutil ├── agetcwd.c ├── agetline.c ├── apathmax.c ├── concat.c ├── ealloc.c ├── eprintf.c ├── estrtol.c ├── estrtoul.c ├── explicit_bzero.c ├── passwd.c ├── proc.c ├── putword.c ├── recurse.c ├── strlcat.c ├── strlcpy.c ├── strtonum.c └── tty.c ├── login.1 ├── login.c ├── lsmod.8 ├── lsmod.c ├── lsusb.8 ├── lsusb.c ├── mesg.1 ├── mesg.c ├── mkswap.8 ├── mkswap.c ├── mount.8 ├── mount.c ├── mountpoint.1 ├── mountpoint.c ├── nologin.8 ├── nologin.c ├── pagesize.1 ├── pagesize.c ├── passwd.1 ├── passwd.c ├── passwd.h ├── pidof.1 ├── pidof.c ├── pivot_root.8 ├── pivot_root.c ├── proc.h ├── ps.1 ├── ps.c ├── pwdx.1 ├── pwdx.c ├── queue.h ├── readahead.8 ├── readahead.c ├── reboot.h ├── respawn.1 ├── respawn.c ├── rmmod.8 ├── rmmod.c ├── rtc.h ├── stat.1 ├── stat.c ├── stty.c ├── su.1 ├── su.c ├── swaplabel.8 ├── swaplabel.c ├── swapoff.8 ├── swapoff.c ├── swapon.8 ├── swapon.c ├── switch_root.8 ├── switch_root.c ├── sysctl.8 ├── sysctl.c ├── text.h ├── truncate.1 ├── truncate.c ├── umount.8 ├── umount.c ├── unshare.1 ├── unshare.c ├── uptime.1 ├── uptime.c ├── util.h ├── vmstat.c ├── vtallow.1 ├── vtallow.c ├── watch.1 ├── watch.c ├── who.1 └── who.c /LICENSE: -------------------------------------------------------------------------------- 1 | MIT/X Consortium License 2 | 3 | © 2013-2016 Dimitris Papapastamos 4 | © 2014-2016 Laslo Hunhold 5 | © 2014-2016 Hiltjo Posthuma 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | 25 | Authors/contributors include: 26 | 27 | © 2013 oblique 28 | © 2013 s-p-k 29 | © 2013 Jakob Kramer 30 | © 2013 David Galos 31 | © 2014 Carlos J. Torres 32 | © 2014 Roberto E. Vargas Caballero 33 | © 2014 Jan Tatje 34 | © 2015 Risto Salminen 35 | © 2019 Mattias Andrée 36 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include config.mk 2 | 3 | .SUFFIXES: 4 | .SUFFIXES: .o .c 5 | 6 | HDR = \ 7 | arg.h \ 8 | config.h \ 9 | passwd.h \ 10 | proc.h \ 11 | queue.h \ 12 | reboot.h \ 13 | rtc.h \ 14 | text.h \ 15 | util.h 16 | 17 | LIBUTIL = libutil.a 18 | LIBUTILSRC = \ 19 | libutil/agetcwd.c \ 20 | libutil/agetline.c \ 21 | libutil/apathmax.c \ 22 | libutil/concat.c \ 23 | libutil/ealloc.c \ 24 | libutil/eprintf.c \ 25 | libutil/estrtol.c \ 26 | libutil/estrtoul.c \ 27 | libutil/explicit_bzero.c \ 28 | libutil/passwd.c \ 29 | libutil/proc.c \ 30 | libutil/putword.c \ 31 | libutil/recurse.c \ 32 | libutil/strlcat.c \ 33 | libutil/strlcpy.c \ 34 | libutil/strtonum.c \ 35 | libutil/tty.c 36 | 37 | LIB = $(LIBUTIL) 38 | 39 | BIN = \ 40 | blkdiscard \ 41 | chvt \ 42 | clear \ 43 | ctrlaltdel \ 44 | df \ 45 | dmesg \ 46 | eject \ 47 | fallocate \ 48 | free \ 49 | freeramdisk \ 50 | fsfreeze \ 51 | getty \ 52 | halt \ 53 | hwclock \ 54 | id \ 55 | insmod \ 56 | killall5 \ 57 | last \ 58 | lastlog \ 59 | login \ 60 | lsmod \ 61 | lsusb \ 62 | mesg \ 63 | mkswap \ 64 | mount \ 65 | mountpoint \ 66 | nologin \ 67 | pagesize \ 68 | passwd \ 69 | pidof \ 70 | pivot_root \ 71 | ps \ 72 | pwdx \ 73 | readahead \ 74 | respawn \ 75 | rmmod \ 76 | stat \ 77 | stty \ 78 | su \ 79 | swaplabel \ 80 | swapoff \ 81 | swapon \ 82 | switch_root \ 83 | sysctl \ 84 | truncate \ 85 | umount \ 86 | unshare \ 87 | uptime \ 88 | vmstat \ 89 | vtallow \ 90 | watch \ 91 | who 92 | 93 | MAN1 = \ 94 | chvt.1 \ 95 | clear.1 \ 96 | df.1 \ 97 | dmesg.1 \ 98 | eject.1 \ 99 | fallocate.1 \ 100 | free.1 \ 101 | id.1 \ 102 | login.1 \ 103 | mesg.1 \ 104 | mountpoint.1 \ 105 | pagesize.1 \ 106 | passwd.1 \ 107 | pidof.1 \ 108 | ps.1 \ 109 | pwdx.1 \ 110 | respawn.1 \ 111 | stat.1 \ 112 | su.1 \ 113 | truncate.1 \ 114 | unshare.1 \ 115 | uptime.1 \ 116 | vtallow.1 \ 117 | watch.1 \ 118 | who.1 119 | 120 | MAN8 = \ 121 | ctrlaltdel.8 \ 122 | freeramdisk.8 \ 123 | fsfreeze.8 \ 124 | getty.8 \ 125 | halt.8 \ 126 | hwclock.8 \ 127 | insmod.8 \ 128 | killall5.8 \ 129 | lastlog.8 \ 130 | lsmod.8 \ 131 | lsusb.8 \ 132 | mkswap.8 \ 133 | mount.8 \ 134 | nologin.8 \ 135 | pivot_root.8 \ 136 | readahead.8 \ 137 | rmmod.8 \ 138 | swaplabel.8 \ 139 | swapoff.8 \ 140 | swapon.8 \ 141 | switch_root.8 \ 142 | sysctl.8 \ 143 | umount.8 144 | 145 | LIBUTILOBJ = $(LIBUTILSRC:.c=.o) 146 | OBJ = $(BIN:=.o) $(LIBUTILOBJ) 147 | SRC = $(BIN:=.c) 148 | 149 | all: $(BIN) 150 | 151 | $(BIN): $(LIB) 152 | 153 | $(OBJ): $(HDR) config.mk 154 | 155 | config.h: 156 | cp config.def.h $@ 157 | 158 | .o: 159 | $(CC) $(LDFLAGS) -o $@ $< $(LIB) $(LDLIBS) 160 | 161 | .c.o: 162 | $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< 163 | 164 | $(LIBUTIL): $(LIBUTILOBJ) 165 | $(AR) rc $@ $? 166 | $(RANLIB) $@ 167 | 168 | install: all 169 | mkdir -p $(DESTDIR)$(PREFIX)/bin 170 | cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin 171 | cd $(DESTDIR)$(PREFIX)/bin && chmod 755 $(BIN) 172 | mkdir -p $(DESTDIR)$(MANPREFIX)/man1 173 | for m in $(MAN1); do sed "s/^\.Os ubase/.Os ubase $(VERSION)/g" < "$$m" > $(DESTDIR)$(MANPREFIX)/man1/"$$m"; done 174 | mkdir -p $(DESTDIR)$(MANPREFIX)/man8 175 | for m in $(MAN8); do sed "s/^\.Os ubase/.Os ubase $(VERSION)/g" < "$$m" > $(DESTDIR)$(MANPREFIX)/man8/"$$m"; done 176 | cd $(DESTDIR)$(MANPREFIX)/man1 && chmod 644 $(MAN1) 177 | cd $(DESTDIR)$(MANPREFIX)/man8 && chmod 644 $(MAN8) 178 | 179 | uninstall: 180 | cd $(DESTDIR)$(PREFIX)/bin && rm -f $(BIN) 181 | cd $(DESTDIR)$(MANPREFIX)/man1 && rm -f $(MAN1) 182 | cd $(DESTDIR)$(MANPREFIX)/man8 && rm -f $(MAN8) 183 | 184 | dist: clean 185 | mkdir -p ubase-$(VERSION) 186 | cp -r LICENSE Makefile README TODO config.mk $(SRC) $(MAN1) $(MAN8) libutil $(HDR) config.def.h ubase-$(VERSION) 187 | tar -cf ubase-$(VERSION).tar ubase-$(VERSION) 188 | gzip ubase-$(VERSION).tar 189 | rm -rf ubase-$(VERSION) 190 | 191 | ubase-box: $(LIB) $(SRC) 192 | mkdir -p build 193 | cp $(HDR) build 194 | cp config.h build 195 | for f in $(SRC); do sed "s/^main(/`basename $$f .c`_&/" < $$f > build/$$f; done 196 | echo '#include ' > build/$@.c 197 | echo '#include ' >> build/$@.c 198 | echo '#include ' >> build/$@.c 199 | echo '#include ' >> build/$@.c 200 | echo '#include "util.h"' >> build/$@.c 201 | for f in $(SRC); do echo "int `basename $$f .c`_main(int, char **);" >> build/$@.c; done 202 | echo 'int main(int argc, char *argv[]) { char *s = basename(argv[0]); if(!strcmp(s,"ubase-box")) { argc--; argv++; s = basename(argv[0]); } if(0) ;' >> build/$@.c 203 | for f in $(SRC); do echo "else if(!strcmp(s, \"`basename $$f .c`\")) return `basename $$f .c`_main(argc, argv);" >> build/$@.c; done 204 | echo 'else {' >> build/$@.c 205 | for f in $(SRC); do echo "printf(\"`basename $$f .c`\"); putchar(' ');" >> build/$@.c; done 206 | echo "putchar(0xa); }; return 0; }" >> build/$@.c 207 | $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ build/*.c $(LIB) $(LDLIBS) 208 | rm -r build 209 | 210 | ubase-box-install: ubase-box 211 | mkdir -p $(DESTDIR)$(PREFIX)/bin 212 | cp -f ubase-box $(DESTDIR)$(PREFIX)/bin 213 | chmod 755 $(DESTDIR)$(PREFIX)/bin/ubase-box 214 | for f in $(BIN); do ln -sf ubase-box $(DESTDIR)$(PREFIX)/bin/"$$f"; done 215 | mkdir -p $(DESTDIR)$(MANPREFIX)/man1 216 | for m in $(MAN1); do sed "s/^\.Os ubase/.Os ubase $(VERSION)/g" < "$$m" > $(DESTDIR)$(MANPREFIX)/man1/"$$m"; done 217 | mkdir -p $(DESTDIR)$(MANPREFIX)/man8 218 | for m in $(MAN8); do sed "s/^\.Os ubase/.Os ubase $(VERSION)/g" < "$$m" > $(DESTDIR)$(MANPREFIX)/man8/"$$m"; done 219 | cd $(DESTDIR)$(MANPREFIX)/man1 && chmod 644 $(MAN1) 220 | cd $(DESTDIR)$(MANPREFIX)/man8 && chmod 644 $(MAN8) 221 | 222 | clean: 223 | rm -f $(BIN) $(OBJ) $(LIB) ubase-box ubase-$(VERSION).tar.gz 224 | 225 | .PHONY: 226 | all install uninstall dist ubase-box ubase-box-install clean 227 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ubase - suckless linux base utils 2 | ================================= 3 | 4 | ubase is a collection of tools similar in spirit to util-linux but 5 | much simpler. 6 | 7 | The complement of ubase is sbase[1] which mostly follows POSIX and 8 | provides all the portable tools. Together they are intended to form a 9 | base system similar to busybox but much smaller and suckless. 10 | 11 | Building 12 | -------- 13 | 14 | To build ubase, simply type make. You may have to fiddle with 15 | config.mk and config.h depending on your system. 16 | 17 | You can also build ubase-box, which generates a single binary 18 | containing all the required tools. You can then symlink the 19 | individual tools to ubase-box or run: make ubase-box-install. 20 | 21 | To run the tools for ubase-box directly use: ubase-box cmd [args] 22 | 23 | Ideally you will want to statically link ubase. We highly recommend 24 | using musl-libc[2]. 25 | 26 | ubase is known to compile with gcc, clang and tcc. 27 | 28 | [1] http://git.suckless.org/sbase/ 29 | [2] http://www.musl-libc.org/ 30 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Tools 2 | ===== 3 | 4 | acpi 5 | addgroup 6 | adduser 7 | blkid 8 | capchroot 9 | fakeroot 10 | fuser 11 | getcap 12 | ifconfig 13 | ionice 14 | less or pg 15 | losetup 16 | lsattr 17 | lspci 18 | mkswap [-L] 19 | partprobe 20 | pmap 21 | ps (support for more options) 22 | rfkill 23 | rmgroup 24 | rmuser 25 | setcap 26 | stty manpage 27 | tabs 28 | taskset 29 | top 30 | tput 31 | vmstat [-sdDpS] 32 | 33 | Misc 34 | ==== 35 | 36 | Beautify passwd(1). 37 | last(1) manpage. 38 | -------------------------------------------------------------------------------- /arg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copy me if you can. 3 | * by 20h 4 | */ 5 | 6 | #ifndef ARG_H__ 7 | #define ARG_H__ 8 | 9 | extern char *argv0; 10 | 11 | /* use main(int argc, char *argv[]) */ 12 | #define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ 13 | argv[0] && argv[0][0] == '-'\ 14 | && argv[0][1];\ 15 | argc--, argv++) {\ 16 | char argc_;\ 17 | char **argv_;\ 18 | int brk_;\ 19 | if (argv[0][1] == '-' && argv[0][2] == '\0') {\ 20 | argv++;\ 21 | argc--;\ 22 | break;\ 23 | }\ 24 | for (brk_ = 0, argv[0]++, argv_ = argv;\ 25 | argv[0][0] && !brk_;\ 26 | argv[0]++) {\ 27 | if (argv_ != argv)\ 28 | break;\ 29 | argc_ = argv[0][0];\ 30 | switch (argc_) 31 | 32 | /* Handles obsolete -NUM syntax */ 33 | #define ARGNUM case '0':\ 34 | case '1':\ 35 | case '2':\ 36 | case '3':\ 37 | case '4':\ 38 | case '5':\ 39 | case '6':\ 40 | case '7':\ 41 | case '8':\ 42 | case '9' 43 | 44 | #define ARGEND }\ 45 | } 46 | 47 | #define ARGC() argc_ 48 | 49 | #define ARGNUMF(base) (brk_ = 1, estrtol(argv[0], (base))) 50 | 51 | #define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\ 52 | ((x), abort(), (char *)0) :\ 53 | (brk_ = 1, (argv[0][1] != '\0')?\ 54 | (&argv[0][1]) :\ 55 | (argc--, argv++, argv[0]))) 56 | 57 | #define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\ 58 | (char *)0 :\ 59 | (brk_ = 1, (argv[0][1] != '\0')?\ 60 | (&argv[0][1]) :\ 61 | (argc--, argv++, argv[0]))) 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /blkdiscard.8: -------------------------------------------------------------------------------- 1 | .Dd July 2, 2018 2 | .Dt BLKDISCARD 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm blkdiscard 6 | .Nd discard sectors on a device 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Ar device 10 | .Sh DESCRIPTION 11 | .Nm 12 | is used to discard all device sectors on solid-state devices. 13 | -------------------------------------------------------------------------------- /blkdiscard.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "util.h" 12 | 13 | #define OFFSET_IDX 0 14 | #define LENGTH_IDX 1 15 | 16 | #define BLKDISCARD _IO(0x12, 119) 17 | 18 | static void 19 | usage(void) 20 | { 21 | eprintf("usage: %s device\n", argv0); 22 | } 23 | 24 | int 25 | main(int argc, char *argv[]) 26 | { 27 | uint64_t range[2]; 28 | int fd; 29 | 30 | ARGBEGIN { 31 | default: 32 | usage(); 33 | } ARGEND 34 | 35 | if (argc != 1) 36 | usage(); 37 | 38 | fd = open(argv[0], O_RDWR); 39 | if (fd < 0) 40 | eprintf("open: %s:", argv[0]); 41 | range[OFFSET_IDX] = 0; 42 | if (ioctl(fd, BLKGETSIZE64, &range[LENGTH_IDX]) < 0) 43 | eprintf("BLKGETSIZE64: %s:", argv[0]); 44 | if (ioctl(fd, BLKDISCARD, range) < 0) 45 | eprintf("BLKDISCARD: %s:", argv[0]); 46 | close(fd); 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /chvt.1: -------------------------------------------------------------------------------- 1 | .Dd September 7, 2015 2 | .Dt CHVT 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm chvt 6 | .Nd change foreground virtual terminal 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Ar num 10 | .Sh DESCRIPTION 11 | .Nm 12 | brings 13 | .Pf /dev/tty Ar num 14 | to the foreground. This has the same effect as 15 | .Pf Ctrl-Alt-F Ar num . 16 | -------------------------------------------------------------------------------- /chvt.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "util.h" 12 | 13 | #define KDGKBTYPE 0x4B33 /* get keyboard type */ 14 | 15 | #define VT_ACTIVATE 0x5606 /* make vt active */ 16 | #define VT_WAITACTIVE 0x5607 /* wait for vt active */ 17 | 18 | static char *vt[] = { 19 | "/proc/self/fd/0", 20 | "/dev/console", 21 | "/dev/tty", 22 | "/dev/tty0", 23 | }; 24 | 25 | static void 26 | usage(void) 27 | { 28 | eprintf("usage: %s num\n", argv0); 29 | } 30 | 31 | int 32 | main(int argc, char *argv[]) 33 | { 34 | unsigned int n, i; 35 | int fd; 36 | char c; 37 | 38 | ARGBEGIN { 39 | default: 40 | usage(); 41 | } ARGEND; 42 | 43 | if (argc != 1) 44 | usage(); 45 | 46 | n = estrtonum(argv[0], 0, UINT_MAX); 47 | for (i = 0; i < LEN(vt); i++) { 48 | if ((fd = open(vt[i], O_RDONLY)) < 0) 49 | continue; 50 | c = 0; 51 | if (ioctl(fd, KDGKBTYPE, &c) == 0) 52 | goto found; 53 | if (close(fd) < 0) 54 | eprintf("close %s:", vt[i]); 55 | } 56 | eprintf("no console found\n"); 57 | 58 | found: 59 | if (ioctl(fd, VT_ACTIVATE, n) == -1) 60 | eprintf("VT_ACTIVATE %u:", n); 61 | if (ioctl(fd, VT_WAITACTIVE, n) == -1) 62 | eprintf("VT_WAITACTIVE %u:", n); 63 | if (close(fd) < 0) 64 | eprintf("close %s:", vt[i]); 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /clear.1: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt CLEAR 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm clear 6 | .Nd clear the screen 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Sh DESCRIPTION 10 | .Nm 11 | clears the screen. 12 | -------------------------------------------------------------------------------- /clear.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include "util.h" 5 | 6 | static void 7 | usage(void) 8 | { 9 | eprintf("usage: %s\n", argv0); 10 | } 11 | 12 | int 13 | main(int argc, char *argv[]) 14 | { 15 | argv0 = argv[0], argc--, argv++; 16 | 17 | if (argc) 18 | usage(); 19 | 20 | printf("\x1b[2J\x1b[H"); 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /config.def.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | 3 | #define ENV_SUPATH "/bin" 4 | #define ENV_PATH "/bin" 5 | #define PW_CIPHER "$6$" /* SHA-512 */ 6 | #undef UTMP_PATH 7 | #define UTMP_PATH "/var/run/utmp" 8 | #undef BTMP_PATH 9 | #define BTMP_PATH "/var/log/btmp" 10 | #undef WTMP_PATH 11 | #define WTMP_PATH "/var/log/wtmp" 12 | -------------------------------------------------------------------------------- /config.mk: -------------------------------------------------------------------------------- 1 | # ubase version 2 | VERSION = 0.1 3 | 4 | # paths 5 | PREFIX = /usr/local 6 | MANPREFIX = $(PREFIX)/share/man 7 | 8 | CC = cc 9 | AR = ar 10 | RANLIB = ranlib 11 | 12 | CPPFLAGS = -D_FILE_OFFSET_BITS=64 -D_XOPEN_SOURCE=700 -D_GNU_SOURCE 13 | CFLAGS = -std=c99 -Wall -Wextra 14 | LDLIBS = -lcrypt 15 | LDFLAGS = -s 16 | -------------------------------------------------------------------------------- /ctrlaltdel.8: -------------------------------------------------------------------------------- 1 | .Dd September 7, 2015 2 | .Dt CTRLALTDEL 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm ctrlaltdel 6 | .Nd toggle Ctrl-Alt-Del behaviour 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Fl h | s 10 | .Sh DESCRIPTION 11 | .Nm 12 | toggles the function of Ctrl-Alt-Del based on the two choices given in 13 | .Pa linux/kernel/sys.c : 14 | .Bl -tag -width Ds 15 | .It hard reset 16 | reboot the computer immediately without calling 17 | .Xr sync 2 . 18 | .It soft reset 19 | send SIGINT to 20 | .Xr init 8 . 21 | .El 22 | .Sh OPTIONS 23 | .Bl -tag -width Ds 24 | .It Fl h 25 | Set to hard reset. 26 | .It Fl s 27 | Set to soft reset. 28 | .El 29 | .Sh SEE ALSO 30 | .Xr sync 2 , 31 | .Xr init 8 32 | -------------------------------------------------------------------------------- /ctrlaltdel.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include "reboot.h" 8 | #include "util.h" 9 | 10 | static void 11 | usage(void) 12 | { 13 | eprintf("usage: %s -h | -s\n", argv0); 14 | } 15 | 16 | int 17 | main(int argc, char *argv[]) 18 | { 19 | int hflag = 0, sflag = 0, cmd; 20 | 21 | ARGBEGIN { 22 | case 'h': 23 | hflag = 1; 24 | break; 25 | case 's': 26 | sflag = 1; 27 | break; 28 | default: 29 | usage(); 30 | } ARGEND; 31 | 32 | if (argc || !(hflag ^ sflag)) 33 | usage(); 34 | 35 | cmd = hflag ? LINUX_REBOOT_CMD_CAD_ON : LINUX_REBOOT_CMD_CAD_OFF; 36 | 37 | if (syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, 38 | cmd, NULL) < 0) 39 | eprintf("reboot:"); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /df.1: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt DF 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm df 6 | .Nd show file system usage 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl ahis 10 | .Sh DESCRIPTION 11 | .Nm 12 | displays the amount of disk space available on a file system. 13 | If no arguments are given, 14 | .Nm 15 | shows all the file systems using 512-byte blocks. 16 | .Sh OPTIONS 17 | .Bl -tag -width Ds 18 | .It Fl a 19 | Show all file systems including dummy ones. This is the default 20 | option. 21 | .It Fl h 22 | Not implemented. 23 | .It Fl i 24 | Not implemented. 25 | .It Fl s 26 | Not implemented. 27 | .El 28 | -------------------------------------------------------------------------------- /df.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "util.h" 10 | 11 | static long blksize = 512; 12 | static int aflag = 0; 13 | static int hflag = 0; 14 | static int kflag = 0; 15 | 16 | #define CALC_POWER(n, power, base, i) do { \ 17 | while (n > power) { \ 18 | power = power * base; \ 19 | i++; \ 20 | } \ 21 | } while(0) 22 | 23 | static void 24 | print_human( 25 | const char *fsname, 26 | unsigned long long total, 27 | unsigned long long used, 28 | unsigned long long avail, 29 | int capacity, 30 | const char *dir) 31 | { 32 | long base = 1024; 33 | unsigned long long power_total = base; 34 | unsigned long long power_used = base; 35 | unsigned long long power_avail = base; 36 | char postfixes[] = {'B', 'K', 'M', 'G', 'T', 'P', 'E'}; 37 | int i = 0, j = 0, k = 0; 38 | 39 | total = total * blksize; 40 | used = used * blksize; 41 | avail = avail * blksize; 42 | 43 | CALC_POWER(total, power_total, base, i); 44 | CALC_POWER(used, power_used, base, j); 45 | CALC_POWER(avail, power_avail, base, k); 46 | 47 | total = i ? total / (power_total / base) : total; 48 | used = j ? used / (power_used / base) : used; 49 | avail = k ? avail / (power_avail / base) : avail; 50 | printf("%-12s %9llu%c %9llu%c %9llu%c %7d%% %s\n", 51 | fsname, total, postfixes[i], used, postfixes[j], 52 | avail, postfixes[k], capacity, dir); 53 | } 54 | 55 | static int 56 | mnt_show(const char *fsname, const char *dir) 57 | { 58 | struct statvfs s; 59 | unsigned long long total, used, avail; 60 | int capacity = 0; 61 | int bs; 62 | 63 | if (statvfs(dir, &s) < 0) 64 | return -1; 65 | 66 | bs = s.f_frsize / blksize; 67 | total = s.f_blocks * bs; 68 | avail = s.f_bavail * bs; 69 | used = total - s.f_bfree * bs; 70 | 71 | if (used + avail) { 72 | capacity = (used * 100) / (used + avail); 73 | if (used * 100 != capacity * (used + avail)) 74 | capacity++; 75 | } 76 | 77 | if (hflag) 78 | print_human(fsname, total, used, avail, capacity, dir); 79 | else 80 | printf("%-12s %9llu %9llu %9llu %7d%% %s\n", 81 | fsname, total, used, avail, capacity, dir); 82 | 83 | return 0; 84 | } 85 | 86 | static void 87 | usage(void) 88 | { 89 | eprintf("usage: %s [-a]\n", argv0); 90 | } 91 | 92 | int 93 | main(int argc, char *argv[]) 94 | { 95 | struct mntent *me = NULL; 96 | FILE *fp; 97 | int ret = 0; 98 | 99 | ARGBEGIN { 100 | case 'a': 101 | aflag = 1; 102 | break; 103 | case 'h': 104 | hflag = 1; 105 | kflag = 0; 106 | break; 107 | case 'k': 108 | kflag = 1; 109 | hflag = 0; 110 | blksize = 1024; 111 | break; 112 | case 's': 113 | case 'i': 114 | eprintf("not implemented\n"); 115 | default: 116 | usage(); 117 | } ARGEND; 118 | 119 | if (hflag) 120 | printf("Filesystem Size Used " 121 | "Avail Capacity Mounted on\n"); 122 | else 123 | printf("Filesystem %ld-blocks Used " 124 | "Avail Capacity Mounted on\n", blksize); 125 | 126 | fp = setmntent("/proc/mounts", "r"); 127 | if (!fp) 128 | eprintf("setmntent %s:", "/proc/mounts"); 129 | while ((me = getmntent(fp)) != NULL) { 130 | if (aflag == 0) 131 | if (strcmp(me->mnt_type, "rootfs") == 0) 132 | continue; 133 | if (mnt_show(me->mnt_fsname, me->mnt_dir) < 0) 134 | ret = 1; 135 | } 136 | endmntent(fp); 137 | 138 | return ret; 139 | } 140 | -------------------------------------------------------------------------------- /dmesg.1: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt DMESG 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm dmesg 6 | .Nd print or control the kernel ring buffer 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl Ccr 10 | .Op Fl n Ar level 11 | .Sh DESCRIPTION 12 | .Nm 13 | examines or controls the kernel ring buffer. By default it reads all the 14 | messages from the kernel ring buffer and prints them to stdout. 15 | .Sh OPTIONS 16 | .Bl -tag -width Ds 17 | .It Fl C 18 | Clear the ring buffer. 19 | .It Fl c 20 | Clear the ring buffer after printing its contents. 21 | .It Fl n Ar level 22 | Set the console 23 | .Ar level . 24 | The log levels are defined in the file 25 | .Pa include/linux/kern_levels.h . 26 | .It Fl r 27 | Print the raw message buffer. 28 | .El 29 | -------------------------------------------------------------------------------- /dmesg.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "util.h" 10 | 11 | enum { 12 | SYSLOG_ACTION_READ_ALL = 3, 13 | SYSLOG_ACTION_CLEAR = 5, 14 | SYSLOG_ACTION_CONSOLE_LEVEL = 8, 15 | SYSLOG_ACTION_SIZE_BUFFER = 10 16 | }; 17 | 18 | static void 19 | dmesg_show(const void *buf, size_t n) 20 | { 21 | const char *p = buf; 22 | ssize_t r; 23 | 24 | r = write(1, p, n); 25 | if (r < 0) 26 | eprintf("write:"); 27 | if (r > 0 && p[r - 1] != '\n') 28 | putchar('\n'); 29 | } 30 | 31 | static void 32 | usage(void) 33 | { 34 | eprintf("usage: %s [-Ccr] [-n level]\n", argv0); 35 | } 36 | 37 | int 38 | main(int argc, char *argv[]) 39 | { 40 | int n; 41 | char *buf; 42 | int cflag = 0; 43 | long level; 44 | 45 | ARGBEGIN { 46 | case 'C': 47 | if (klogctl(SYSLOG_ACTION_CLEAR, NULL, 0) < 0) 48 | eprintf("klogctl:"); 49 | return 0; 50 | case 'c': 51 | cflag = 1; 52 | break; 53 | case 'r': 54 | break; 55 | case 'n': 56 | level = estrtol(EARGF(usage()), 10); 57 | if (klogctl(SYSLOG_ACTION_CONSOLE_LEVEL, NULL, level) < 0) 58 | eprintf("klogctl:"); 59 | return 0; 60 | default: 61 | usage(); 62 | } ARGEND; 63 | 64 | n = klogctl(SYSLOG_ACTION_SIZE_BUFFER, NULL, 0); 65 | if (n < 0) 66 | eprintf("klogctl:"); 67 | 68 | buf = emalloc(n); 69 | 70 | n = klogctl(SYSLOG_ACTION_READ_ALL, buf, n); 71 | if (n < 0) 72 | eprintf("klogctl:"); 73 | 74 | dmesg_show(buf, n); 75 | 76 | if (cflag && klogctl(SYSLOG_ACTION_CLEAR, NULL, 0) < 0) 77 | eprintf("klogctl:"); 78 | 79 | free(buf); 80 | return 0; 81 | } -------------------------------------------------------------------------------- /eject.1: -------------------------------------------------------------------------------- 1 | .Dd September 9, 2015 2 | .Dt EJECT 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm eject 6 | .Nd control device trays 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl t 10 | .Op Ar device ... 11 | .Sh DESCRIPTION 12 | .Nm 13 | opens the tray of each 14 | .Ar device . 15 | If no 16 | .Ar device 17 | is given 18 | .Nm 19 | opens the tray of 20 | .Pa /dev/sr0 . 21 | .Sh OPTIONS 22 | .Bl -tag -width Ds 23 | .It Fl t 24 | Close instead of open the tray. 25 | .El 26 | -------------------------------------------------------------------------------- /eject.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "util.h" 11 | 12 | enum { 13 | OPEN_TRAY = 0x5309, 14 | CLOSE_TRAY = 0x5319, 15 | }; 16 | 17 | static int tflag = 0; 18 | static int ret = 0; 19 | 20 | static void 21 | eject(const char *devname) 22 | { 23 | int fd, out; 24 | 25 | if ((fd = open(devname, O_RDONLY | O_NONBLOCK)) < 0) { 26 | weprintf("open %s:", devname); 27 | ret = 1; 28 | } else if (tflag && ioctl(fd, CLOSE_TRAY, &out) < 0) { 29 | weprintf("ioctl %s:", devname); 30 | ret = 1; 31 | } else if (!tflag && ioctl(fd, OPEN_TRAY, &out) < 0) { 32 | weprintf("ioctl %s:", devname); 33 | ret = 1; 34 | } 35 | 36 | if (fd >= 0 && close(fd) < 0) { 37 | weprintf("close %s:", devname); 38 | ret = 1; 39 | } 40 | } 41 | 42 | 43 | static void 44 | usage(void) 45 | { 46 | eprintf("usage: %s [-t] [device ...]\n", argv0); 47 | } 48 | 49 | int 50 | main(int argc, char *argv[]) 51 | { 52 | ARGBEGIN { 53 | case 't': 54 | tflag = 1; 55 | break; 56 | default: 57 | usage(); 58 | } ARGEND; 59 | 60 | if (!argc) { 61 | eject("/dev/sr0"); 62 | } else { 63 | for (; *argv; argc--, argv++) 64 | eject(*argv); 65 | } 66 | 67 | return ret; 68 | } 69 | -------------------------------------------------------------------------------- /fallocate.1: -------------------------------------------------------------------------------- 1 | .Dd September 12, 2015 2 | .Dt FALLOCATE 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm fallocate 6 | .Nd preallocate files 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl o Ar num 10 | .Fl l Ar num 11 | .Ar file ... 12 | .Sh DESCRIPTION 13 | .Nm 14 | if necessary creates and preallocates each 15 | .Ar file 16 | without truncation. 17 | .sp 18 | Given the filesystem supports 19 | .Xr fallocate 2 , 20 | it is a very fast method of preallocation. 21 | .Sh OPTIONS 22 | .Bl -tag -width Ds 23 | .It Fl l Ar num 24 | Preallocate 25 | .Ar num 26 | bytes. 27 | .It Fl o Ar num 28 | Offset allocation by 29 | .Ar num 30 | bytes. 31 | .El 32 | .Sh SEE ALSO 33 | .Xr fallocate 2 34 | -------------------------------------------------------------------------------- /fallocate.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "util.h" 12 | 13 | static void 14 | usage(void) 15 | { 16 | eprintf("usage: %s [-o num] -l num file ...\n", argv0); 17 | } 18 | 19 | int 20 | main(int argc, char *argv[]) 21 | { 22 | int fd, ret = 0; 23 | off_t size = 0, offset = 0; 24 | 25 | ARGBEGIN { 26 | case 'l': 27 | size = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX)); 28 | break; 29 | case 'o': 30 | offset = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX)); 31 | break; 32 | default: 33 | usage(); 34 | } ARGEND; 35 | 36 | if (!argc || !size) 37 | usage(); 38 | 39 | for (; *argv; argc--, argv++) { 40 | if ((fd = open(*argv, O_RDWR | O_CREAT, 0644)) < 0) { 41 | weprintf("open %s:", *argv); 42 | ret = 1; 43 | } else if (posix_fallocate(fd, offset, size) < 0) { 44 | weprintf("posix_fallocate %s:", *argv); 45 | ret = 1; 46 | } 47 | 48 | if (fd >= 0 && close(fd) < 0) { 49 | weprintf("close %s:", *argv); 50 | ret = 1; 51 | } 52 | } 53 | 54 | return ret; 55 | } 56 | -------------------------------------------------------------------------------- /free.1: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt FREE 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm free 6 | .Nd display amount of free and used memory in the system 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl bgkm 10 | .Sh DESCRIPTION 11 | .Nm 12 | displays the total amount of free and used physical and swap memory in the 13 | system, as well as the buffers used by the kernel. 14 | .Sh OPTIONS 15 | .Bl -tag -width Ds 16 | .It Fl b 17 | Display the amount of memory in bytes. This is the default. 18 | .It Fl g 19 | Display the amount of memory in gigabytes. 20 | .It Fl k 21 | Display the amount of memory in kilobytes. 22 | .It Fl m 23 | Display the amount of memory in megabytes. 24 | .El -------------------------------------------------------------------------------- /free.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include "util.h" 8 | 9 | static unsigned int mem_unit = 1; 10 | static unsigned int unit_shift; 11 | 12 | static unsigned long long 13 | scale(unsigned long long v) 14 | { 15 | return (v * mem_unit) >> unit_shift; 16 | } 17 | 18 | static void 19 | usage(void) 20 | { 21 | eprintf("usage: %s [-bkmg]\n", argv0); 22 | } 23 | 24 | int 25 | main(int argc, char *argv[]) 26 | { 27 | struct sysinfo info; 28 | 29 | if (sysinfo(&info) < 0) 30 | eprintf("sysinfo:"); 31 | mem_unit = info.mem_unit ? info.mem_unit : 1; 32 | 33 | ARGBEGIN { 34 | case 'b': 35 | unit_shift = 0; 36 | break; 37 | case 'k': 38 | unit_shift = 10; 39 | break; 40 | case 'm': 41 | unit_shift = 20; 42 | break; 43 | case 'g': 44 | unit_shift = 30; 45 | break; 46 | default: 47 | usage(); 48 | } ARGEND; 49 | 50 | printf(" %13s%13s%13s%13s%13s\n", 51 | "total", 52 | "used", 53 | "free", 54 | "shared", "buffers"); 55 | printf("Mem: "); 56 | printf("%13llu%13llu%13llu%13llu%13llu\n", 57 | scale(info.totalram), 58 | scale(info.totalram - info.freeram), 59 | scale(info.freeram), 60 | scale(info.sharedram), 61 | scale(info.bufferram)); 62 | printf("-/+ buffers/cache:"); 63 | printf("%13llu%13llu\n", 64 | scale(info.totalram - info.freeram - info.bufferram), 65 | scale(info.freeram + info.bufferram)); 66 | printf("Swap:"); 67 | printf("%13llu%13llu%13llu\n", 68 | scale(info.totalswap), 69 | scale(info.totalswap - info.freeswap), 70 | scale(info.freeswap)); 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /freeramdisk.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt FREERAMDISK 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm freeramdisk 6 | .Nd free memory used by the loadlin ramdisk 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Sh DESCRIPTION 10 | .Nm 11 | frees the memory that is used by the ramdisk. It uses the 12 | .Pa /dev/ram 13 | device node. -------------------------------------------------------------------------------- /freeramdisk.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "util.h" 12 | 13 | static void 14 | usage(void) 15 | { 16 | eprintf("usage: %s\n", argv0); 17 | } 18 | 19 | int 20 | main(int argc, char *argv[]) 21 | { 22 | char *dev = "/dev/ram"; 23 | int fd; 24 | 25 | ARGBEGIN { 26 | default: 27 | usage(); 28 | } ARGEND; 29 | 30 | if (argc != 0) 31 | usage(); 32 | 33 | if ((fd = open(dev, O_RDWR)) < 0) 34 | eprintf("open: %s:", dev); 35 | if (ioctl(fd, BLKFLSBUF, dev) < 0) 36 | eprintf("BLKFLSBUF %s:", dev); 37 | close(fd); 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /fsfreeze.8: -------------------------------------------------------------------------------- 1 | .Dd March 26, 2016 2 | .Dt FSFREEZE 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm fsfreeze 6 | .Nd suspend access to a filesystem 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Po Fl f | Fl u Pc 10 | .Ar mountpoint 11 | .Sh DESCRIPTION 12 | .Nm 13 | suspends and resumes access to a filesystem. 14 | .Nm 15 | is intended to be used with hardware RAID devices that support the creation 16 | of snapshots. 17 | The 18 | .Ar mountpoint 19 | argument is the pathname of the directory where the filesystem is mounted. 20 | The filesystem must be mounted to be frozen. 21 | .Sh OPTIONS 22 | .Bl -tag -width Ds 23 | .It Fl f 24 | Freeze the filesystem mounted at 25 | .Ar mountpoint . 26 | .It Fl u 27 | Unfreeze the filesystem mounted at 28 | .Ar mountpoint . 29 | .El 30 | .Sh SEE ALSO 31 | .Xr mount 8 32 | .Sh BUGS 33 | Only works for ext3/4, reiserfs, jfs and xfs. 34 | -------------------------------------------------------------------------------- /fsfreeze.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "util.h" 12 | 13 | #define FIFREEZE _IOWR('X', 119, int) /* Freeze */ 14 | #define FITHAW _IOWR('X', 120, int) /* Thaw */ 15 | 16 | static void 17 | usage(void) 18 | { 19 | eprintf("usage: %s (-f | -u) mountpoint\n", argv0); 20 | } 21 | 22 | int 23 | main(int argc, char *argv[]) 24 | { 25 | int fflag = 0; 26 | int uflag = 0; 27 | long p = 1; 28 | int fd; 29 | 30 | ARGBEGIN { 31 | case 'f': 32 | fflag = 1; 33 | break; 34 | case 'u': 35 | uflag = 1; 36 | break; 37 | default: 38 | usage(); 39 | } ARGEND; 40 | 41 | if (argc != 1) 42 | usage(); 43 | 44 | if ((fflag ^ uflag) == 0) 45 | usage(); 46 | 47 | fd = open(argv[0], O_RDONLY); 48 | if (fd < 0) 49 | eprintf("open: %s:", argv[0]); 50 | if (ioctl(fd, fflag == 1 ? FIFREEZE : FITHAW, &p) < 0) 51 | eprintf("%s %s:", fflag == 1 ? "FIFREEZE" : "FITHAW", argv[0]); 52 | close(fd); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /getty.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt GETTY 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm getty 6 | .Nd suckless linux getty 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Ar tty Op Ar term Op Ar cmd Op Ar args... 10 | .Sh DESCRIPTION 11 | .Nm 12 | opens a tty device, prompts for a login name and by default 13 | invokes the /bin/login program. You can start another program instead of 14 | /bin/login via 15 | .Ar cmd 16 | with 17 | .Ar args . 18 | The hostname is printed in the login name prompt as well. The 19 | .Ar tty 20 | should be specified using an absolute path. 21 | .Sh SEE ALSO 22 | .Xr login 1 -------------------------------------------------------------------------------- /getty.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "config.h" 16 | #include "util.h" 17 | 18 | static char *tty = "/dev/tty1"; 19 | static char *defaultterm = "linux"; 20 | 21 | static void 22 | usage(void) 23 | { 24 | eprintf("usage: %s [tty] [term] [cmd] [args...]\n", argv0); 25 | } 26 | 27 | int 28 | main(int argc, char *argv[]) 29 | { 30 | char term[128], logname[LOGIN_NAME_MAX], c; 31 | char hostname[HOST_NAME_MAX + 1]; 32 | struct utmp usr; 33 | struct sigaction sa; 34 | FILE *fp; 35 | int fd; 36 | unsigned int i = 0; 37 | ssize_t n; 38 | long pos; 39 | 40 | ARGBEGIN { 41 | default: 42 | usage(); 43 | } ARGEND; 44 | 45 | strlcpy(term, defaultterm, sizeof(term)); 46 | if (argc > 0) { 47 | tty = argv[0]; 48 | if (argc > 1) 49 | strlcpy(term, argv[1], sizeof(term)); 50 | } 51 | 52 | sa.sa_handler = SIG_IGN; 53 | sa.sa_flags = 0; 54 | sigemptyset(&sa.sa_mask); 55 | sigaction(SIGHUP, &sa, NULL); 56 | 57 | setenv("TERM", term, 1); 58 | 59 | setsid(); 60 | 61 | fd = open(tty, O_RDWR); 62 | if (fd < 0) 63 | eprintf("open %s:", tty); 64 | if (isatty(fd) == 0) 65 | eprintf("%s is not a tty\n", tty); 66 | 67 | /* steal the controlling terminal if necessary */ 68 | if (ioctl(fd, TIOCSCTTY, (void *)1) != 0) 69 | weprintf("TIOCSCTTY: could not set controlling tty\n"); 70 | vhangup(); 71 | close(fd); 72 | 73 | fd = open(tty, O_RDWR); 74 | if (fd < 0) 75 | eprintf("open %s:", tty); 76 | dup2(fd, 0); 77 | dup2(fd, 1); 78 | dup2(fd, 2); 79 | if (fchown(fd, 0, 0) < 0) 80 | weprintf("fchown %s:", tty); 81 | if (fchmod(fd, 0600) < 0) 82 | weprintf("fchmod %s:", tty); 83 | if (fd > 2) 84 | close(fd); 85 | 86 | sa.sa_handler = SIG_DFL; 87 | sa.sa_flags = 0; 88 | sigemptyset(&sa.sa_mask); 89 | sigaction(SIGHUP, &sa, NULL); 90 | 91 | /* Clear all utmp entries for this tty */ 92 | fp = fopen(UTMP_PATH, "r+"); 93 | if (fp) { 94 | do { 95 | pos = ftell(fp); 96 | if (fread(&usr, sizeof(usr), 1, fp) != 1) 97 | break; 98 | if (usr.ut_line[0] == '\0') 99 | continue; 100 | if (strcmp(usr.ut_line, tty) != 0) 101 | continue; 102 | memset(&usr, 0, sizeof(usr)); 103 | fseek(fp, pos, SEEK_SET); 104 | if (fwrite(&usr, sizeof(usr), 1, fp) != 1) 105 | break; 106 | } while (1); 107 | if (ferror(fp)) 108 | weprintf("%s: I/O error:", UTMP_PATH); 109 | fclose(fp); 110 | } 111 | 112 | if (argc > 2) 113 | return execvp(argv[2], argv + 2); 114 | 115 | if (gethostname(hostname, sizeof(hostname)) == 0) 116 | printf("%s ", hostname); 117 | printf("login: "); 118 | fflush(stdout); 119 | 120 | /* Flush pending input */ 121 | ioctl(0, TCFLSH, (void *)0); 122 | memset(logname, 0, sizeof(logname)); 123 | while (1) { 124 | n = read(0, &c, 1); 125 | if (n < 0) 126 | eprintf("read:"); 127 | if (n == 0) 128 | return 1; 129 | if (i >= sizeof(logname) - 1) 130 | eprintf("login name too long\n"); 131 | if (c == '\n' || c == '\r') 132 | break; 133 | logname[i++] = c; 134 | } 135 | if (logname[0] == '-') 136 | eprintf("login name cannot start with '-'\n"); 137 | if (logname[0] == '\0') 138 | return 1; 139 | return execlp("/bin/login", "login", "-p", logname, NULL); 140 | } 141 | -------------------------------------------------------------------------------- /halt.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt HALT 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm halt 6 | .Nd power-off or reboot the machine 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl pr 10 | .Sh DESCRIPTION 11 | .Nm 12 | can be used to power-off or reboot the machine. 13 | This is a low-level tool and should not be used directly or data-loss 14 | can happen if the filesystems are not properly unmounted first. 15 | .Sh OPTIONS 16 | .Bl -tag -width Ds 17 | .It Fl p 18 | Power-off the machine. 19 | .It Fl r 20 | Reboot the machine. 21 | .El 22 | -------------------------------------------------------------------------------- /halt.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "reboot.h" 9 | #include "util.h" 10 | 11 | static void 12 | usage(void) 13 | { 14 | eprintf("usage: %s [-pr]\n", argv0); 15 | } 16 | 17 | int 18 | main(int argc, char *argv[]) 19 | { 20 | int pflag = 0, rflag = 0; 21 | int cmd = LINUX_REBOOT_CMD_HALT; 22 | 23 | ARGBEGIN { 24 | case 'p': 25 | pflag = 1; 26 | break; 27 | case 'r': 28 | rflag = 1; 29 | break; 30 | default: 31 | usage(); 32 | } ARGEND; 33 | 34 | if (argc > 0) 35 | usage(); 36 | 37 | sync(); 38 | 39 | if (pflag && rflag) 40 | usage(); 41 | 42 | if (pflag) 43 | cmd = LINUX_REBOOT_CMD_POWER_OFF; 44 | if (rflag) 45 | cmd = LINUX_REBOOT_CMD_RESTART; 46 | 47 | if (syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, 48 | LINUX_REBOOT_MAGIC2, cmd, NULL) < 0) 49 | eprintf("reboot:"); 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /hwclock.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt HWCLOCK 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm hwclock 6 | .Nd query or set the hardware clock 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl r | Fl s | Fl w 10 | .Op Fl u 11 | .Op Ar dev 12 | .Sh DESCRIPTION 13 | .Nm 14 | is a tool for accessing the hardware clock. You can display the current time, 15 | set the hardware clock from the System Time, or set the System Time from the 16 | hardware clock. It currently only works with UTC. You can use 17 | .Ar dev 18 | to specify the RTC device node absolute path. By default 19 | it will use 20 | .Pa /dev/rtc . 21 | .Sh OPTIONS 22 | .Bl -tag -width Ds 23 | .It Fl r 24 | Read the hardware clock and print the time on stdout. 25 | .It Fl s 26 | Set the system time from the hardware clock. 27 | .It Fl u 28 | Use UTC. This is the default option. 29 | .It Fl w 30 | Set the hardware clock to the system time. 31 | .El 32 | -------------------------------------------------------------------------------- /hwclock.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "rtc.h" 15 | #include "util.h" 16 | 17 | static void 18 | readrtctm(struct tm *tm, int fd) 19 | { 20 | struct rtc_time rt; 21 | 22 | memset(&rt, 0, sizeof(rt)); 23 | if (ioctl(fd, RTC_RD_TIME, &rt) < 0) 24 | eprintf("RTC_RD_TIME:"); 25 | tm->tm_sec = rt.tm_sec; 26 | tm->tm_min = rt.tm_min; 27 | tm->tm_hour = rt.tm_hour; 28 | tm->tm_mday = rt.tm_mday; 29 | tm->tm_mon = rt.tm_mon; 30 | tm->tm_year = rt.tm_year; 31 | tm->tm_wday = rt.tm_wday; 32 | tm->tm_yday = rt.tm_yday; 33 | tm->tm_isdst = rt.tm_isdst; 34 | } 35 | 36 | static void 37 | writertctm(struct tm *tm, int fd) 38 | { 39 | struct rtc_time rt; 40 | 41 | rt.tm_sec = tm->tm_sec; 42 | rt.tm_min = tm->tm_min; 43 | rt.tm_hour = tm->tm_hour; 44 | rt.tm_mday = tm->tm_mday; 45 | rt.tm_mon = tm->tm_mon; 46 | rt.tm_year = tm->tm_year; 47 | rt.tm_wday = tm->tm_wday; 48 | rt.tm_yday = tm->tm_yday; 49 | rt.tm_isdst = tm->tm_isdst; 50 | if (ioctl(fd, RTC_SET_TIME, &rt) < 0) 51 | eprintf("RTC_SET_TIME:"); 52 | } 53 | 54 | static void 55 | show(char *dev) 56 | { 57 | struct tm tm; 58 | time_t t; 59 | int fd; 60 | 61 | fd = open(dev, O_RDONLY); 62 | if (fd < 0) 63 | eprintf("open %s:", dev); 64 | readrtctm(&tm, fd); 65 | t = mktime(&tm); 66 | printf("%s", asctime(localtime(&t))); 67 | close(fd); 68 | } 69 | 70 | static void 71 | hctosys(char *dev) 72 | { 73 | struct timeval tv; 74 | struct tm tm; 75 | int r; 76 | int fd; 77 | 78 | fd = open(dev, O_RDONLY); 79 | if (fd < 0) 80 | eprintf("open %s:", dev); 81 | readrtctm(&tm, fd); 82 | tv.tv_sec = mktime(&tm); 83 | tv.tv_usec = 0; 84 | r = settimeofday(&tv, NULL); 85 | if (r < 0) 86 | eprintf("settimeofday:"); 87 | close(fd); 88 | } 89 | 90 | static void 91 | systohc(char *dev) 92 | { 93 | struct timeval tv; 94 | struct tm *tm; 95 | time_t t; 96 | int fd; 97 | 98 | fd = open(dev, O_WRONLY); 99 | if (fd < 0) 100 | eprintf("open %s:", dev); 101 | gettimeofday(&tv, NULL); 102 | t = tv.tv_sec; 103 | tm = gmtime(&t); 104 | weprintf("warning: assuming UTC for systohc\n"); 105 | writertctm(tm, fd); 106 | close(fd); 107 | } 108 | 109 | static void 110 | usage(void) 111 | { 112 | eprintf("usage: %s [-rsw] [-u] [dev]\n", argv0); 113 | } 114 | 115 | int 116 | main(int argc, char *argv[]) 117 | { 118 | char *dev = "/dev/rtc0"; 119 | int rflag = 0; 120 | int sflag = 0; 121 | int wflag = 0; 122 | 123 | ARGBEGIN { 124 | case 'r': 125 | rflag = 1; 126 | break; 127 | case 's': 128 | sflag = 1; 129 | break; 130 | case 'w': 131 | wflag = 1; 132 | break; 133 | case 'u': 134 | break; 135 | default: 136 | usage(); 137 | } ARGEND; 138 | 139 | if (argc > 1) 140 | usage(); 141 | else if (argc == 1) 142 | dev = argv[0]; 143 | 144 | if ((rflag ^ sflag ^ wflag) == 0) 145 | eprintf("missing or incompatible function\n"); 146 | 147 | /* Only UTC support at the moment */ 148 | setenv("TZ", "UTC0", 1); 149 | tzset(); 150 | 151 | if (rflag == 1) 152 | show(dev); 153 | else if (sflag == 1) 154 | hctosys(dev); 155 | else if (wflag == 1) 156 | systohc(dev); 157 | 158 | return 0; 159 | } -------------------------------------------------------------------------------- /id.1: -------------------------------------------------------------------------------- 1 | .Dd April 24, 2015 2 | .Dt ID 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm id 6 | .Nd print real and effective user and group IDs 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl n 10 | .Op Fl g | u | G 11 | .Op Ar user | uid 12 | .Sh DESCRIPTION 13 | .Nm 14 | prints user and group information of the calling process to standard output. 15 | If a login name or uid is specified, the user and group information of that 16 | user is displayed. 17 | .Sh OPTIONS 18 | .Bl -tag -width Ds 19 | .It Fl n 20 | Print names instead of ID numbers, for -g, -u, and -G. 21 | .It Fl g 22 | Print only the effective group ID. 23 | .It Fl u 24 | Print only the effective user ID. 25 | .It Fl G 26 | Display group information as whitespace separated numbers, in no particular order. 27 | .El 28 | .Sh SEE ALSO 29 | .Xr who 1 30 | -------------------------------------------------------------------------------- /id.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "util.h" 14 | 15 | static void groupid(struct passwd *pw); 16 | static void user(struct passwd *pw); 17 | static void userid(uid_t id); 18 | static void usernam(const char *nam); 19 | 20 | static int gflag = 0; 21 | static int uflag = 0; 22 | static int Gflag = 0; 23 | static int nflag = 0; 24 | 25 | static void 26 | groupid(struct passwd *pw) 27 | { 28 | gid_t gid, groups[NGROUPS_MAX]; 29 | struct group *gr; 30 | int ngroups; 31 | int i; 32 | 33 | ngroups = NGROUPS_MAX; 34 | getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups); 35 | for (i = 0; i < ngroups; i++) { 36 | gid = groups[i]; 37 | if (nflag) { 38 | if (!(gr = getgrgid(gid))) 39 | eprintf("getgrgid:"); 40 | printf("%s", gr->gr_name); 41 | } else 42 | printf("%u", gid); 43 | 44 | if (i < ngroups - 1) 45 | putchar(' '); 46 | } 47 | putchar('\n'); 48 | } 49 | 50 | static void 51 | user(struct passwd *pw) 52 | { 53 | struct group *gr; 54 | gid_t gid, groups[NGROUPS_MAX]; 55 | int ngroups; 56 | int i; 57 | 58 | if (uflag) { 59 | if (nflag) 60 | printf("%s\n", pw->pw_name); 61 | else 62 | printf("%u\n", pw->pw_uid); 63 | return; 64 | } else if (gflag) { 65 | if (nflag) { 66 | if (!(gr = getgrgid(pw->pw_gid))) 67 | eprintf("getgrgid:"); 68 | printf("%s\n", gr->gr_name); 69 | } else 70 | printf("%u\n", pw->pw_gid); 71 | return; 72 | } 73 | 74 | printf("uid=%u(%s)", pw->pw_uid, pw->pw_name); 75 | printf(" gid=%u", pw->pw_gid); 76 | if (!(gr = getgrgid(pw->pw_gid))) 77 | eprintf("getgrgid:"); 78 | printf("(%s)", gr->gr_name); 79 | 80 | ngroups = NGROUPS_MAX; 81 | getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups); 82 | for (i = 0; i < ngroups; i++) { 83 | gid = groups[i]; 84 | printf("%s%u", !i ? " groups=" : ",", gid); 85 | if (!(gr = getgrgid(gid))) 86 | eprintf("getgrgid:"); 87 | printf("(%s)", gr->gr_name); 88 | } 89 | putchar('\n'); 90 | } 91 | 92 | static void 93 | usernam(const char *nam) 94 | { 95 | struct passwd *pw; 96 | 97 | errno = 0; 98 | pw = getpwnam(nam); 99 | if (!pw) { 100 | if (errno) 101 | eprintf("getpwnam %s:", nam); 102 | else 103 | eprintf("getpwnam %s: no such user\n", nam); 104 | } 105 | if (Gflag) 106 | groupid(pw); 107 | else 108 | user(pw); 109 | } 110 | 111 | static void 112 | userid(uid_t id) 113 | { 114 | struct passwd *pw; 115 | 116 | errno = 0; 117 | pw = getpwuid(id); 118 | if (!pw) { 119 | if (errno) 120 | eprintf("getpwuid %d:", id); 121 | else 122 | eprintf("getpwuid %d: no such user\n", id); 123 | } 124 | if (Gflag) 125 | groupid(pw); 126 | else 127 | user(pw); 128 | } 129 | 130 | static void 131 | usage(void) 132 | { 133 | eprintf("usage: %s [-n] [-g | -u | -G] [user | uid]\n", argv0); 134 | } 135 | 136 | int 137 | main(int argc, char *argv[]) 138 | { 139 | ARGBEGIN { 140 | case 'g': 141 | gflag = 1; 142 | break; 143 | case 'u': 144 | uflag = 1; 145 | break; 146 | case 'G': 147 | Gflag = 1; 148 | break; 149 | case 'n': 150 | nflag = 1; 151 | break; 152 | default: 153 | usage(); 154 | } ARGEND; 155 | 156 | /* ensure that only one of -g, -u, or -G was specified */ 157 | if (gflag + uflag + Gflag > 1) 158 | usage(); 159 | 160 | switch (argc) { 161 | case 0: 162 | userid(getuid()); 163 | break; 164 | case 1: 165 | /* user names can't begin [0-9] */ 166 | if (isdigit(argv[0][0])) 167 | userid(estrtol(argv[0], 0)); 168 | else 169 | usernam(argv[0]); 170 | break; 171 | default: 172 | usage(); 173 | } 174 | 175 | return 0; 176 | } 177 | -------------------------------------------------------------------------------- /insmod.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt INSMOD 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm insmod 6 | .Nd insert a module into the Linux kernel 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Ar filename 10 | .Op Ar args... 11 | .Sh DESCRIPTION 12 | .Nm 13 | inserts the module specified by 14 | .Ar filename 15 | into the kernel. It does not handle module dependencies. 16 | .Sh SEE ALSO 17 | .Xr lsmod 8 , 18 | .Xr rmmod 8 -------------------------------------------------------------------------------- /insmod.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "util.h" 12 | 13 | static void 14 | usage(void) 15 | { 16 | eprintf("usage: %s filename [args...]\n", argv0); 17 | } 18 | 19 | int 20 | main(int argc, char *argv[]) 21 | { 22 | char *buf = NULL, *opts = NULL; 23 | size_t blen, plen = 0; 24 | int i, fd; 25 | ssize_t n; 26 | struct stat sb; 27 | 28 | ARGBEGIN { 29 | default: 30 | usage(); 31 | } ARGEND; 32 | 33 | if (argc < 1) 34 | usage(); 35 | 36 | fd = open(argv[0], O_RDONLY); 37 | if (fd < 0) 38 | eprintf("open %s:", argv[0]); 39 | if (fstat(fd, &sb) < 0) 40 | eprintf("stat %s:", argv[0]); 41 | blen = sb.st_size; 42 | buf = emalloc(blen); 43 | 44 | n = read(fd, buf, blen); 45 | if (n < 0 || (size_t)n != blen) 46 | eprintf("read:"); 47 | 48 | argc--; 49 | argv++; 50 | 51 | for (i = 0; i < argc; i++) 52 | plen += strlen(argv[i]); 53 | if (plen > 0) { 54 | plen += argc; 55 | opts = ecalloc(1, plen); 56 | for (i = 0; i < argc; i++) { 57 | strcat(opts, argv[i]); 58 | if (i + 1 < argc) 59 | strcat(opts, " "); 60 | } 61 | } 62 | 63 | if (syscall(__NR_init_module, buf, blen, !opts ? "" : opts) < 0) 64 | eprintf("init_module:"); 65 | 66 | free(opts); 67 | free(buf); 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /killall5.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt KILLALL5 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm killall5 6 | .Nd send a signal to all processes 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl o Ar pid1,pid2,...,pidN 10 | .Op Fl s Ar signal 11 | .Sh DESCRIPTION 12 | .Nm 13 | is an implementation of the SystemV 14 | .Xr killall 8 15 | command. It sends a signal to all processes except kernel threads and the 16 | processes in its own session. It is primarily used by the system's init 17 | scripts. 18 | .Sh OPTIONS 19 | .Bl -tag -width Ds 20 | .It Fl o 21 | Tell 22 | .Nm 23 | to omit processes with that process id. 24 | .It Fl s Ar signal 25 | Send 26 | .Ar signal 27 | instead of the default SIGTERM. 28 | .El 29 | .Sh SEE ALSO 30 | .Xr halt 8 , 31 | .Xr reboot 8 32 | -------------------------------------------------------------------------------- /killall5.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "proc.h" 11 | #include "queue.h" 12 | #include "util.h" 13 | 14 | struct { 15 | const char *name; 16 | int sig; 17 | } sigs[] = { 18 | #define SIG(n) { #n, SIG##n } 19 | SIG(ABRT), SIG(ALRM), SIG(BUS), SIG(CHLD), SIG(CONT), SIG(FPE), SIG(HUP), 20 | SIG(ILL), SIG(INT), SIG(KILL), SIG(PIPE), SIG(QUIT), SIG(SEGV), SIG(STOP), 21 | SIG(TERM), SIG(TSTP), SIG(TTIN), SIG(TTOU), SIG(USR1), SIG(USR2), SIG(URG), 22 | #undef SIG 23 | }; 24 | 25 | struct pidentry { 26 | pid_t pid; 27 | SLIST_ENTRY(pidentry) entry; 28 | }; 29 | 30 | static SLIST_HEAD(, pidentry) omitpid_head; 31 | 32 | static void 33 | usage(void) 34 | { 35 | eprintf("usage: %s [-o pid1,pid2,..,pidN] [-s signal]\n", argv0); 36 | } 37 | 38 | int 39 | main(int argc, char *argv[]) 40 | { 41 | struct pidentry *pe; 42 | struct dirent *entry; 43 | DIR *dp; 44 | char *p, *arg = NULL; 45 | char *end, *v; 46 | int oflag = 0; 47 | int sig = SIGTERM; 48 | pid_t pid; 49 | size_t i; 50 | 51 | ARGBEGIN { 52 | case 's': 53 | v = EARGF(usage()); 54 | sig = strtol(v, &end, 0); 55 | if (*end == '\0') 56 | break; 57 | for (i = 0; i < LEN(sigs); i++) { 58 | if (strcasecmp(v, sigs[i].name) == 0) { 59 | sig = sigs[i].sig; 60 | break; 61 | } 62 | } 63 | if (i == LEN(sigs)) 64 | eprintf("%s: unknown signal\n", v); 65 | break; 66 | case 'o': 67 | oflag = 1; 68 | arg = EARGF(usage()); 69 | break; 70 | default: 71 | usage(); 72 | } ARGEND; 73 | 74 | SLIST_INIT(&omitpid_head); 75 | 76 | if (oflag) { 77 | for (p = strtok(arg, ","); p; p = strtok(NULL, ",")) { 78 | pe = emalloc(sizeof(*pe)); 79 | pe->pid = estrtol(p, 10); 80 | SLIST_INSERT_HEAD(&omitpid_head, pe, entry); 81 | } 82 | } 83 | 84 | if (sig != SIGSTOP && sig != SIGCONT) 85 | kill(-1, SIGSTOP); 86 | 87 | if (!(dp = opendir("/proc"))) 88 | eprintf("opendir /proc:"); 89 | while ((entry = readdir(dp))) { 90 | if (pidfile(entry->d_name) == 0) 91 | continue; 92 | pid = estrtol(entry->d_name, 10); 93 | if (pid == 1 || pid == getpid() || 94 | getsid(pid) == getsid(0) || getsid(pid) == 0) 95 | continue; 96 | if (oflag == 1) { 97 | SLIST_FOREACH(pe, &omitpid_head, entry) 98 | if (pe->pid == pid) 99 | break; 100 | if (pe) 101 | continue; 102 | } 103 | kill(pid, sig); 104 | } 105 | closedir(dp); 106 | 107 | if (sig != SIGSTOP && sig != SIGCONT) 108 | kill(-1, SIGCONT); 109 | 110 | return 0; 111 | } 112 | -------------------------------------------------------------------------------- /last.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "config.h" 14 | #include "util.h" 15 | 16 | static void 17 | usage(void) 18 | { 19 | eprintf("usage: %s [user]\n", argv0); 20 | } 21 | 22 | int 23 | main(int argc, char **argv) 24 | { 25 | FILE *fp; 26 | struct utmp ut; 27 | char *user, *file, *prog; 28 | time_t t; 29 | 30 | ARGBEGIN { 31 | default: 32 | usage(); 33 | } ARGEND; 34 | 35 | switch (argc) { 36 | case 0: 37 | user = NULL; 38 | break; 39 | case 1: 40 | user = argv[0]; 41 | break; 42 | default: 43 | usage(); 44 | } 45 | 46 | prog = basename(argv0); 47 | file = (!strcmp(prog, "last")) ? WTMP_PATH : BTMP_PATH; 48 | if ((fp = fopen(file, "r")) == NULL) 49 | eprintf("fopen %s:", file); 50 | 51 | while (fread(&ut, sizeof(ut), 1, fp) == 1) { 52 | if (ut.ut_type != USER_PROCESS || 53 | (user && strcmp(user, ut.ut_name))) { 54 | continue; 55 | } 56 | 57 | t = ut.ut_time; 58 | printf("%-8.8s %-8.8s %-16.16s %s", 59 | ut.ut_user, ut.ut_line, ut.ut_host, ctime(&t)); 60 | } 61 | if (fclose(fp)) 62 | eprintf("fclose %s:", file); 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /lastlog.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt LASTLOG 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm lastlog 6 | .Nd show last login of users 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Ar user... 10 | .Sh DESCRIPTION 11 | .Nm 12 | shows the time, tty and host (if it was a remote connection) of the last 13 | login of the users. If one or more 14 | .Ar user 15 | names are passed as a parameter then information about the last login of these 16 | users are shown, otherwise the users in 17 | .Pa /etc/passwd 18 | will be used and shown in order of appearance. 19 | -------------------------------------------------------------------------------- /lastlog.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "text.h" 12 | #include "util.h" 13 | 14 | #define PASSWD "/etc/passwd" 15 | 16 | static FILE *last; 17 | 18 | static void 19 | lastlog(char *user) 20 | { 21 | struct passwd *pwd; 22 | struct lastlog ll; 23 | time_t lltime; 24 | 25 | errno = 0; 26 | if ((pwd = getpwnam(user)) == NULL) { 27 | if (errno) 28 | weprintf("getpwnam %s:", user); 29 | else 30 | weprintf("unknown user: %s\n", user); 31 | return; 32 | } 33 | 34 | fseek(last, pwd->pw_uid * sizeof(struct lastlog), 0); 35 | fread(&ll, sizeof(struct lastlog), 1, last); 36 | 37 | if (ferror(last)) 38 | eprintf("%s: read error:", _PATH_LASTLOG); 39 | 40 | /* on glibc `ll_time' can be an int32_t with compat32 41 | * avoid compiler warning when calling ctime() */ 42 | lltime = ll.ll_time; 43 | printf("%-8.8s %-8.8s %-16.16s %s", 44 | user, ll.ll_line, ll.ll_host, ctime(&lltime)); 45 | } 46 | 47 | int 48 | main(int argc, char **argv) 49 | { 50 | FILE *fp; 51 | char *line = NULL, *p; 52 | size_t sz = 0; 53 | 54 | if ((last = fopen(_PATH_LASTLOG, "r")) == NULL) 55 | eprintf("fopen %s:", _PATH_LASTLOG); 56 | 57 | if (argc > 1) { 58 | while (*++argv) 59 | lastlog(*argv); 60 | } else { 61 | if ((fp = fopen(PASSWD, "r")) == NULL) 62 | eprintf("fopen %s:", PASSWD); 63 | while (agetline(&line, &sz, fp) != -1) { 64 | if ((p = strchr(line, ':')) == NULL) 65 | eprintf("invalid passwd entry\n"); 66 | *p = '\0'; 67 | lastlog(line); 68 | } 69 | if (fclose(fp)) 70 | eprintf("fclose %s:", PASSWD); 71 | free(line); 72 | } 73 | 74 | if (fclose(last)) 75 | eprintf("fclose %s:", _PATH_LASTLOG); 76 | 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /libutil/agetcwd.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include "../util.h" 5 | 6 | char * 7 | agetcwd(void) 8 | { 9 | char *buf; 10 | long size; 11 | 12 | apathmax(&buf, &size); 13 | if (!getcwd(buf, size)) 14 | eprintf("getcwd:"); 15 | 16 | return buf; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /libutil/agetline.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | 6 | #include "../text.h" 7 | #include "../util.h" 8 | 9 | ssize_t 10 | agetline(char **p, size_t *size, FILE *fp) 11 | { 12 | return getline(p, size, fp); 13 | } 14 | -------------------------------------------------------------------------------- /libutil/apathmax.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../util.h" 8 | 9 | void 10 | apathmax(char **p, long *size) 11 | { 12 | errno = 0; 13 | 14 | if ((*size = pathconf("/", _PC_PATH_MAX)) == -1) { 15 | if (errno == 0) { 16 | *size = BUFSIZ; 17 | } else { 18 | eprintf("pathconf:"); 19 | } 20 | } 21 | *p = emalloc(*size); 22 | } 23 | -------------------------------------------------------------------------------- /libutil/concat.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include "../text.h" 5 | #include "../util.h" 6 | 7 | void 8 | concat(FILE *fp1, const char *s1, FILE *fp2, const char *s2) 9 | { 10 | char buf[BUFSIZ]; 11 | size_t n; 12 | 13 | while ((n = fread(buf, 1, sizeof(buf), fp1)) > 0) { 14 | if (fwrite(buf, 1, n, fp2) != n) 15 | eprintf("%s: write error:", s2); 16 | if (feof(fp1)) 17 | break; 18 | } 19 | if (ferror(fp1)) 20 | eprintf("%s: read error:", s1); 21 | } 22 | -------------------------------------------------------------------------------- /libutil/ealloc.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | 5 | #include "../util.h" 6 | 7 | void * 8 | ecalloc(size_t nmemb, size_t size) 9 | { 10 | void *p; 11 | 12 | p = calloc(nmemb, size); 13 | if (!p) 14 | eprintf("calloc: out of memory\n"); 15 | return p; 16 | } 17 | 18 | void * 19 | emalloc(size_t size) 20 | { 21 | void *p; 22 | 23 | p = malloc(size); 24 | if (!p) 25 | eprintf("malloc: out of memory\n"); 26 | return p; 27 | } 28 | 29 | void * 30 | erealloc(void *p, size_t size) 31 | { 32 | p = realloc(p, size); 33 | if (!p) 34 | eprintf("realloc: out of memory\n"); 35 | return p; 36 | } 37 | 38 | char * 39 | estrdup(const char *s) 40 | { 41 | char *p; 42 | 43 | p = strdup(s); 44 | if (!p) 45 | eprintf("strdup: out of memory\n"); 46 | return p; 47 | } 48 | -------------------------------------------------------------------------------- /libutil/eprintf.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../util.h" 8 | 9 | char *argv0; 10 | 11 | static void venprintf(int, const char *, va_list); 12 | 13 | void 14 | eprintf(const char *fmt, ...) 15 | { 16 | va_list ap; 17 | 18 | va_start(ap, fmt); 19 | venprintf(1, fmt, ap); 20 | va_end(ap); 21 | } 22 | 23 | void 24 | enprintf(int status, const char *fmt, ...) 25 | { 26 | va_list ap; 27 | 28 | va_start(ap, fmt); 29 | venprintf(status, fmt, ap); 30 | va_end(ap); 31 | } 32 | 33 | void 34 | venprintf(int status, const char *fmt, va_list ap) 35 | { 36 | if (strncmp(fmt, "usage", strlen("usage"))) 37 | fprintf(stderr, "%s: ", argv0); 38 | 39 | vfprintf(stderr, fmt, ap); 40 | 41 | if (fmt[0] && fmt[strlen(fmt)-1] == ':') { 42 | fputc(' ', stderr); 43 | perror(NULL); 44 | } 45 | 46 | exit(status); 47 | } 48 | 49 | void 50 | weprintf(const char *fmt, ...) 51 | { 52 | va_list ap; 53 | 54 | if (strncmp(fmt, "usage", strlen("usage"))) 55 | fprintf(stderr, "%s: ", argv0); 56 | 57 | va_start(ap, fmt); 58 | vfprintf(stderr, fmt, ap); 59 | va_end(ap); 60 | 61 | if (fmt[0] && fmt[strlen(fmt)-1] == ':') { 62 | fputc(' ', stderr); 63 | perror(NULL); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /libutil/estrtol.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | 6 | #include "../util.h" 7 | 8 | long 9 | estrtol(const char *s, int base) 10 | { 11 | char *end; 12 | long n; 13 | 14 | errno = 0; 15 | n = strtol(s, &end, base); 16 | if (*end != '\0') { 17 | if (base == 0) 18 | eprintf("%s: not an integer\n", s); 19 | else 20 | eprintf("%s: not a base %d integer\n", s, base); 21 | } 22 | if (errno != 0) 23 | eprintf("%s:", s); 24 | 25 | return n; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /libutil/estrtoul.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | 6 | #include "../util.h" 7 | 8 | unsigned long 9 | estrtoul(const char *s, int base) 10 | { 11 | char *end; 12 | unsigned long n; 13 | 14 | errno = 0; 15 | n = strtoul(s, &end, base); 16 | if (*end != '\0') { 17 | if (base == 0) 18 | eprintf("%s: not an integer\n", s); 19 | else 20 | eprintf("%s: not a base %d integer\n", s, base); 21 | } 22 | if (errno != 0) 23 | eprintf("%s:", s); 24 | 25 | return n; 26 | } 27 | -------------------------------------------------------------------------------- /libutil/explicit_bzero.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include "../util.h" 5 | 6 | static void *(*volatile explicit_memset)(void *, int, size_t) = memset; 7 | 8 | void 9 | explicit_bzero(void *b, size_t len) 10 | { 11 | (*explicit_memset)(b, 0, len); 12 | } 13 | -------------------------------------------------------------------------------- /libutil/passwd.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "../passwd.h" 14 | #include "../text.h" 15 | #include "../util.h" 16 | 17 | /* Returns -1 on error, 0 for incorrect password 18 | * and 1 if all went OK */ 19 | int 20 | pw_check(const struct passwd *pw, const char *pass) 21 | { 22 | char *cryptpass, *p; 23 | struct spwd *spw; 24 | 25 | p = pw->pw_passwd; 26 | if (p[0] == 'x' && p[1] == '\0') { 27 | errno = 0; 28 | spw = getspnam(pw->pw_name); 29 | if (!spw) { 30 | if (errno) 31 | weprintf("getspnam: %s:", pw->pw_name); 32 | else 33 | weprintf("who are you?\n"); 34 | return -1; 35 | } 36 | p = spw->sp_pwdp; 37 | } 38 | if (p[0] == '!' || p[0] == '*') { 39 | weprintf("denied\n"); 40 | return -1; 41 | } 42 | if (p[0] == '\0') { 43 | if (pass[0] == '\0') 44 | return 1; 45 | weprintf("incorrect password\n"); 46 | return 0; 47 | } 48 | 49 | cryptpass = crypt(pass, p); 50 | if (!cryptpass) { 51 | weprintf("crypt:"); 52 | return -1; 53 | } 54 | if (strcmp(cryptpass, p) != 0) { 55 | weprintf("incorrect password\n"); 56 | return 0; 57 | } 58 | return 1; 59 | } 60 | 61 | int 62 | pw_init(void) 63 | { 64 | struct rlimit rlim; 65 | 66 | rlim.rlim_cur = 0; 67 | rlim.rlim_max = 0; 68 | if (setrlimit(RLIMIT_CORE, &rlim) < 0) 69 | eprintf("setrlimit:"); 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /libutil/proc.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "../proc.h" 13 | #include "../util.h" 14 | 15 | int 16 | parsecmdline(pid_t pid, char *buf, size_t siz) 17 | { 18 | int fd; 19 | char path[PATH_MAX]; 20 | ssize_t n, i; 21 | 22 | snprintf(path, sizeof(path), "/proc/%ld/cmdline", (long)pid); 23 | fd = open(path, O_RDONLY); 24 | if (fd < 0) 25 | return -1; 26 | n = read(fd, buf, siz > 0 ? siz - 1 : 0); 27 | if (n < 0) { 28 | weprintf("read %s:", path); 29 | close(fd); 30 | return -1; 31 | } 32 | if (!n) { 33 | close(fd); 34 | return -1; 35 | } 36 | buf[n] = '\0'; 37 | for (i = 0; i < n; i++) 38 | if (buf[i] == '\0') 39 | buf[i] = ' '; 40 | close(fd); 41 | return 0; 42 | } 43 | 44 | int 45 | parsestat(pid_t pid, struct procstat *ps) 46 | { 47 | char path[PATH_MAX]; 48 | FILE *fp; 49 | size_t len; 50 | 51 | snprintf(path, sizeof(path), "/proc/%d/stat", pid); 52 | if (!(fp = fopen(path, "r"))) 53 | return -1; 54 | fscanf(fp, "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu", 55 | &ps->pid, ps->comm, 56 | &ps->state, &ps->ppid, &ps->pgrp, 57 | &ps->sid, &ps->tty_nr, &ps->tpgid, &ps->flags, 58 | &ps->minflt, &ps->cminflt, &ps->majflt, &ps->cmajflt, 59 | &ps->utime, &ps->stime); 60 | fscanf(fp, "%ld %ld %ld %ld %ld %ld %llu %lu %ld %ld", 61 | &ps->cutime, &ps->cstime, &ps->priority, &ps->nice, 62 | &ps->num_threads, &ps->itrealvalue, &ps->starttime, 63 | &ps->vsize, &ps->rss, &ps->rsslim); 64 | /* Filter out '(' and ')' from comm */ 65 | if ((len = strlen(ps->comm)) > 0) 66 | len--; 67 | ps->comm[len] = '\0'; 68 | memmove(ps->comm, ps->comm + 1, len); 69 | fclose(fp); 70 | return 0; 71 | } 72 | 73 | int 74 | parsestatus(pid_t pid, struct procstatus *pstatus) 75 | { 76 | char path[PATH_MAX]; 77 | char buf[BUFSIZ], *off; 78 | int fd; 79 | ssize_t n; 80 | 81 | snprintf(path, sizeof(path), "/proc/%d/status", pid); 82 | fd = open(path, O_RDONLY); 83 | if (fd < 0) 84 | return -1; 85 | n = read(fd, buf, sizeof(buf) - 1); 86 | if (n < 0) 87 | eprintf("%s: read error:", path); 88 | if (!n) { 89 | close(fd); 90 | return -1; 91 | } 92 | buf[n] = '\0'; 93 | close(fd); 94 | off = strstr(buf, "Uid:"); 95 | if (!off) 96 | return -1; 97 | sscanf(off, "Uid: %u %u", &pstatus->uid, &pstatus->euid); 98 | off = strstr(buf, "Gid:"); 99 | if (!off) 100 | return -1; 101 | sscanf(off, "Gid: %u %u", &pstatus->gid, &pstatus->egid); 102 | return 0; 103 | } 104 | 105 | int 106 | pidfile(const char *file) 107 | { 108 | char *end; 109 | 110 | errno = 0; 111 | strtol(file, &end, 10); 112 | if (*end != '\0') 113 | return 0; 114 | if (errno != 0) 115 | return 0; 116 | return 1; 117 | } 118 | -------------------------------------------------------------------------------- /libutil/putword.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include "../util.h" 5 | 6 | void 7 | putword(const char *s) 8 | { 9 | static int first = 1; 10 | 11 | if (!first) 12 | putchar(' '); 13 | 14 | fputs(s, stdout); 15 | first = 0; 16 | } 17 | -------------------------------------------------------------------------------- /libutil/recurse.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "../util.h" 12 | 13 | void 14 | recurse(const char *path, void (*fn)(const char *)) 15 | { 16 | char buf[PATH_MAX]; 17 | struct dirent *d; 18 | struct stat st; 19 | DIR *dp; 20 | 21 | if (lstat(path, &st) == -1 || S_ISDIR(st.st_mode) == 0) 22 | return; 23 | 24 | if (!(dp = opendir(path))) 25 | eprintf("opendir %s:", path); 26 | 27 | while ((d = readdir(dp))) { 28 | if (strcmp(d->d_name, ".") == 0 || 29 | strcmp(d->d_name, "..") == 0) 30 | continue; 31 | if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) 32 | eprintf("path too long\n"); 33 | if (buf[strlen(buf) - 1] != '/') 34 | if (strlcat(buf, "/", sizeof(buf)) >= sizeof(buf)) 35 | eprintf("path too long\n"); 36 | if (strlcat(buf, d->d_name, sizeof(buf)) >= sizeof(buf)) 37 | eprintf("path too long\n"); 38 | fn(buf); 39 | } 40 | 41 | closedir(dp); 42 | } 43 | -------------------------------------------------------------------------------- /libutil/strlcat.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1998 Todd C. Miller 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include "../util.h" 21 | 22 | /* 23 | * Appends src to string dst of size siz (unlike strncat, siz is the 24 | * full size of dst, not space left). At most siz-1 characters 25 | * will be copied. Always NUL terminates (unless siz <= strlen(dst)). 26 | * Returns strlen(src) + MIN(siz, strlen(initial dst)). 27 | * If retval >= siz, truncation occurred. 28 | */ 29 | size_t 30 | strlcat(char *dst, const char *src, size_t siz) 31 | { 32 | char *d = dst; 33 | const char *s = src; 34 | size_t n = siz; 35 | size_t dlen; 36 | /* Find the end of dst and adjust bytes left but don't go past end */ 37 | while (n-- != 0 && *d != '\0') 38 | d++; 39 | dlen = d - dst; 40 | n = siz - dlen; 41 | if (n == 0) 42 | return(dlen + strlen(s)); 43 | while (*s != '\0') { 44 | if (n != 1) { 45 | *d++ = *s; 46 | n--; 47 | } 48 | s++; 49 | } 50 | *d = '\0'; 51 | return(dlen + (s - src)); /* count does not include NUL */ 52 | } 53 | 54 | size_t 55 | estrlcat(char *dst, const char *src, size_t siz) 56 | { 57 | size_t ret; 58 | 59 | if ((ret = strlcat(dst, src, siz)) >= siz) 60 | eprintf("strlcat: input string too long\n"); 61 | 62 | return ret; 63 | } 64 | -------------------------------------------------------------------------------- /libutil/strlcpy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1998 Todd C. Miller 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include "../util.h" 21 | 22 | /* 23 | * Copy src to string dst of size siz. At most siz-1 characters 24 | * will be copied. Always NUL terminates (unless siz == 0). 25 | * Returns strlen(src); if retval >= siz, truncation occurred. 26 | */ 27 | size_t 28 | strlcpy(char *dst, const char *src, size_t siz) 29 | { 30 | char *d = dst; 31 | const char *s = src; 32 | size_t n = siz; 33 | /* Copy as many bytes as will fit */ 34 | if (n != 0) { 35 | while (--n != 0) { 36 | if ((*d++ = *s++) == '\0') 37 | break; 38 | } 39 | } 40 | /* Not enough room in dst, add NUL and traverse rest of src */ 41 | if (n == 0) { 42 | if (siz != 0) 43 | *d = '\0'; /* NUL-terminate dst */ 44 | while (*s++) 45 | ; 46 | } 47 | return(s - src - 1); /* count does not include NUL */ 48 | } 49 | 50 | size_t 51 | estrlcpy(char *dst, const char *src, size_t siz) 52 | { 53 | size_t ret; 54 | 55 | if ((ret = strlcpy(dst, src, siz)) >= siz) 56 | eprintf("strlcpy: input string too long\n"); 57 | 58 | return ret; 59 | } 60 | -------------------------------------------------------------------------------- /libutil/strtonum.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 2004 Ted Unangst and Todd Miller 5 | * All rights reserved. 6 | * 7 | * Permission to use, copy, modify, and distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "../util.h" 25 | 26 | #define INVALID 1 27 | #define TOOSMALL 2 28 | #define TOOLARGE 3 29 | 30 | long long 31 | strtonum(const char *numstr, long long minval, long long maxval, 32 | const char **errstrp) 33 | { 34 | long long ll = 0; 35 | int error = 0; 36 | char *ep; 37 | struct errval { 38 | const char *errstr; 39 | int err; 40 | } ev[4] = { 41 | { NULL, 0 }, 42 | { "invalid", EINVAL }, 43 | { "too small", ERANGE }, 44 | { "too large", ERANGE }, 45 | }; 46 | 47 | ev[0].err = errno; 48 | errno = 0; 49 | if (minval > maxval) { 50 | error = INVALID; 51 | } else { 52 | ll = strtoll(numstr, &ep, 10); 53 | if (numstr == ep || *ep != '\0') 54 | error = INVALID; 55 | else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) 56 | error = TOOSMALL; 57 | else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) 58 | error = TOOLARGE; 59 | } 60 | if (errstrp != NULL) 61 | *errstrp = ev[error].errstr; 62 | errno = ev[error].err; 63 | if (error) 64 | ll = 0; 65 | 66 | return (ll); 67 | } 68 | 69 | long long 70 | enstrtonum(int status, const char *numstr, long long minval, long long maxval) 71 | { 72 | const char *errstr; 73 | long long ll; 74 | 75 | ll = strtonum(numstr, minval, maxval, &errstr); 76 | if (errstr) 77 | enprintf(status, "strtonum %s: %s\n", numstr, errstr); 78 | return ll; 79 | } 80 | 81 | long long 82 | estrtonum(const char *numstr, long long minval, long long maxval) 83 | { 84 | return enstrtonum(1, numstr, minval, maxval); 85 | } 86 | -------------------------------------------------------------------------------- /libutil/tty.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #ifndef major 5 | #include 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "../util.h" 17 | 18 | void 19 | devtotty(int dev, int *tty_maj, int *tty_min) 20 | { 21 | *tty_maj = (dev >> 8) & 0xfff; 22 | *tty_min = (dev & 0xff) | ((dev >> 12) & 0xfff00); 23 | } 24 | 25 | int 26 | ttytostr(int tty_maj, int tty_min, char *str, size_t n) 27 | { 28 | struct stat sb; 29 | struct dirent *dp; 30 | DIR *dirp; 31 | char path[PATH_MAX]; 32 | int fd; 33 | int r = 0; 34 | 35 | switch (tty_maj) { 36 | case 136: 37 | snprintf(str, n, "pts/%d", tty_min); 38 | return 0; 39 | case 4: 40 | snprintf(str, n, "tty%d", tty_min); 41 | return 0; 42 | default: 43 | str[0] = '?'; 44 | str[1] = '\0'; 45 | break; 46 | } 47 | 48 | dirp = opendir("/dev"); 49 | if (!dirp) { 50 | weprintf("opendir /dev:"); 51 | return -1; 52 | } 53 | 54 | while ((dp = readdir(dirp))) { 55 | if (!strcmp(dp->d_name, ".") || 56 | !strcmp(dp->d_name, "..")) 57 | continue; 58 | 59 | if (strlcpy(path, "/dev/", sizeof(path)) >= sizeof(path)) { 60 | weprintf("path too long\n"); 61 | r = -1; 62 | goto err0; 63 | } 64 | if (strlcat(path, dp->d_name, sizeof(path)) >= sizeof(path)) { 65 | weprintf("path too long\n"); 66 | r = -1; 67 | goto err0; 68 | } 69 | 70 | if (stat(path, &sb) < 0) { 71 | weprintf("stat %s:", path); 72 | r = -1; 73 | goto err0; 74 | } 75 | 76 | if ((int)major(sb.st_rdev) == tty_maj && 77 | (int)minor(sb.st_rdev) == tty_min) { 78 | fd = open(path, O_RDONLY | O_NONBLOCK); 79 | if (fd < 0) 80 | continue; 81 | if (isatty(fd)) { 82 | strlcpy(str, dp->d_name, n); 83 | close(fd); 84 | break; 85 | } else { 86 | close(fd); 87 | r = -1; 88 | goto err0; 89 | } 90 | } 91 | } 92 | 93 | err0: 94 | if (closedir(dirp) < 0) { 95 | weprintf("closedir /dev:"); 96 | r = -1; 97 | } 98 | 99 | return r; 100 | } 101 | -------------------------------------------------------------------------------- /login.1: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt LOGIN 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm login 6 | .Nd log into the system 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl p 10 | .Ar username 11 | .Sh DESCRIPTION 12 | .Nm 13 | logs the 14 | .Ar username 15 | into the system. It sets 16 | .Ev HOME , 17 | .Ev SHELL , 18 | .Ev USER , 19 | .Ev LOGNAME 20 | and the 21 | .Ev PATH environment variables and invokes the login shell as specified in 22 | .Pa /etc/passwd . 23 | .Sh OPTIONS 24 | .Bl -tag -width Ds 25 | .It Fl p 26 | Preserve the environment. 27 | .El 28 | -------------------------------------------------------------------------------- /login.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "config.h" 16 | #include "passwd.h" 17 | #include "util.h" 18 | 19 | /* Write utmp entry */ 20 | static void 21 | writeutmp(const char *user, const char *tty) 22 | { 23 | struct utmp usr; 24 | FILE *fp; 25 | 26 | memset(&usr, 0, sizeof(usr)); 27 | 28 | usr.ut_type = USER_PROCESS; 29 | usr.ut_pid = getpid(); 30 | strlcpy(usr.ut_user, user, sizeof(usr.ut_user)); 31 | strlcpy(usr.ut_line, tty, sizeof(usr.ut_line)); 32 | usr.ut_tv.tv_sec = time(NULL); 33 | 34 | fp = fopen(UTMP_PATH, "a"); 35 | if (fp) { 36 | if (fwrite(&usr, sizeof(usr), 1, fp) != 1) 37 | if (ferror(fp)) 38 | weprintf("%s: write error:", UTMP_PATH); 39 | fclose(fp); 40 | } else { 41 | weprintf("fopen %s:", UTMP_PATH); 42 | } 43 | } 44 | 45 | static int 46 | dologin(struct passwd *pw, int preserve) 47 | { 48 | char *shell = pw->pw_shell[0] == '\0' ? "/bin/sh" : pw->pw_shell; 49 | 50 | if (preserve == 0) 51 | clearenv(); 52 | setenv("HOME", pw->pw_dir, 1); 53 | setenv("SHELL", shell, 1); 54 | setenv("USER", pw->pw_name, 1); 55 | setenv("LOGNAME", pw->pw_name, 1); 56 | setenv("PATH", ENV_PATH, 1); 57 | if (chdir(pw->pw_dir) < 0) 58 | eprintf("chdir %s:", pw->pw_dir); 59 | execlp(shell, shell, "-l", NULL); 60 | weprintf("execlp %s:", shell); 61 | return (errno == ENOENT) ? 127 : 126; 62 | } 63 | 64 | static void 65 | usage(void) 66 | { 67 | eprintf("usage: %s [-p] username\n", argv0); 68 | } 69 | 70 | int 71 | main(int argc, char *argv[]) 72 | { 73 | struct passwd *pw; 74 | char *pass, *user; 75 | char *tty; 76 | uid_t uid; 77 | gid_t gid; 78 | int pflag = 0; 79 | 80 | ARGBEGIN { 81 | case 'p': 82 | pflag = 1; 83 | break; 84 | default: 85 | usage(); 86 | } ARGEND; 87 | 88 | if (argc < 1) 89 | usage(); 90 | 91 | if (isatty(0) == 0 || isatty(1) == 0 || isatty(2) == 0) 92 | eprintf("no tty"); 93 | 94 | user = argv[0]; 95 | errno = 0; 96 | pw = getpwnam(user); 97 | if (!pw) { 98 | if (errno) 99 | eprintf("getpwnam %s:", user); 100 | else 101 | eprintf("who are you?\n"); 102 | } 103 | 104 | uid = pw->pw_uid; 105 | gid = pw->pw_gid; 106 | 107 | /* Flush pending input */ 108 | ioctl(0, TCFLSH, (void *)0); 109 | 110 | pass = getpass("Password: "); 111 | if (!pass) 112 | eprintf("getpass:"); 113 | if (pw_check(pw, pass) <= 0) 114 | exit(1); 115 | 116 | tty = ttyname(0); 117 | if (!tty) 118 | eprintf("ttyname:"); 119 | 120 | writeutmp(user, tty); 121 | 122 | if (initgroups(user, gid) < 0) 123 | eprintf("initgroups:"); 124 | if (setgid(gid) < 0) 125 | eprintf("setgid:"); 126 | if (setuid(uid) < 0) 127 | eprintf("setuid:"); 128 | 129 | return dologin(pw, pflag); 130 | } 131 | -------------------------------------------------------------------------------- /lsmod.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt LSMOD 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm lsmod 6 | .Nd list loaded kernel modules 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Sh DESCRIPTION 10 | .Nm 11 | parses 12 | .Pa /proc/modules 13 | and shows the loadable kernel modules that are currently loaded. 14 | -------------------------------------------------------------------------------- /lsmod.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | 6 | #include "text.h" 7 | #include "util.h" 8 | 9 | static void parse_modline(char *buf, char **name, char **size, 10 | char **refcount, char **users); 11 | 12 | static void 13 | usage(void) 14 | { 15 | eprintf("usage: %s\n", argv0); 16 | } 17 | 18 | int 19 | main(int argc, char *argv[]) 20 | { 21 | const char *modfile = "/proc/modules"; 22 | FILE *fp; 23 | char *buf = NULL; 24 | char *name, *size, *refcount, *users; 25 | size_t bufsize = 0; 26 | size_t len; 27 | 28 | ARGBEGIN { 29 | default: 30 | usage(); 31 | } ARGEND; 32 | 33 | if (argc > 0) 34 | usage(); 35 | 36 | fp = fopen(modfile, "r"); 37 | if (!fp) 38 | eprintf("fopen %s:", modfile); 39 | 40 | printf("%-23s Size Used by\n", "Module"); 41 | 42 | while (agetline(&buf, &bufsize, fp) != -1) { 43 | parse_modline(buf, &name, &size, &refcount, &users); 44 | if (!name || !size || !refcount || !users) 45 | eprintf("invalid format: %s\n", modfile); 46 | len = strlen(users) - 1; 47 | if (users[len] == ',' || users[len] == '-') 48 | users[len] = '\0'; 49 | printf("%-20s%8s%3s %s\n", name, size, refcount, 50 | users); 51 | } 52 | if (ferror(fp)) 53 | eprintf("%s: read error:", modfile); 54 | free(buf); 55 | fclose(fp); 56 | return 0; 57 | } 58 | 59 | static void 60 | parse_modline(char *buf, char **name, char **size, 61 | char **refcount, char **users) 62 | { 63 | *name = strtok(buf, " "); 64 | *size = strtok(NULL, " "); 65 | *refcount = strtok(NULL, " "); 66 | *users = strtok(NULL, " "); 67 | } 68 | -------------------------------------------------------------------------------- /lsusb.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt LSUSB 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm lsusb 6 | .Nd list USB devices 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Sh DESCRIPTION 10 | .Nm 11 | searches in 12 | .Pa /sys/bus/usb/devices 13 | for USB's and connected devices and prints them one by one. -------------------------------------------------------------------------------- /lsusb.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | 6 | #include "text.h" 7 | #include "util.h" 8 | 9 | static void 10 | lsusb(const char *file) 11 | { 12 | FILE *fp; 13 | char path[PATH_MAX]; 14 | char *buf = NULL; 15 | size_t size = 0; 16 | unsigned int i = 0, busnum = 0, devnum = 0, pid = 0, vid = 0; 17 | 18 | if (strlcpy(path, file, sizeof(path)) >= sizeof(path)) 19 | eprintf("path too long\n"); 20 | if (strlcat(path, "/uevent", sizeof(path)) >= sizeof(path)) 21 | eprintf("path too long\n"); 22 | 23 | if (!(fp = fopen(path, "r"))) 24 | return; 25 | while (agetline(&buf, &size, fp) != -1) { 26 | if (sscanf(buf, "BUSNUM=%u\n", &busnum) || 27 | sscanf(buf, "DEVNUM=%u\n", &devnum) || 28 | sscanf(buf, "PRODUCT=%x/%x/", &pid, &vid)) 29 | i++; 30 | if (i == 3) { 31 | printf("Bus %03d Device %03d: ID %04x:%04x\n", busnum, devnum, 32 | pid, vid); 33 | break; 34 | } 35 | } 36 | if (ferror(fp)) 37 | eprintf("%s: read error:", path); 38 | free(buf); 39 | fclose(fp); 40 | } 41 | 42 | static void 43 | usage(void) 44 | { 45 | eprintf("usage: %s\n", argv0); 46 | } 47 | 48 | int 49 | main(int argc, char *argv[]) 50 | { 51 | ARGBEGIN { 52 | default: 53 | usage(); 54 | } ARGEND; 55 | 56 | recurse("/sys/bus/usb/devices", lsusb); 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /mesg.1: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt MESG 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm mesg 6 | .Nd display (do not display) messages from other users 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl n | Fl y 10 | .Sh DESCRIPTION 11 | .Nm 12 | controls write access others have to the terminal device associated with 13 | standard error output. If write access is allowed, then programs such as 14 | .Xr talk 1 15 | and 16 | .Xr write 1 17 | may display messages on the terminal. 18 | .Sh OPTIONS 19 | .Bl -tag -width Ds 20 | .It Fl n 21 | Disallow messages. 22 | .It Fl y 23 | Allow messages. 24 | .El 25 | .Sh SEE ALSO 26 | .Xr talk 1 , 27 | .Xr write 1 28 | -------------------------------------------------------------------------------- /mesg.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "util.h" 10 | 11 | static void 12 | usage(void) 13 | { 14 | eprintf("usage: %s [n|y]\n", argv0); 15 | } 16 | 17 | int 18 | main(int argc, char *argv[]) 19 | { 20 | struct stat sb; 21 | mode_t mode; 22 | 23 | ARGBEGIN { 24 | default: 25 | usage(); 26 | } ARGEND; 27 | 28 | if (argc > 1) 29 | usage(); 30 | 31 | if (isatty(2) == 0) 32 | eprintf("stderr: not a tty\n"); 33 | 34 | if (fstat(2, &sb) < 0) 35 | eprintf("fstat stderr:"); 36 | 37 | if (argc == 0) { 38 | puts(sb.st_mode & (S_IWGRP | S_IWOTH) ? "is y" : "is n"); 39 | return 0; 40 | } 41 | 42 | if (argv[0][0] == 'y' && argv[0][1] == '\0') 43 | mode = sb.st_mode | S_IWGRP | S_IWOTH; 44 | else if (argv[0][0] == 'n' && argv[0][1] == '\0') 45 | mode = sb.st_mode & ~(S_IWGRP | S_IWOTH); 46 | else 47 | usage(); 48 | 49 | if (fchmod(2, mode) < 0) 50 | eprintf("fchmod stderr:"); 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /mkswap.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt MKSWAP 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm mkswap 6 | .Nd set up a Linux swap area 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Ar device 10 | .Sh DESCRIPTION 11 | .Nm 12 | sets up a Linux swap area on a device or in a file. The 13 | .Ar device 14 | argument will usually be a disk-partition but it can also be a file. After 15 | creating the swap area you will typically need to use the 16 | .Xr swapon 8 17 | command to start using it. 18 | .Sh SEE ALSO 19 | .Xr swapon 8 20 | -------------------------------------------------------------------------------- /mkswap.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "util.h" 11 | 12 | #define SWAP_UUID_LENGTH 16 13 | #define SWAP_LABEL_LENGTH 16 14 | #define SWAP_MIN_PAGES 10 15 | 16 | struct swap_hdr { 17 | char bootbits[1024]; 18 | unsigned int version; 19 | unsigned int last_page; 20 | unsigned int nr_badpages; 21 | unsigned char uuid[SWAP_UUID_LENGTH]; 22 | char volume_name[SWAP_LABEL_LENGTH]; 23 | unsigned int padding[117]; 24 | unsigned int badpages[1]; 25 | }; 26 | 27 | static void 28 | usage(void) 29 | { 30 | eprintf("usage: %s device\n", argv0); 31 | } 32 | 33 | int 34 | main(int argc, char *argv[]) 35 | { 36 | int fd; 37 | unsigned int pages; 38 | long pagesize; 39 | struct stat sb; 40 | char *buf; 41 | struct swap_hdr *hdr; 42 | 43 | ARGBEGIN { 44 | default: 45 | usage(); 46 | } ARGEND; 47 | 48 | if (argc < 1) 49 | usage(); 50 | 51 | pagesize = sysconf(_SC_PAGESIZE); 52 | if (pagesize <= 0) { 53 | pagesize = sysconf(_SC_PAGE_SIZE); 54 | if (pagesize <= 0) 55 | eprintf("can't determine pagesize\n"); 56 | } 57 | 58 | fd = open(argv[0], O_RDWR); 59 | if (fd < 0) 60 | eprintf("open %s:", argv[0]); 61 | if (fstat(fd, &sb) < 0) 62 | eprintf("stat %s:", argv[0]); 63 | 64 | buf = ecalloc(1, pagesize); 65 | 66 | pages = sb.st_size / pagesize; 67 | if (pages < SWAP_MIN_PAGES) 68 | eprintf("swap space needs to be at least %ldKiB\n", 69 | SWAP_MIN_PAGES * pagesize / 1024); 70 | 71 | /* Fill up the swap header */ 72 | hdr = (struct swap_hdr *)buf; 73 | hdr->version = 1; 74 | hdr->last_page = pages - 1; 75 | memcpy(buf + pagesize - 10, "SWAPSPACE2", 10); 76 | 77 | printf("Setting up swapspace version 1, size = %luKiB\n", 78 | (pages - 1) * pagesize / 1024); 79 | 80 | /* Write out the signature page */ 81 | if (write(fd, buf, pagesize) != pagesize) 82 | eprintf("unable to write signature page\n"); 83 | 84 | fsync(fd); 85 | close(fd); 86 | free(buf); 87 | 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /mount.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt MOUNT 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm mount 6 | .Nd mount a filesystem 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl BMRan 10 | .Op Fl o Ar options 11 | .Op Fl t Ar fstype 12 | .Op Ar source 13 | .Op Ar target 14 | .Sh DESCRIPTION 15 | .Nm 16 | attaches the filesystem specified to the filesystem hierarchy. The 17 | .Xr umount 8 18 | command will detach it again. 19 | .Sh OPTIONS 20 | .Bl -tag -width Ds 21 | .It Fl B 22 | Remount a subtree somewhere else (so that its contents are visible in both 23 | places). 24 | .It Fl M 25 | Move a subtree to some other place. 26 | .It Fl R 27 | Remount a subtree and all possible submounts somewhere else (so that its 28 | contents are available in both places). 29 | .It Fl a 30 | Mount all filesystems mentioned in 31 | .Pa /etc/fstab . 32 | .It Fl n 33 | Mount without writing in 34 | .Pa /etc/mtab . 35 | This is the default action. 36 | .It Fl o Ar options 37 | Specify a comma separated string of filesystem specific options. 38 | .It Fl t Ar fstype 39 | Set the filesystem type. More than one type may be specified in a comma 40 | separated list. The list of file system types can be prefixed with "no" to 41 | specify the file system types for which action should not be taken. For 42 | example, the 43 | .Nm 44 | command: 45 | .Bd -literal 46 | # mount -a -t nonfs,ext4 47 | 48 | .Ed 49 | mounts all file systems except those of type NFS and EXT4. 50 | .Nm 51 | will attempt to execute a program in your 52 | .Ev PATH 53 | mount.XXX where XXX is replaced by the type name. For example, NFS file 54 | systems are mounted by the program 55 | .Pa mount.nfs . 56 | .El 57 | .Sh SEE ALSO 58 | .Xr mount 2 , 59 | .Xr umount 2 , 60 | .Xr swapon 8 , 61 | .Xr umount 8 62 | -------------------------------------------------------------------------------- /mount.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "text.h" 16 | #include "util.h" 17 | 18 | struct { 19 | const char *opt; 20 | const char *notopt; 21 | unsigned long v; 22 | } optnames[] = { 23 | { "defaults", NULL, 0 }, 24 | { "remount", NULL, MS_REMOUNT }, 25 | { "ro", "rw", MS_RDONLY }, 26 | { "sync", "async", MS_SYNCHRONOUS }, 27 | { "dirsync", NULL, MS_DIRSYNC }, 28 | { "nodev", "dev", MS_NODEV }, 29 | { "noatime", "atime", MS_NOATIME }, 30 | { "noauto", "auto", 0 }, 31 | { "nodiratime", "diratime", MS_NODIRATIME }, 32 | { "noexec", "exec", MS_NOEXEC }, 33 | { "nosuid", "suid", MS_NOSUID }, 34 | { "mand", "nomand", MS_MANDLOCK }, 35 | { "relatime", "norelatime", MS_RELATIME }, 36 | { "bind", NULL, MS_BIND }, 37 | { "move", NULL, MS_MOVE }, 38 | { NULL, NULL, 0 } 39 | }; 40 | 41 | static unsigned long argflags = 0; 42 | static char *argopts = NULL; 43 | 44 | static char * 45 | findtype(const char *types, const char *t) 46 | { 47 | const char *p; 48 | size_t len; 49 | 50 | for (len = strlen(t); (p = strstr(types, t)); types = p + len) { 51 | if (!strncmp(p, t, len) && (p[len] == '\0' || p[len] == ',')) 52 | return (char *)p; 53 | } 54 | return NULL; 55 | } 56 | 57 | static void 58 | parseopts(const char *popts, unsigned long *flags, char *data, size_t datasiz) 59 | { 60 | unsigned int i, validopt; 61 | size_t optlen, dlen = 0; 62 | const char *name, *e; 63 | 64 | name = popts; 65 | data[0] = '\0'; 66 | do { 67 | if ((e = strstr(name, ","))) 68 | optlen = e - name; 69 | else 70 | optlen = strlen(name); 71 | 72 | validopt = 0; 73 | for (i = 0; optnames[i].opt; i++) { 74 | if (optnames[i].opt && 75 | !strncmp(name, optnames[i].opt, optlen)) { 76 | *flags |= optnames[i].v; 77 | validopt = 1; 78 | break; 79 | } 80 | if (optnames[i].notopt && 81 | !strncmp(name, optnames[i].notopt, optlen)) { 82 | *flags &= ~optnames[i].v; 83 | validopt = 1; 84 | break; 85 | } 86 | } 87 | 88 | if (!validopt && optlen > 0) { 89 | /* unknown option, pass as data option to mount() */ 90 | if (dlen + optlen + 2 >= datasiz) 91 | return; /* prevent overflow */ 92 | if (dlen) 93 | data[dlen++] = ','; 94 | memcpy(&data[dlen], name, optlen); 95 | dlen += optlen; 96 | data[dlen] = '\0'; 97 | } 98 | name = e + 1; 99 | } while (e); 100 | } 101 | 102 | static int 103 | mounthelper(const char *fsname, const char *dir, const char *fstype) 104 | { 105 | pid_t pid; 106 | char eprog[PATH_MAX]; 107 | char const *eargv[10]; 108 | int status, i; 109 | 110 | pid = fork(); 111 | switch(pid) { 112 | case -1: 113 | break; 114 | case 0: 115 | snprintf(eprog, sizeof(eprog), "mount.%s", fstype); 116 | 117 | i = 0; 118 | eargv[i++] = eprog; 119 | if (argflags & MS_BIND) 120 | eargv[i++] = "-B"; 121 | if (argflags & MS_MOVE) 122 | eargv[i++] = "-M"; 123 | if (argflags & MS_REC) 124 | eargv[i++] = "-R"; 125 | 126 | if (argopts) { 127 | eargv[i++] = "-o"; 128 | eargv[i++] = argopts; 129 | } 130 | eargv[i++] = fsname; 131 | eargv[i++] = dir; 132 | eargv[i] = NULL; 133 | 134 | execvp(eprog, (char * const *)eargv); 135 | if (errno == ENOENT) 136 | _exit(1); 137 | weprintf("execvp:"); 138 | _exit(1); 139 | break; 140 | default: 141 | if (waitpid(pid, &status, 0) < 0) { 142 | weprintf("waitpid:"); 143 | return -1; 144 | } 145 | if (WIFEXITED(status)) 146 | return WEXITSTATUS(status); 147 | else if (WIFSIGNALED(status)) 148 | return 1; 149 | break; 150 | } 151 | return 0; 152 | } 153 | 154 | static int 155 | mounted(const char *dir) 156 | { 157 | FILE *fp; 158 | struct mntent *me, mebuf; 159 | struct stat st1, st2; 160 | char linebuf[256]; 161 | 162 | if (stat(dir, &st1) < 0) { 163 | weprintf("stat %s:", dir); 164 | return 0; 165 | } 166 | if (!(fp = setmntent("/proc/mounts", "r"))) 167 | eprintf("setmntent %s:", "/proc/mounts"); 168 | 169 | while ((me = getmntent_r(fp, &mebuf, linebuf, sizeof(linebuf)))) { 170 | if (stat(me->mnt_dir, &st2) < 0) { 171 | weprintf("stat %s:", me->mnt_dir); 172 | continue; 173 | } 174 | if (st1.st_dev == st2.st_dev && 175 | st1.st_ino == st2.st_ino) 176 | return 1; 177 | } 178 | endmntent(fp); 179 | 180 | return 0; 181 | } 182 | 183 | static void 184 | usage(void) 185 | { 186 | eprintf("usage: %s [-BMRan] [-t fstype] [-o options] [source] [target]\n", 187 | argv0); 188 | } 189 | 190 | int 191 | main(int argc, char *argv[]) 192 | { 193 | char *types = NULL, data[512] = "", *resolvpath = NULL; 194 | char *files[] = { "/proc/mounts", "/etc/fstab", NULL }; 195 | const char *source, *target; 196 | struct mntent *me = NULL; 197 | int aflag = 0, status = 0, i, r; 198 | unsigned long flags = 0; 199 | FILE *fp; 200 | 201 | ARGBEGIN { 202 | case 'B': 203 | argflags |= MS_BIND; 204 | break; 205 | case 'M': 206 | argflags |= MS_MOVE; 207 | break; 208 | case 'R': 209 | argflags |= MS_REC; 210 | break; 211 | case 'a': 212 | aflag = 1; 213 | break; 214 | case 'o': 215 | argopts = EARGF(usage()); 216 | parseopts(argopts, &flags, data, sizeof(data)); 217 | break; 218 | case 't': 219 | types = EARGF(usage()); 220 | break; 221 | case 'n': 222 | break; 223 | default: 224 | usage(); 225 | } ARGEND; 226 | 227 | if (argc < 1 && aflag == 0) { 228 | if (!(fp = fopen(files[0], "r"))) 229 | eprintf("fopen %s:", files[0]); 230 | concat(fp, files[0], stdout, ""); 231 | fclose(fp); 232 | return 0; 233 | } 234 | 235 | if (aflag == 1) 236 | goto mountall; 237 | 238 | source = argv[0]; 239 | target = argv[1]; 240 | 241 | if (!target) { 242 | target = argv[0]; 243 | source = NULL; 244 | if (strcmp(target, "/") != 0) { 245 | if (!(resolvpath = realpath(target, NULL))) 246 | eprintf("realpath %s:", target); 247 | target = resolvpath; 248 | } 249 | } 250 | 251 | for (i = 0; files[i]; i++) { 252 | if (!(fp = setmntent(files[i], "r"))) { 253 | if (strcmp(files[i], "/proc/mounts") != 0) 254 | weprintf("setmntent %s:", files[i]); 255 | continue; 256 | } 257 | while ((me = getmntent(fp))) { 258 | if (strcmp(me->mnt_dir, target) == 0 || 259 | strcmp(me->mnt_fsname, target) == 0 || 260 | (source && strcmp(me->mnt_dir, source) == 0) || 261 | (source && strcmp(me->mnt_fsname, source) == 0)) { 262 | if (!source) { 263 | target = me->mnt_dir; 264 | source = me->mnt_fsname; 265 | } 266 | if (!argopts) { 267 | argopts = me->mnt_opts; 268 | parseopts(argopts, &flags, data, sizeof(data)); 269 | } 270 | if (!types) 271 | types = me->mnt_type; 272 | goto mountsingle; 273 | } 274 | } 275 | endmntent(fp); 276 | fp = NULL; 277 | } 278 | if (!source) 279 | eprintf("can't find %s in /etc/fstab\n", target); 280 | 281 | mountsingle: 282 | r = mounthelper(source, target, types); 283 | if (r == -1) 284 | status = 1; 285 | if (r > 0 && mount(source, target, types, argflags | flags, data) < 0) { 286 | weprintf("mount: %s:", source); 287 | status = 1; 288 | } 289 | if (fp) 290 | endmntent(fp); 291 | free(resolvpath); 292 | return status; 293 | 294 | mountall: 295 | if (!(fp = setmntent("/etc/fstab", "r"))) 296 | eprintf("setmntent %s:", "/etc/fstab"); 297 | while ((me = getmntent(fp))) { 298 | /* has "noauto" option or already mounted: skip */ 299 | if (hasmntopt(me, MNTOPT_NOAUTO) || mounted(me->mnt_dir)) 300 | continue; 301 | flags = 0; 302 | argopts = me->mnt_opts; 303 | parseopts(argopts, &flags, data, sizeof(data)); 304 | /* if -t types specified: 305 | * if non-match, skip 306 | * if match and prefixed with "no", skip */ 307 | if (types && 308 | ((types[0] == 'n' && types[1] == 'o' && 309 | findtype(types + 2, me->mnt_type)) || 310 | (!findtype(types, me->mnt_type)))) 311 | continue; 312 | 313 | r = mounthelper(me->mnt_fsname, me->mnt_dir, me->mnt_type); 314 | if (r > 0 && mount(me->mnt_fsname, me->mnt_dir, me->mnt_type, 315 | argflags | flags, data) < 0) { 316 | weprintf("mount: %s:", me->mnt_fsname); 317 | status = 1; 318 | } 319 | } 320 | endmntent(fp); 321 | 322 | return status; 323 | } 324 | -------------------------------------------------------------------------------- /mountpoint.1: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt MOUNTPOINT 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm mountpoint 6 | .Nd check if a directory is a mountpoint 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl dq 10 | .Ar directory 11 | .Nm 12 | .Fl x Ar device 13 | .Sh DESCRIPTION 14 | .Nm 15 | checks if the 16 | .Ar directory 17 | is mentioned in the 18 | .Pa /proc/mounts 19 | file. 20 | .Sh OPTIONS 21 | .Bl -tag -width Ds 22 | .It Fl d 23 | Print the major/minor device number of the filesystem on stdout. 24 | .It Fl q 25 | Be quiet, don't print anything. 26 | .It Fl x 27 | Print the major/minor device number of the 28 | .Ar device 29 | on stdout. 30 | .El 31 | .Sh SEE ALSO 32 | .Xr mount 8 33 | -------------------------------------------------------------------------------- /mountpoint.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #ifndef major 5 | #include 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "util.h" 15 | 16 | static void 17 | usage(void) 18 | { 19 | eprintf("usage: %s [-dqx] target\n", argv0); 20 | } 21 | 22 | int 23 | main(int argc, char *argv[]) 24 | { 25 | int dflag = 0, qflag = 0, xflag = 0; 26 | int ret = 0; 27 | struct mntent *me = NULL; 28 | FILE *fp; 29 | struct stat st1, st2; 30 | 31 | ARGBEGIN { 32 | case 'd': 33 | dflag = 1; 34 | break; 35 | case 'q': 36 | qflag = 1; 37 | break; 38 | case 'x': 39 | xflag = 1; 40 | break; 41 | default: 42 | usage(); 43 | } ARGEND; 44 | 45 | if (argc < 1) 46 | usage(); 47 | 48 | if (stat(argv[0], &st1) < 0) { 49 | if (qflag) 50 | return 1; 51 | eprintf("stat %s:", argv[0]); 52 | } 53 | 54 | if (xflag) { 55 | if (!S_ISBLK(st1.st_mode)) { 56 | if (qflag) 57 | return 1; 58 | eprintf("stat: %s: not a block device\n", 59 | argv[0]); 60 | } 61 | printf("%u:%u\n", major(st1.st_rdev), 62 | minor(st1.st_rdev)); 63 | return 0; 64 | } 65 | 66 | if (!S_ISDIR(st1.st_mode)) { 67 | if (qflag) 68 | return 1; 69 | eprintf("stat %s: not a directory\n", argv[0]); 70 | } 71 | 72 | if (dflag) { 73 | printf("%u:%u\n", major(st1.st_dev), 74 | minor(st1.st_dev)); 75 | return 0; 76 | } 77 | 78 | fp = setmntent("/proc/mounts", "r"); 79 | if (!fp) { 80 | if (qflag) 81 | return 1; 82 | eprintf("setmntent %s:", "/proc/mounts"); 83 | } 84 | while ((me = getmntent(fp)) != NULL) { 85 | if (stat(me->mnt_dir, &st2) < 0) { 86 | if (qflag) 87 | return 1; 88 | eprintf("stat %s:", me->mnt_dir); 89 | } 90 | if (st1.st_dev == st2.st_dev && 91 | st1.st_ino == st2.st_ino) 92 | break; 93 | } 94 | endmntent(fp); 95 | 96 | if (me == NULL) 97 | ret = 1; 98 | 99 | if (!qflag) 100 | printf("%s %s a mountpoint\n", argv[0], 101 | !ret ? "is" : "is not"); 102 | 103 | return ret; 104 | } 105 | -------------------------------------------------------------------------------- /nologin.8: -------------------------------------------------------------------------------- 1 | .Dd March 26, 2016 2 | .Dt NOLOGIN 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm nologin 6 | .Nd refuse login 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Sh DESCRIPTION 10 | .Nm 11 | prints a message informing the user that she 12 | is not allowed to log in. If /etc/nologin.txt 13 | exists, its content is printed instead of 14 | the default message. 15 | .Pp 16 | .Nm 17 | is intended to be specified as the user's 18 | default shell. 19 | .Sh EXIT STATUS 20 | .Nm 21 | returns a status code indicating failure. 22 | -------------------------------------------------------------------------------- /nologin.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | 6 | int 7 | main(void) 8 | { 9 | int fd; 10 | char buf[BUFSIZ]; 11 | ssize_t n; 12 | 13 | fd = open("/etc/nologin.txt", O_RDONLY); 14 | if (fd >= 0) { 15 | while ((n = read(fd, buf, sizeof(buf))) > 0) 16 | write(STDOUT_FILENO, buf, n); 17 | close(fd); 18 | } else { 19 | printf("The account is currently unavailable.\n"); 20 | } 21 | return 1; 22 | } 23 | -------------------------------------------------------------------------------- /pagesize.1: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt PAGESIZE 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm pagesize 6 | .Nd print system page size 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Sh DESCRIPTION 10 | .Nm 11 | prints the size of a page of memory in bytes. This program is 12 | useful in constructing portable shell scripts. -------------------------------------------------------------------------------- /pagesize.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | 6 | #include "util.h" 7 | 8 | static void 9 | usage(void) 10 | { 11 | eprintf("usage: %s\n", argv0); 12 | } 13 | 14 | int 15 | main(int argc, char *argv[]) 16 | { 17 | long pagesz; 18 | 19 | ARGBEGIN { 20 | default: 21 | usage(); 22 | } ARGEND; 23 | 24 | pagesz = sysconf(_SC_PAGESIZE); 25 | if (pagesz <= 0) { 26 | pagesz = sysconf(_SC_PAGE_SIZE); 27 | if (pagesz <= 0) 28 | eprintf("can't determine pagesize\n"); 29 | } 30 | printf("%ld\n", pagesz); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /passwd.1: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt PASSWD 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm passwd 6 | .Nd change a user's password 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Ar username 10 | .Sh DESCRIPTION 11 | .Nm 12 | changes the user's password. The user is prompted for their current password. 13 | If the current password is correctly typed, a new password is requested. The 14 | new password must be entered twice to avoid typing errors. The superuser is 15 | not required to provide a user's current password. 16 | -------------------------------------------------------------------------------- /passwd.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "config.h" 19 | #include "passwd.h" 20 | #include "text.h" 21 | #include "util.h" 22 | 23 | static FILE * 24 | spw_get_file(const char *user) 25 | { 26 | FILE *fp = NULL; 27 | char file[PATH_MAX]; 28 | int r; 29 | 30 | r = snprintf(file, sizeof(file), "/etc/tcb/%s/shadow", user); 31 | if (r < 0 || (size_t)r >= sizeof(file)) 32 | eprintf("snprintf:"); 33 | fp = fopen(file, "r+"); 34 | if (!fp) 35 | fp = fopen("/etc/shadow", "r+"); 36 | return fp; 37 | } 38 | 39 | static int 40 | spw_write_file(FILE *fp, const struct spwd *spw, char *pwhash) 41 | { 42 | struct spwd *spwent; 43 | int r = -1, w = 0; 44 | FILE *tfp = NULL; 45 | 46 | /* write to temporary file. */ 47 | tfp = tmpfile(); 48 | if (!tfp) { 49 | weprintf("tmpfile:"); 50 | goto cleanup; 51 | } 52 | while ((spwent = fgetspent(fp))) { 53 | /* update entry on name match */ 54 | if (strcmp(spwent->sp_namp, spw->sp_namp) == 0) { 55 | spwent->sp_pwdp = pwhash; 56 | w++; 57 | } 58 | errno = 0; 59 | if (putspent(spwent, tfp) == -1) { 60 | weprintf("putspent:"); 61 | goto cleanup; 62 | } 63 | } 64 | if (!w) { 65 | weprintf("shadow: no matching entry to write to\n"); 66 | goto cleanup; 67 | } 68 | fflush(tfp); 69 | 70 | if (fseek(fp, 0, SEEK_SET) == -1 || fseek(tfp, 0, SEEK_SET) == -1) { 71 | weprintf("fseek:"); 72 | goto cleanup; 73 | } 74 | 75 | /* write temporary file to (tcb) shadow file */ 76 | concat(tfp, "tmpfile", fp, "shadow"); 77 | ftruncate(fileno(fp), ftell(tfp)); 78 | 79 | r = 0; /* success */ 80 | cleanup: 81 | if (tfp) 82 | fclose(tfp); 83 | return r; 84 | } 85 | 86 | static int 87 | pw_write_file(FILE *fp, const struct passwd *pw, char *pwhash) { 88 | struct passwd *pwent; 89 | int r = -1, w = 0; 90 | FILE *tfp = NULL; 91 | 92 | /* write to temporary file. */ 93 | tfp = tmpfile(); 94 | if (!tfp) { 95 | weprintf("tmpfile:"); 96 | goto cleanup; 97 | } 98 | while ((pwent = fgetpwent(fp))) { 99 | /* update entry on name match */ 100 | if (strcmp(pwent->pw_name, pw->pw_name) == 0) { 101 | pwent->pw_passwd = pwhash; 102 | w++; 103 | } 104 | errno = 0; 105 | if (putpwent(pwent, tfp) == -1) { 106 | weprintf("putpwent:"); 107 | goto cleanup; 108 | } 109 | } 110 | if (!w) { 111 | weprintf("passwd: no matching entry to write to\n"); 112 | goto cleanup; 113 | } 114 | fflush(tfp); 115 | 116 | if (fseek(fp, 0, SEEK_SET) == -1 || fseek(tfp, 0, SEEK_SET) == -1) { 117 | weprintf("fseek:"); 118 | goto cleanup; 119 | } 120 | 121 | /* write to passwd file. */ 122 | concat(tfp, "tmpfile", fp, "passwd"); 123 | ftruncate(fileno(fp), ftell(tfp)); 124 | 125 | r = 0; /* success */ 126 | cleanup: 127 | if (tfp) 128 | fclose(tfp); 129 | return r; 130 | } 131 | 132 | /* generates a random base64-encoded salt string of length 16 */ 133 | static void 134 | gensalt(char *s) 135 | { 136 | static const char b64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 137 | uint8_t buf[12]; 138 | uint32_t n; 139 | int i; 140 | 141 | if (syscall(SYS_getrandom, buf, sizeof(buf), 0) < 0) 142 | eprintf("getrandom:"); 143 | for (i = 0; i < 12; i += 3) { 144 | n = buf[i] << 16 | buf[i+1] << 8 | buf[i+2]; 145 | *s++ = b64[n%64]; n /= 64; 146 | *s++ = b64[n%64]; n /= 64; 147 | *s++ = b64[n%64]; n /= 64; 148 | *s++ = b64[n]; 149 | } 150 | *s++ = '\0'; 151 | } 152 | 153 | static void 154 | usage(void) 155 | { 156 | eprintf("usage: %s [username]\n", argv0); 157 | } 158 | 159 | int 160 | main(int argc, char *argv[]) 161 | { 162 | char *cryptpass1 = NULL, *cryptpass2 = NULL, *cryptpass3 = NULL; 163 | char *inpass, *p, *prevhash, salt[sizeof(PW_CIPHER) + 16] = PW_CIPHER; 164 | struct passwd *pw; 165 | struct spwd *spw = NULL; 166 | FILE *fp = NULL; 167 | int r = -1, status = 1; 168 | 169 | ARGBEGIN { 170 | default: 171 | usage(); 172 | } ARGEND; 173 | 174 | pw_init(); 175 | umask(077); 176 | 177 | errno = 0; 178 | if (argc == 0) 179 | pw = getpwuid(getuid()); 180 | else 181 | pw = getpwnam(argv[0]); 182 | if (!pw) { 183 | if (errno) 184 | eprintf("getpwnam: %s:", argv[0]); 185 | else 186 | eprintf("who are you?\n"); 187 | } 188 | 189 | /* is using shadow entry ? */ 190 | if (pw->pw_passwd[0] == 'x' && pw->pw_passwd[1] == '\0') { 191 | errno = 0; 192 | spw = getspnam(pw->pw_name); 193 | if (!spw) { 194 | if (errno) 195 | eprintf("getspnam: %s:", pw->pw_name); 196 | else 197 | eprintf("who are you?\n"); 198 | } 199 | prevhash = spw->sp_pwdp; 200 | } else { 201 | prevhash = pw->pw_passwd; 202 | } 203 | 204 | /* Flush pending input */ 205 | ioctl(0, TCFLSH, (void *)0); 206 | 207 | if (getuid() != 0 && prevhash[0] != '\0') { 208 | if (prevhash[0] == '!' || prevhash[0] == '*') 209 | eprintf("denied\n"); 210 | printf("Changing password for %s\n", pw->pw_name); 211 | inpass = getpass("Old password: "); 212 | if (!inpass) 213 | eprintf("getpass:"); 214 | if (inpass[0] == '\0') 215 | eprintf("no password supplied\n"); 216 | p = crypt(inpass, prevhash); 217 | if (!p) 218 | eprintf("crypt:"); 219 | cryptpass1 = estrdup(p); 220 | if (strcmp(cryptpass1, prevhash) != 0) 221 | eprintf("incorrect password\n"); 222 | } 223 | 224 | inpass = getpass("Enter new password: "); 225 | if (!inpass) 226 | eprintf("getpass:"); 227 | if (inpass[0] == '\0') 228 | eprintf("no password supplied\n"); 229 | 230 | if (cryptpass1) { 231 | p = crypt(inpass, prevhash); 232 | if (!p) 233 | eprintf("crypt:"); 234 | if (strcmp(cryptpass1, p) == 0) 235 | eprintf("password left unchanged\n"); 236 | } 237 | gensalt(salt + strlen(salt)); 238 | p = crypt(inpass, salt); 239 | if (!p) 240 | eprintf("crypt:"); 241 | cryptpass2 = estrdup(p); 242 | 243 | /* Flush pending input */ 244 | ioctl(0, TCFLSH, (void *)0); 245 | 246 | inpass = getpass("Retype new password: "); 247 | if (!inpass) 248 | eprintf("getpass:"); 249 | if (inpass[0] == '\0') 250 | eprintf("no password supplied\n"); 251 | p = crypt(inpass, salt); 252 | if (!p) 253 | eprintf("crypt:"); 254 | cryptpass3 = estrdup(p); 255 | if (strcmp(cryptpass2, cryptpass3) != 0) 256 | eprintf("passwords don't match\n"); 257 | 258 | fp = spw_get_file(pw->pw_name); 259 | if (fp) { 260 | r = spw_write_file(fp, spw, cryptpass3); 261 | } else { 262 | fp = fopen("/etc/passwd", "r+"); 263 | if (fp) 264 | r = pw_write_file(fp, pw, cryptpass3); 265 | else 266 | weprintf("fopen:"); 267 | } 268 | if (!r) 269 | status = 0; 270 | 271 | if (fp) 272 | fclose(fp); 273 | free(cryptpass3); 274 | free(cryptpass2); 275 | free(cryptpass1); 276 | 277 | return status; 278 | } 279 | -------------------------------------------------------------------------------- /passwd.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | /* passwd.c */ 3 | int pw_check(const struct passwd *, const char *); 4 | int pw_init(void); 5 | -------------------------------------------------------------------------------- /pidof.1: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt PIDOF 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm pidof 6 | .Nd find the process ID of a running program 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl o Ar pid1,pid2,...pidN 10 | .Op Fl s 11 | .Op Ar program... 12 | .Sh DESCRIPTION 13 | .Nm 14 | finds the process id's of the named programs and prints them to 15 | stdout. 16 | .Sh OPTIONS 17 | .Bl -tag -width Ds 18 | .It Fl o 19 | Tell pidof to omit processes with that process id. The special pid 20 | %PPID can be used to name the parent process of the pidof program. 21 | .It Fl s 22 | Single shot - this instructs the program to only return one process id. 23 | .El 24 | .Sh SEE ALSO 25 | .Xr killall5 8 26 | -------------------------------------------------------------------------------- /pidof.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "proc.h" 13 | #include "queue.h" 14 | #include "util.h" 15 | 16 | struct pidentry { 17 | pid_t pid; 18 | SLIST_ENTRY(pidentry) entry; 19 | }; 20 | 21 | static SLIST_HEAD(, pidentry) omitpid_head; 22 | 23 | static void 24 | usage(void) 25 | { 26 | eprintf("usage: %s [-o pid1,pid2,...pidN] [-s] [program...]\n", argv0); 27 | } 28 | 29 | int 30 | main(int argc, char *argv[]) 31 | { 32 | DIR *dp; 33 | struct dirent *entry; 34 | pid_t pid; 35 | struct procstat ps; 36 | char cmdline[BUFSIZ], *cmd, *cmdbase = NULL, *p, *arg = NULL; 37 | int i, found = 0; 38 | int sflag = 0, oflag = 0; 39 | struct pidentry *pe; 40 | 41 | ARGBEGIN { 42 | case 's': 43 | sflag = 1; 44 | break; 45 | case 'o': 46 | oflag = 1; 47 | arg = EARGF(usage()); 48 | break; 49 | default: 50 | usage(); 51 | } ARGEND; 52 | 53 | if (!argc) 54 | return 1; 55 | 56 | SLIST_INIT(&omitpid_head); 57 | 58 | for (p = strtok(arg, ","); p; p = strtok(NULL, ",")) { 59 | pe = emalloc(sizeof(*pe)); 60 | if (strcmp(p, "%PPID") == 0) 61 | pe->pid = getppid(); 62 | else 63 | pe->pid = estrtol(p, 10); 64 | SLIST_INSERT_HEAD(&omitpid_head, pe, entry); 65 | } 66 | 67 | if (!(dp = opendir("/proc"))) 68 | eprintf("opendir /proc:"); 69 | 70 | while ((entry = readdir(dp))) { 71 | if (!pidfile(entry->d_name)) 72 | continue; 73 | pid = estrtol(entry->d_name, 10); 74 | if (oflag) { 75 | SLIST_FOREACH(pe, &omitpid_head, entry) 76 | if (pe->pid == pid) 77 | break; 78 | if (pe) 79 | continue; 80 | } 81 | if (parsestat(pid, &ps) < 0) 82 | continue; 83 | if (parsecmdline(ps.pid, cmdline, 84 | sizeof(cmdline)) < 0) { 85 | cmd = ps.comm; 86 | cmdbase = cmd; 87 | } else { 88 | if ((p = strchr(cmdline, ' '))) 89 | *p = '\0'; 90 | cmd = cmdline; 91 | cmdbase = basename(cmdline); 92 | } 93 | /* Workaround for login shells */ 94 | if (cmd[0] == '-') 95 | cmd++; 96 | for (i = 0; i < argc; i++) { 97 | if (strcmp(cmd, argv[i]) == 0 || 98 | strcmp(cmdbase, argv[i]) == 0) { 99 | putword(entry->d_name); 100 | found++; 101 | if (sflag) 102 | goto out; 103 | } 104 | } 105 | } 106 | 107 | out: 108 | if (found) 109 | putchar('\n'); 110 | 111 | closedir(dp); 112 | 113 | return 0; 114 | } 115 | -------------------------------------------------------------------------------- /pivot_root.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt PIVOT_ROOT 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm pivot_root 6 | .Nd change the root filesystem 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Ar newroot putold 10 | .Sh DESCRIPTION 11 | .Nm 12 | moves the root file system of the current process to the 13 | directory 14 | .Ar put_old 15 | and makes 16 | .Ar new_root 17 | the new root file system. 18 | -------------------------------------------------------------------------------- /pivot_root.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "util.h" 9 | 10 | static void 11 | usage(void) 12 | { 13 | eprintf("usage: %s new-root put-old\n", argv0); 14 | } 15 | 16 | int 17 | main(int argc, char *argv[]) 18 | { 19 | ARGBEGIN { 20 | default: 21 | usage(); 22 | } ARGEND; 23 | 24 | if (argc < 2) 25 | usage(); 26 | 27 | if (syscall(SYS_pivot_root, argv[0], argv[1]) < 0) 28 | eprintf("pivot_root:"); 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /proc.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | struct procstat { 3 | int pid; 4 | char comm[PATH_MAX + 2]; /* + 2 for '(' and ')' */ 5 | unsigned char state; 6 | int ppid; 7 | int pgrp; 8 | int sid; 9 | int tty_nr; 10 | int tpgid; 11 | unsigned flags; 12 | unsigned long minflt; 13 | unsigned long cminflt; 14 | unsigned long majflt; 15 | unsigned long cmajflt; 16 | unsigned long utime; 17 | unsigned long stime; 18 | long cutime; 19 | long cstime; 20 | long priority; 21 | long nice; 22 | long num_threads; 23 | long itrealvalue; 24 | unsigned long long starttime; 25 | unsigned long vsize; 26 | long rss; 27 | long rsslim; 28 | }; 29 | 30 | struct procstatus { 31 | uid_t uid; 32 | uid_t euid; 33 | gid_t gid; 34 | gid_t egid; 35 | }; 36 | 37 | int parsecmdline(pid_t pid, char *buf, size_t siz); 38 | int parsestat(pid_t pid, struct procstat *ps); 39 | int parsestatus(pid_t pid, struct procstatus *pstatus); 40 | int proceuid(pid_t pid, uid_t *euid); 41 | int procuid(pid_t pid, uid_t *euid); 42 | int pidfile(const char *file); 43 | -------------------------------------------------------------------------------- /ps.1: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt PS 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm ps 6 | .Nd display process status 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl aAdef 10 | .Sh DESCRIPTION 11 | .Nm 12 | displays information about active processes. When given no options, 13 | .Nm 14 | prints information about processes of the current user that has a 15 | controlling terminal. 16 | .Sh OPTIONS 17 | .Bl -tag -width Ds 18 | .It Fl a 19 | Select all processes except both session leaders and processes not 20 | associated with a terminal. 21 | .It Fl A 22 | Select all processes. Identical to \fB-e\fR. 23 | .It Fl d 24 | Select all processes except session leaders. 25 | .It Fl e 26 | Select all processes. Identical to \fB-A\fR. 27 | .It Fl f 28 | Do full-format listing. 29 | .El 30 | -------------------------------------------------------------------------------- /ps.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "proc.h" 16 | #include "util.h" 17 | 18 | static void psout(struct procstat *ps); 19 | static void psr(const char *file); 20 | 21 | enum { 22 | PS_aflag = 1 << 0, 23 | PS_Aflag = 1 << 1, 24 | PS_dflag = 1 << 2, 25 | PS_fflag = 1 << 3 26 | }; 27 | 28 | static int flags; 29 | 30 | static void 31 | psout(struct procstat *ps) 32 | { 33 | struct procstatus pstatus; 34 | char cmdline[BUFSIZ], *cmd; 35 | char buf[BUFSIZ]; 36 | char ttystr[TTY_NAME_MAX], *myttystr; 37 | int tty_maj, tty_min; 38 | uid_t myeuid; 39 | unsigned sutime; 40 | time_t start; 41 | char stimestr[sizeof("%H:%M")]; 42 | struct sysinfo info; 43 | struct passwd *pw; 44 | struct winsize w; 45 | 46 | /* Ignore session leaders */ 47 | if (flags & PS_dflag) 48 | if (ps->pid == ps->sid) 49 | return; 50 | 51 | devtotty(ps->tty_nr, &tty_maj, &tty_min); 52 | ttytostr(tty_maj, tty_min, ttystr, sizeof(ttystr)); 53 | 54 | /* Only print processes that are associated with 55 | * a terminal and they are not session leaders */ 56 | if (flags & PS_aflag) 57 | if (ps->pid == ps->sid || ttystr[0] == '?') 58 | return; 59 | 60 | if (parsestatus(ps->pid, &pstatus) < 0) 61 | return; 62 | 63 | /* This is the default case, only print processes that have 64 | * the same controlling terminal as the invoker and the same 65 | * euid as the current user */ 66 | if (!(flags & (PS_aflag | PS_Aflag | PS_dflag))) { 67 | myttystr = ttyname(0); 68 | if (myttystr) { 69 | if (strcmp(myttystr + strlen("/dev/"), ttystr)) 70 | return; 71 | } else { 72 | /* The invoker has no controlling terminal - just 73 | * go ahead and print the processes anyway */ 74 | ttystr[0] = '?'; 75 | ttystr[1] = '\0'; 76 | } 77 | myeuid = geteuid(); 78 | if (myeuid != pstatus.euid) 79 | return; 80 | } 81 | 82 | sutime = (ps->stime + ps->utime) / sysconf(_SC_CLK_TCK); 83 | 84 | ioctl(1, TIOCGWINSZ, &w); 85 | if (!(flags & PS_fflag)) { 86 | snprintf(buf, sizeof(buf), "%5d %-6s %02u:%02u:%02u %s", ps->pid, ttystr, 87 | sutime / 3600, (sutime % 3600) / 60, sutime % 60, 88 | ps->comm); 89 | if (w.ws_col) 90 | printf("%.*s\n", w.ws_col, buf); 91 | else 92 | printf("%s\n", buf); 93 | } else { 94 | errno = 0; 95 | pw = getpwuid(pstatus.uid); 96 | if (!pw) 97 | eprintf("getpwuid %d:", pstatus.uid); 98 | 99 | if (sysinfo(&info) < 0) 100 | eprintf("sysinfo:"); 101 | 102 | start = time(NULL) - info.uptime; 103 | start += (ps->starttime / sysconf(_SC_CLK_TCK)); 104 | strftime(stimestr, sizeof(stimestr), 105 | "%H:%M", localtime(&start)); 106 | 107 | /* For kthreads/zombies /proc//cmdline will be 108 | * empty so use ps->comm in that case */ 109 | if (parsecmdline(ps->pid, cmdline, sizeof(cmdline)) < 0) 110 | cmd = ps->comm; 111 | else 112 | cmd = cmdline; 113 | 114 | snprintf(buf, sizeof(buf), "%-8s %5d %5d ? %5s %-5s %02u:%02u:%02u %s%s%s", 115 | pw->pw_name, ps->pid, 116 | ps->ppid, stimestr, ttystr, 117 | sutime / 3600, (sutime % 3600) / 60, sutime % 60, 118 | (cmd == ps->comm) ? "[" : "", cmd, 119 | (cmd == ps->comm) ? "]" : ""); 120 | if (w.ws_col) 121 | printf("%.*s\n", w.ws_col, buf); 122 | else 123 | printf("%s\n", buf); 124 | } 125 | } 126 | 127 | static void 128 | psr(const char *file) 129 | { 130 | char path[PATH_MAX], *p; 131 | struct procstat ps; 132 | pid_t pid; 133 | 134 | if (strlcpy(path, file, sizeof(path)) >= sizeof(path)) 135 | eprintf("path too long\n"); 136 | p = basename(path); 137 | if (pidfile(p) == 0) 138 | return; 139 | pid = estrtol(p, 10); 140 | if (parsestat(pid, &ps) < 0) 141 | return; 142 | psout(&ps); 143 | } 144 | 145 | static void 146 | usage(void) 147 | { 148 | eprintf("usage: %s [-aAdef]\n", argv0); 149 | } 150 | 151 | int 152 | main(int argc, char *argv[]) 153 | { 154 | ARGBEGIN { 155 | case 'a': 156 | flags |= PS_aflag; 157 | break; 158 | case 'A': 159 | flags |= PS_Aflag; 160 | break; 161 | case 'd': 162 | flags |= PS_dflag; 163 | break; 164 | case 'e': 165 | flags |= PS_Aflag; 166 | break; 167 | case 'f': 168 | flags |= PS_fflag; 169 | break; 170 | default: 171 | usage(); 172 | } ARGEND; 173 | 174 | if (!(flags & PS_fflag)) 175 | printf(" PID TTY TIME CMD\n"); 176 | else 177 | printf("UID PID PPID C STIME TTY TIME CMD\n"); 178 | recurse("/proc", psr); 179 | return 0; 180 | } 181 | -------------------------------------------------------------------------------- /pwdx.1: -------------------------------------------------------------------------------- 1 | .Dd March 26, 2015 2 | .Dt PWDX 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm pwdx 6 | .Nd print working directory of other processes 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Ar pid... 10 | .Sh DESCRIPTION 11 | .Nm 12 | Prints the current working directory for each 13 | .Ar pid . 14 | -------------------------------------------------------------------------------- /pwdx.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "util.h" 9 | 10 | static void 11 | usage(void) 12 | { 13 | eprintf("usage: %s pid...\n", argv0); 14 | } 15 | 16 | int 17 | main(int argc, char *argv[]) 18 | { 19 | int ret = 0; 20 | char path[PATH_MAX]; 21 | char target[PATH_MAX + sizeof(" (deleted)")]; 22 | ssize_t n; 23 | 24 | ARGBEGIN { 25 | default: 26 | usage(); 27 | } ARGEND; 28 | 29 | if (argc == 0) 30 | usage(); 31 | 32 | for (; argc > 0; argc--, argv++) { 33 | n = snprintf(path, sizeof(path), "/proc/%s/cwd", *argv); 34 | if (n < 0 || n >= sizeof(path)) { 35 | errno = ESRCH; 36 | } else { 37 | n = readlink(path, target, sizeof(target) - 1); 38 | if (n >= 0) { 39 | target[n] = '\0'; 40 | printf("%s: %s\n", *argv, target); 41 | continue; 42 | } 43 | } 44 | if (errno == ENOENT) 45 | errno = ESRCH; 46 | weprintf("%s:", *argv); 47 | ret = 1; 48 | } 49 | 50 | return ret; 51 | } 52 | -------------------------------------------------------------------------------- /queue.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: queue.h,v 1.38 2013/07/03 15:05:21 fgsch Exp $ */ 2 | /* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ 3 | 4 | /* 5 | * Copyright (c) 1991, 1993 6 | * The Regents of the University of California. All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 3. Neither the name of the University nor the names of its contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | * SUCH DAMAGE. 31 | * 32 | * @(#)queue.h 8.5 (Berkeley) 8/20/94 33 | */ 34 | 35 | #ifndef _SYS_QUEUE_H_ 36 | #define _SYS_QUEUE_H_ 37 | 38 | /* 39 | * This file defines five types of data structures: singly-linked lists, 40 | * lists, simple queues, tail queues, and circular queues. 41 | * 42 | * 43 | * A singly-linked list is headed by a single forward pointer. The elements 44 | * are singly linked for minimum space and pointer manipulation overhead at 45 | * the expense of O(n) removal for arbitrary elements. New elements can be 46 | * added to the list after an existing element or at the head of the list. 47 | * Elements being removed from the head of the list should use the explicit 48 | * macro for this purpose for optimum efficiency. A singly-linked list may 49 | * only be traversed in the forward direction. Singly-linked lists are ideal 50 | * for applications with large datasets and few or no removals or for 51 | * implementing a LIFO queue. 52 | * 53 | * A list is headed by a single forward pointer (or an array of forward 54 | * pointers for a hash table header). The elements are doubly linked 55 | * so that an arbitrary element can be removed without a need to 56 | * traverse the list. New elements can be added to the list before 57 | * or after an existing element or at the head of the list. A list 58 | * may only be traversed in the forward direction. 59 | * 60 | * A simple queue is headed by a pair of pointers, one the head of the 61 | * list and the other to the tail of the list. The elements are singly 62 | * linked to save space, so elements can only be removed from the 63 | * head of the list. New elements can be added to the list before or after 64 | * an existing element, at the head of the list, or at the end of the 65 | * list. A simple queue may only be traversed in the forward direction. 66 | * 67 | * A tail queue is headed by a pair of pointers, one to the head of the 68 | * list and the other to the tail of the list. The elements are doubly 69 | * linked so that an arbitrary element can be removed without a need to 70 | * traverse the list. New elements can be added to the list before or 71 | * after an existing element, at the head of the list, or at the end of 72 | * the list. A tail queue may be traversed in either direction. 73 | * 74 | * A circle queue is headed by a pair of pointers, one to the head of the 75 | * list and the other to the tail of the list. The elements are doubly 76 | * linked so that an arbitrary element can be removed without a need to 77 | * traverse the list. New elements can be added to the list before or after 78 | * an existing element, at the head of the list, or at the end of the list. 79 | * A circle queue may be traversed in either direction, but has a more 80 | * complex end of list detection. 81 | * 82 | * For details on the use of these macros, see the queue(3) manual page. 83 | */ 84 | 85 | #if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) 86 | #define _Q_INVALIDATE(a) (a) = ((void *)-1) 87 | #else 88 | #define _Q_INVALIDATE(a) 89 | #endif 90 | 91 | /* 92 | * Singly-linked List definitions. 93 | */ 94 | #define SLIST_HEAD(name, type) \ 95 | struct name { \ 96 | struct type *slh_first; /* first element */ \ 97 | } 98 | 99 | #define SLIST_HEAD_INITIALIZER(head) \ 100 | { NULL } 101 | 102 | #define SLIST_ENTRY(type) \ 103 | struct { \ 104 | struct type *sle_next; /* next element */ \ 105 | } 106 | 107 | /* 108 | * Singly-linked List access methods. 109 | */ 110 | #define SLIST_FIRST(head) ((head)->slh_first) 111 | #define SLIST_END(head) NULL 112 | #define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) 113 | #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) 114 | 115 | #define SLIST_FOREACH(var, head, field) \ 116 | for((var) = SLIST_FIRST(head); \ 117 | (var) != SLIST_END(head); \ 118 | (var) = SLIST_NEXT(var, field)) 119 | 120 | #define SLIST_FOREACH_SAFE(var, head, field, tvar) \ 121 | for ((var) = SLIST_FIRST(head); \ 122 | (var) && ((tvar) = SLIST_NEXT(var, field), 1); \ 123 | (var) = (tvar)) 124 | 125 | /* 126 | * Singly-linked List functions. 127 | */ 128 | #define SLIST_INIT(head) { \ 129 | SLIST_FIRST(head) = SLIST_END(head); \ 130 | } 131 | 132 | #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ 133 | (elm)->field.sle_next = (slistelm)->field.sle_next; \ 134 | (slistelm)->field.sle_next = (elm); \ 135 | } while (0) 136 | 137 | #define SLIST_INSERT_HEAD(head, elm, field) do { \ 138 | (elm)->field.sle_next = (head)->slh_first; \ 139 | (head)->slh_first = (elm); \ 140 | } while (0) 141 | 142 | #define SLIST_REMOVE_AFTER(elm, field) do { \ 143 | (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ 144 | } while (0) 145 | 146 | #define SLIST_REMOVE_HEAD(head, field) do { \ 147 | (head)->slh_first = (head)->slh_first->field.sle_next; \ 148 | } while (0) 149 | 150 | #define SLIST_REMOVE(head, elm, type, field) do { \ 151 | if ((head)->slh_first == (elm)) { \ 152 | SLIST_REMOVE_HEAD((head), field); \ 153 | } else { \ 154 | struct type *curelm = (head)->slh_first; \ 155 | \ 156 | while (curelm->field.sle_next != (elm)) \ 157 | curelm = curelm->field.sle_next; \ 158 | curelm->field.sle_next = \ 159 | curelm->field.sle_next->field.sle_next; \ 160 | _Q_INVALIDATE((elm)->field.sle_next); \ 161 | } \ 162 | } while (0) 163 | 164 | /* 165 | * List definitions. 166 | */ 167 | #define LIST_HEAD(name, type) \ 168 | struct name { \ 169 | struct type *lh_first; /* first element */ \ 170 | } 171 | 172 | #define LIST_HEAD_INITIALIZER(head) \ 173 | { NULL } 174 | 175 | #define LIST_ENTRY(type) \ 176 | struct { \ 177 | struct type *le_next; /* next element */ \ 178 | struct type **le_prev; /* address of previous next element */ \ 179 | } 180 | 181 | /* 182 | * List access methods 183 | */ 184 | #define LIST_FIRST(head) ((head)->lh_first) 185 | #define LIST_END(head) NULL 186 | #define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) 187 | #define LIST_NEXT(elm, field) ((elm)->field.le_next) 188 | 189 | #define LIST_FOREACH(var, head, field) \ 190 | for((var) = LIST_FIRST(head); \ 191 | (var)!= LIST_END(head); \ 192 | (var) = LIST_NEXT(var, field)) 193 | 194 | #define LIST_FOREACH_SAFE(var, head, field, tvar) \ 195 | for ((var) = LIST_FIRST(head); \ 196 | (var) && ((tvar) = LIST_NEXT(var, field), 1); \ 197 | (var) = (tvar)) 198 | 199 | /* 200 | * List functions. 201 | */ 202 | #define LIST_INIT(head) do { \ 203 | LIST_FIRST(head) = LIST_END(head); \ 204 | } while (0) 205 | 206 | #define LIST_INSERT_AFTER(listelm, elm, field) do { \ 207 | if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ 208 | (listelm)->field.le_next->field.le_prev = \ 209 | &(elm)->field.le_next; \ 210 | (listelm)->field.le_next = (elm); \ 211 | (elm)->field.le_prev = &(listelm)->field.le_next; \ 212 | } while (0) 213 | 214 | #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ 215 | (elm)->field.le_prev = (listelm)->field.le_prev; \ 216 | (elm)->field.le_next = (listelm); \ 217 | *(listelm)->field.le_prev = (elm); \ 218 | (listelm)->field.le_prev = &(elm)->field.le_next; \ 219 | } while (0) 220 | 221 | #define LIST_INSERT_HEAD(head, elm, field) do { \ 222 | if (((elm)->field.le_next = (head)->lh_first) != NULL) \ 223 | (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ 224 | (head)->lh_first = (elm); \ 225 | (elm)->field.le_prev = &(head)->lh_first; \ 226 | } while (0) 227 | 228 | #define LIST_REMOVE(elm, field) do { \ 229 | if ((elm)->field.le_next != NULL) \ 230 | (elm)->field.le_next->field.le_prev = \ 231 | (elm)->field.le_prev; \ 232 | *(elm)->field.le_prev = (elm)->field.le_next; \ 233 | _Q_INVALIDATE((elm)->field.le_prev); \ 234 | _Q_INVALIDATE((elm)->field.le_next); \ 235 | } while (0) 236 | 237 | #define LIST_REPLACE(elm, elm2, field) do { \ 238 | if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ 239 | (elm2)->field.le_next->field.le_prev = \ 240 | &(elm2)->field.le_next; \ 241 | (elm2)->field.le_prev = (elm)->field.le_prev; \ 242 | *(elm2)->field.le_prev = (elm2); \ 243 | _Q_INVALIDATE((elm)->field.le_prev); \ 244 | _Q_INVALIDATE((elm)->field.le_next); \ 245 | } while (0) 246 | 247 | /* 248 | * Simple queue definitions. 249 | */ 250 | #define SIMPLEQ_HEAD(name, type) \ 251 | struct name { \ 252 | struct type *sqh_first; /* first element */ \ 253 | struct type **sqh_last; /* addr of last next element */ \ 254 | } 255 | 256 | #define SIMPLEQ_HEAD_INITIALIZER(head) \ 257 | { NULL, &(head).sqh_first } 258 | 259 | #define SIMPLEQ_ENTRY(type) \ 260 | struct { \ 261 | struct type *sqe_next; /* next element */ \ 262 | } 263 | 264 | /* 265 | * Simple queue access methods. 266 | */ 267 | #define SIMPLEQ_FIRST(head) ((head)->sqh_first) 268 | #define SIMPLEQ_END(head) NULL 269 | #define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) 270 | #define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) 271 | 272 | #define SIMPLEQ_FOREACH(var, head, field) \ 273 | for((var) = SIMPLEQ_FIRST(head); \ 274 | (var) != SIMPLEQ_END(head); \ 275 | (var) = SIMPLEQ_NEXT(var, field)) 276 | 277 | #define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \ 278 | for ((var) = SIMPLEQ_FIRST(head); \ 279 | (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \ 280 | (var) = (tvar)) 281 | 282 | /* 283 | * Simple queue functions. 284 | */ 285 | #define SIMPLEQ_INIT(head) do { \ 286 | (head)->sqh_first = NULL; \ 287 | (head)->sqh_last = &(head)->sqh_first; \ 288 | } while (0) 289 | 290 | #define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ 291 | if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ 292 | (head)->sqh_last = &(elm)->field.sqe_next; \ 293 | (head)->sqh_first = (elm); \ 294 | } while (0) 295 | 296 | #define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ 297 | (elm)->field.sqe_next = NULL; \ 298 | *(head)->sqh_last = (elm); \ 299 | (head)->sqh_last = &(elm)->field.sqe_next; \ 300 | } while (0) 301 | 302 | #define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ 303 | if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ 304 | (head)->sqh_last = &(elm)->field.sqe_next; \ 305 | (listelm)->field.sqe_next = (elm); \ 306 | } while (0) 307 | 308 | #define SIMPLEQ_REMOVE_HEAD(head, field) do { \ 309 | if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ 310 | (head)->sqh_last = &(head)->sqh_first; \ 311 | } while (0) 312 | 313 | #define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ 314 | if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \ 315 | == NULL) \ 316 | (head)->sqh_last = &(elm)->field.sqe_next; \ 317 | } while (0) 318 | 319 | /* 320 | * XOR Simple queue definitions. 321 | */ 322 | #define XSIMPLEQ_HEAD(name, type) \ 323 | struct name { \ 324 | struct type *sqx_first; /* first element */ \ 325 | struct type **sqx_last; /* addr of last next element */ \ 326 | unsigned long sqx_cookie; \ 327 | } 328 | 329 | #define XSIMPLEQ_ENTRY(type) \ 330 | struct { \ 331 | struct type *sqx_next; /* next element */ \ 332 | } 333 | 334 | /* 335 | * XOR Simple queue access methods. 336 | */ 337 | #define XSIMPLEQ_XOR(head, ptr) ((__typeof(ptr))((head)->sqx_cookie ^ \ 338 | (unsigned long)(ptr))) 339 | #define XSIMPLEQ_FIRST(head) XSIMPLEQ_XOR(head, ((head)->sqx_first)) 340 | #define XSIMPLEQ_END(head) NULL 341 | #define XSIMPLEQ_EMPTY(head) (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head)) 342 | #define XSIMPLEQ_NEXT(head, elm, field) XSIMPLEQ_XOR(head, ((elm)->field.sqx_next)) 343 | 344 | 345 | #define XSIMPLEQ_FOREACH(var, head, field) \ 346 | for ((var) = XSIMPLEQ_FIRST(head); \ 347 | (var) != XSIMPLEQ_END(head); \ 348 | (var) = XSIMPLEQ_NEXT(head, var, field)) 349 | 350 | #define XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \ 351 | for ((var) = XSIMPLEQ_FIRST(head); \ 352 | (var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1); \ 353 | (var) = (tvar)) 354 | 355 | /* 356 | * XOR Simple queue functions. 357 | */ 358 | #define XSIMPLEQ_INIT(head) do { \ 359 | arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \ 360 | (head)->sqx_first = XSIMPLEQ_XOR(head, NULL); \ 361 | (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \ 362 | } while (0) 363 | 364 | #define XSIMPLEQ_INSERT_HEAD(head, elm, field) do { \ 365 | if (((elm)->field.sqx_next = (head)->sqx_first) == \ 366 | XSIMPLEQ_XOR(head, NULL)) \ 367 | (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \ 368 | (head)->sqx_first = XSIMPLEQ_XOR(head, (elm)); \ 369 | } while (0) 370 | 371 | #define XSIMPLEQ_INSERT_TAIL(head, elm, field) do { \ 372 | (elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL); \ 373 | *(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \ 374 | (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \ 375 | } while (0) 376 | 377 | #define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ 378 | if (((elm)->field.sqx_next = (listelm)->field.sqx_next) == \ 379 | XSIMPLEQ_XOR(head, NULL)) \ 380 | (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \ 381 | (listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm)); \ 382 | } while (0) 383 | 384 | #define XSIMPLEQ_REMOVE_HEAD(head, field) do { \ 385 | if (((head)->sqx_first = XSIMPLEQ_XOR(head, \ 386 | (head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \ 387 | (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \ 388 | } while (0) 389 | 390 | #define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ 391 | if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head, \ 392 | (elm)->field.sqx_next)->field.sqx_next) \ 393 | == XSIMPLEQ_XOR(head, NULL)) \ 394 | (head)->sqx_last = \ 395 | XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \ 396 | } while (0) 397 | 398 | 399 | /* 400 | * Tail queue definitions. 401 | */ 402 | #define TAILQ_HEAD(name, type) \ 403 | struct name { \ 404 | struct type *tqh_first; /* first element */ \ 405 | struct type **tqh_last; /* addr of last next element */ \ 406 | } 407 | 408 | #define TAILQ_HEAD_INITIALIZER(head) \ 409 | { NULL, &(head).tqh_first } 410 | 411 | #define TAILQ_ENTRY(type) \ 412 | struct { \ 413 | struct type *tqe_next; /* next element */ \ 414 | struct type **tqe_prev; /* address of previous next element */ \ 415 | } 416 | 417 | /* 418 | * tail queue access methods 419 | */ 420 | #define TAILQ_FIRST(head) ((head)->tqh_first) 421 | #define TAILQ_END(head) NULL 422 | #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) 423 | #define TAILQ_LAST(head, headname) \ 424 | (*(((struct headname *)((head)->tqh_last))->tqh_last)) 425 | /* XXX */ 426 | #define TAILQ_PREV(elm, headname, field) \ 427 | (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) 428 | #define TAILQ_EMPTY(head) \ 429 | (TAILQ_FIRST(head) == TAILQ_END(head)) 430 | 431 | #define TAILQ_FOREACH(var, head, field) \ 432 | for((var) = TAILQ_FIRST(head); \ 433 | (var) != TAILQ_END(head); \ 434 | (var) = TAILQ_NEXT(var, field)) 435 | 436 | #define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ 437 | for ((var) = TAILQ_FIRST(head); \ 438 | (var) != TAILQ_END(head) && \ 439 | ((tvar) = TAILQ_NEXT(var, field), 1); \ 440 | (var) = (tvar)) 441 | 442 | 443 | #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ 444 | for((var) = TAILQ_LAST(head, headname); \ 445 | (var) != TAILQ_END(head); \ 446 | (var) = TAILQ_PREV(var, headname, field)) 447 | 448 | #define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ 449 | for ((var) = TAILQ_LAST(head, headname); \ 450 | (var) != TAILQ_END(head) && \ 451 | ((tvar) = TAILQ_PREV(var, headname, field), 1); \ 452 | (var) = (tvar)) 453 | 454 | /* 455 | * Tail queue functions. 456 | */ 457 | #define TAILQ_INIT(head) do { \ 458 | (head)->tqh_first = NULL; \ 459 | (head)->tqh_last = &(head)->tqh_first; \ 460 | } while (0) 461 | 462 | #define TAILQ_INSERT_HEAD(head, elm, field) do { \ 463 | if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ 464 | (head)->tqh_first->field.tqe_prev = \ 465 | &(elm)->field.tqe_next; \ 466 | else \ 467 | (head)->tqh_last = &(elm)->field.tqe_next; \ 468 | (head)->tqh_first = (elm); \ 469 | (elm)->field.tqe_prev = &(head)->tqh_first; \ 470 | } while (0) 471 | 472 | #define TAILQ_INSERT_TAIL(head, elm, field) do { \ 473 | (elm)->field.tqe_next = NULL; \ 474 | (elm)->field.tqe_prev = (head)->tqh_last; \ 475 | *(head)->tqh_last = (elm); \ 476 | (head)->tqh_last = &(elm)->field.tqe_next; \ 477 | } while (0) 478 | 479 | #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ 480 | if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ 481 | (elm)->field.tqe_next->field.tqe_prev = \ 482 | &(elm)->field.tqe_next; \ 483 | else \ 484 | (head)->tqh_last = &(elm)->field.tqe_next; \ 485 | (listelm)->field.tqe_next = (elm); \ 486 | (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ 487 | } while (0) 488 | 489 | #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ 490 | (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ 491 | (elm)->field.tqe_next = (listelm); \ 492 | *(listelm)->field.tqe_prev = (elm); \ 493 | (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ 494 | } while (0) 495 | 496 | #define TAILQ_REMOVE(head, elm, field) do { \ 497 | if (((elm)->field.tqe_next) != NULL) \ 498 | (elm)->field.tqe_next->field.tqe_prev = \ 499 | (elm)->field.tqe_prev; \ 500 | else \ 501 | (head)->tqh_last = (elm)->field.tqe_prev; \ 502 | *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ 503 | _Q_INVALIDATE((elm)->field.tqe_prev); \ 504 | _Q_INVALIDATE((elm)->field.tqe_next); \ 505 | } while (0) 506 | 507 | #define TAILQ_REPLACE(head, elm, elm2, field) do { \ 508 | if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ 509 | (elm2)->field.tqe_next->field.tqe_prev = \ 510 | &(elm2)->field.tqe_next; \ 511 | else \ 512 | (head)->tqh_last = &(elm2)->field.tqe_next; \ 513 | (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ 514 | *(elm2)->field.tqe_prev = (elm2); \ 515 | _Q_INVALIDATE((elm)->field.tqe_prev); \ 516 | _Q_INVALIDATE((elm)->field.tqe_next); \ 517 | } while (0) 518 | 519 | /* 520 | * Circular queue definitions. 521 | */ 522 | #define CIRCLEQ_HEAD(name, type) \ 523 | struct name { \ 524 | struct type *cqh_first; /* first element */ \ 525 | struct type *cqh_last; /* last element */ \ 526 | } 527 | 528 | #define CIRCLEQ_HEAD_INITIALIZER(head) \ 529 | { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } 530 | 531 | #define CIRCLEQ_ENTRY(type) \ 532 | struct { \ 533 | struct type *cqe_next; /* next element */ \ 534 | struct type *cqe_prev; /* previous element */ \ 535 | } 536 | 537 | /* 538 | * Circular queue access methods 539 | */ 540 | #define CIRCLEQ_FIRST(head) ((head)->cqh_first) 541 | #define CIRCLEQ_LAST(head) ((head)->cqh_last) 542 | #define CIRCLEQ_END(head) ((void *)(head)) 543 | #define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) 544 | #define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) 545 | #define CIRCLEQ_EMPTY(head) \ 546 | (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) 547 | 548 | #define CIRCLEQ_FOREACH(var, head, field) \ 549 | for((var) = CIRCLEQ_FIRST(head); \ 550 | (var) != CIRCLEQ_END(head); \ 551 | (var) = CIRCLEQ_NEXT(var, field)) 552 | 553 | #define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \ 554 | for ((var) = CIRCLEQ_FIRST(head); \ 555 | (var) != CIRCLEQ_END(head) && \ 556 | ((tvar) = CIRCLEQ_NEXT(var, field), 1); \ 557 | (var) = (tvar)) 558 | 559 | #define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ 560 | for((var) = CIRCLEQ_LAST(head); \ 561 | (var) != CIRCLEQ_END(head); \ 562 | (var) = CIRCLEQ_PREV(var, field)) 563 | 564 | #define CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ 565 | for ((var) = CIRCLEQ_LAST(head, headname); \ 566 | (var) != CIRCLEQ_END(head) && \ 567 | ((tvar) = CIRCLEQ_PREV(var, headname, field), 1); \ 568 | (var) = (tvar)) 569 | 570 | /* 571 | * Circular queue functions. 572 | */ 573 | #define CIRCLEQ_INIT(head) do { \ 574 | (head)->cqh_first = CIRCLEQ_END(head); \ 575 | (head)->cqh_last = CIRCLEQ_END(head); \ 576 | } while (0) 577 | 578 | #define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ 579 | (elm)->field.cqe_next = (listelm)->field.cqe_next; \ 580 | (elm)->field.cqe_prev = (listelm); \ 581 | if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ 582 | (head)->cqh_last = (elm); \ 583 | else \ 584 | (listelm)->field.cqe_next->field.cqe_prev = (elm); \ 585 | (listelm)->field.cqe_next = (elm); \ 586 | } while (0) 587 | 588 | #define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ 589 | (elm)->field.cqe_next = (listelm); \ 590 | (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ 591 | if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ 592 | (head)->cqh_first = (elm); \ 593 | else \ 594 | (listelm)->field.cqe_prev->field.cqe_next = (elm); \ 595 | (listelm)->field.cqe_prev = (elm); \ 596 | } while (0) 597 | 598 | #define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ 599 | (elm)->field.cqe_next = (head)->cqh_first; \ 600 | (elm)->field.cqe_prev = CIRCLEQ_END(head); \ 601 | if ((head)->cqh_last == CIRCLEQ_END(head)) \ 602 | (head)->cqh_last = (elm); \ 603 | else \ 604 | (head)->cqh_first->field.cqe_prev = (elm); \ 605 | (head)->cqh_first = (elm); \ 606 | } while (0) 607 | 608 | #define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ 609 | (elm)->field.cqe_next = CIRCLEQ_END(head); \ 610 | (elm)->field.cqe_prev = (head)->cqh_last; \ 611 | if ((head)->cqh_first == CIRCLEQ_END(head)) \ 612 | (head)->cqh_first = (elm); \ 613 | else \ 614 | (head)->cqh_last->field.cqe_next = (elm); \ 615 | (head)->cqh_last = (elm); \ 616 | } while (0) 617 | 618 | #define CIRCLEQ_REMOVE(head, elm, field) do { \ 619 | if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ 620 | (head)->cqh_last = (elm)->field.cqe_prev; \ 621 | else \ 622 | (elm)->field.cqe_next->field.cqe_prev = \ 623 | (elm)->field.cqe_prev; \ 624 | if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ 625 | (head)->cqh_first = (elm)->field.cqe_next; \ 626 | else \ 627 | (elm)->field.cqe_prev->field.cqe_next = \ 628 | (elm)->field.cqe_next; \ 629 | _Q_INVALIDATE((elm)->field.cqe_prev); \ 630 | _Q_INVALIDATE((elm)->field.cqe_next); \ 631 | } while (0) 632 | 633 | #define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ 634 | if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ 635 | CIRCLEQ_END(head)) \ 636 | (head)->cqh_last = (elm2); \ 637 | else \ 638 | (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ 639 | if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ 640 | CIRCLEQ_END(head)) \ 641 | (head)->cqh_first = (elm2); \ 642 | else \ 643 | (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ 644 | _Q_INVALIDATE((elm)->field.cqe_prev); \ 645 | _Q_INVALIDATE((elm)->field.cqe_next); \ 646 | } while (0) 647 | 648 | #endif /* !_SYS_QUEUE_H_ */ 649 | -------------------------------------------------------------------------------- /readahead.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt READAHEAD 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm preload 6 | .Nd preload files into disk cache 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Ar file... 10 | .Sh DESCRIPTION 11 | .Nm 12 | preloads files into the kernel's disk cache. The number of pages preloaded 13 | depends on the kernel but it is usually around 2MB. 14 | .Sh SEE ALSO 15 | .Xr readahead 2 16 | -------------------------------------------------------------------------------- /readahead.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "util.h" 8 | 9 | static void 10 | usage(void) 11 | { 12 | eprintf("usage: %s file...\n", argv0); 13 | } 14 | 15 | int 16 | main(int argc, char *argv[]) 17 | { 18 | FILE *fp; 19 | 20 | ARGBEGIN { 21 | default: 22 | usage(); 23 | } ARGEND; 24 | 25 | if (argc == 0) 26 | usage(); 27 | 28 | for (; argc > 0; argc--, argv++) { 29 | if (!(fp = fopen(argv[0], "r"))) { 30 | weprintf("fopen %s:", argv[0]); 31 | continue; 32 | } 33 | if (readahead(fileno(fp), 0, -1) < 0) 34 | weprintf("readahead %s:", argv[0]); 35 | fclose(fp); 36 | } 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /reboot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Magic values required to use _reboot() system call. 3 | */ 4 | 5 | #define LINUX_REBOOT_MAGIC1 0xfee1dead 6 | #define LINUX_REBOOT_MAGIC2 672274793 7 | #define LINUX_REBOOT_MAGIC2A 85072278 8 | #define LINUX_REBOOT_MAGIC2B 369367448 9 | #define LINUX_REBOOT_MAGIC2C 537993216 10 | 11 | 12 | /* 13 | * Commands accepted by the _reboot() system call. 14 | * 15 | * RESTART Restart system using default command and mode. 16 | * HALT Stop OS and give system control to ROM monitor, if any. 17 | * CAD_ON Ctrl-Alt-Del sequence causes RESTART command. 18 | * CAD_OFF Ctrl-Alt-Del sequence sends SIGINT to init task. 19 | * POWER_OFF Stop OS and remove all power from system, if possible. 20 | * RESTART2 Restart system using given command string. 21 | * SW_SUSPEND Suspend system using software suspend if compiled in. 22 | * KEXEC Restart system using a previously loaded Linux kernel 23 | */ 24 | 25 | #define LINUX_REBOOT_CMD_RESTART 0x01234567 26 | #define LINUX_REBOOT_CMD_HALT 0xCDEF0123 27 | #define LINUX_REBOOT_CMD_CAD_ON 0x89ABCDEF 28 | #define LINUX_REBOOT_CMD_CAD_OFF 0x00000000 29 | #define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC 30 | #define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4 31 | #define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2 32 | #define LINUX_REBOOT_CMD_KEXEC 0x45584543 33 | -------------------------------------------------------------------------------- /respawn.1: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt RESPAWN 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm respawn 6 | .Nd spawn the given command repeatedly 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl l Ar fifo 10 | .Op Fl d Ar N 11 | .Ar cmd Op Ar args... 12 | .Sh DESCRIPTION 13 | .Nm 14 | spawns the given 15 | .Ar cmd 16 | in a new session repeatedly. 17 | .Sh OPTIONS 18 | .Bl -tag -width Ds 19 | .It Fl d 20 | Set the delay between invocations of \fIcmd\fR. It defaults to 0. 21 | .It Fl l 22 | Listen on the specified 23 | .Ar fifo 24 | for writes. For each write spawn a new instance of 25 | .Ar cmd . 26 | This can be used in conjunction with a process supervisor to restart a 27 | particular program. The 28 | .Fl l 29 | and 30 | .Fl d 31 | options are incompatible. All writes are discarded. 32 | .El -------------------------------------------------------------------------------- /respawn.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "util.h" 16 | 17 | static void 18 | sigterm(int sig) 19 | { 20 | if (sig == SIGTERM) { 21 | kill(0, SIGTERM); 22 | _exit(0); 23 | } 24 | } 25 | 26 | static void 27 | usage(void) 28 | { 29 | eprintf("usage: %s [-l fifo] [-d N] cmd [args...]\n", argv0); 30 | } 31 | 32 | int 33 | main(int argc, char *argv[]) 34 | { 35 | char *fifo = NULL; 36 | unsigned int delay = 0; 37 | pid_t pid; 38 | char buf[BUFSIZ]; 39 | int savederrno; 40 | ssize_t n; 41 | struct pollfd pollset[1]; 42 | int polln; 43 | 44 | ARGBEGIN { 45 | case 'd': 46 | delay = estrtol(EARGF(usage()), 0); 47 | break; 48 | case 'l': 49 | fifo = EARGF(usage()); 50 | break; 51 | default: 52 | usage(); 53 | } ARGEND; 54 | 55 | if (argc < 1) 56 | usage(); 57 | 58 | if (fifo && delay > 0) 59 | usage(); 60 | 61 | setsid(); 62 | 63 | signal(SIGTERM, sigterm); 64 | 65 | if (fifo) { 66 | pollset->fd = open(fifo, O_RDONLY | O_NONBLOCK); 67 | if (pollset->fd < 0) 68 | eprintf("open %s:", fifo); 69 | pollset->events = POLLIN; 70 | } 71 | 72 | while (1) { 73 | if (fifo) { 74 | pollset->revents = 0; 75 | polln = poll(pollset, 1, -1); 76 | if (polln <= 0) { 77 | if (polln == 0 || errno == EAGAIN) 78 | continue; 79 | eprintf("poll:"); 80 | } 81 | while ((n = read(pollset->fd, buf, sizeof(buf))) > 0) 82 | ; 83 | if (n < 0) 84 | if (errno != EAGAIN) 85 | eprintf("read %s:", fifo); 86 | if (n == 0) { 87 | close(pollset->fd); 88 | pollset->fd = open(fifo, O_RDONLY | O_NONBLOCK); 89 | if (pollset->fd < 0) 90 | eprintf("open %s:", fifo); 91 | pollset->events = POLLIN; 92 | } 93 | } 94 | pid = fork(); 95 | if (pid < 0) 96 | eprintf("fork:"); 97 | switch (pid) { 98 | case 0: 99 | execvp(argv[0], argv); 100 | savederrno = errno; 101 | weprintf("execvp %s:", argv[0]); 102 | _exit(savederrno == ENOENT ? 127 : 126); 103 | break; 104 | default: 105 | waitpid(pid, NULL, 0); 106 | break; 107 | } 108 | if (!fifo) 109 | sleep(delay); 110 | } 111 | /* not reachable */ 112 | return 0; 113 | } 114 | -------------------------------------------------------------------------------- /rmmod.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt RMMOD 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm rmmod 6 | .Nd remove a module from the Linux kernel 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl fw 10 | .Ar module... 11 | .Sh DESCRIPTION 12 | .Nm 13 | removes one or more modules from the kernel. 14 | .Sh OPTIONS 15 | .Bl -tag -width Ds 16 | .It Fl f 17 | This option can be extremely dangerous: it has no effect unless 18 | CONFIG_MODULE_FORCE_UNLOAD was set when the kernel was compiled. 19 | With this option, you can remove modules which are being used, or 20 | which are not designed to be removed, or have been marked as unsafe. 21 | .It Fl w 22 | Normally, 23 | .Nm 24 | will refuse to unload modules which are in 25 | use. With this option, 26 | .Nm 27 | will isolate the module, and wait until the module is no longer used. Noone 28 | new will be able to use the module, but it's up to you to make sure the 29 | current users eventually finish with it. 30 | .El 31 | .Sh SEE ALSO 32 | .Xr insmod 8 , 33 | .Xr lsmod 8 -------------------------------------------------------------------------------- /rmmod.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "util.h" 12 | 13 | static void 14 | usage(void) 15 | { 16 | eprintf("usage: %s [-fw] module...\n", argv0); 17 | } 18 | 19 | int 20 | main(int argc, char *argv[]) 21 | { 22 | char *mod, *p; 23 | int i; 24 | int flags = O_NONBLOCK; 25 | 26 | ARGBEGIN { 27 | case 'f': 28 | flags |= O_TRUNC; 29 | break; 30 | case 'w': 31 | flags &= ~O_NONBLOCK; 32 | break; 33 | default: 34 | usage(); 35 | } ARGEND; 36 | 37 | if (argc < 1) 38 | usage(); 39 | 40 | for (i = 0; i < argc; i++) { 41 | mod = argv[i]; 42 | p = strrchr(mod, '.'); 43 | if (p && !strcmp(p, ".ko")) 44 | *p = '\0'; 45 | if (syscall(__NR_delete_module, mod, flags) < 0) 46 | eprintf("delete_module:"); 47 | } 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /rtc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The struct used to pass data via the following ioctl. Similar to the 3 | * struct tm in , but it needs to be here so that the kernel 4 | * source is self contained, allowing cross-compiles, etc. etc. 5 | */ 6 | 7 | struct rtc_time { 8 | int tm_sec; 9 | int tm_min; 10 | int tm_hour; 11 | int tm_mday; 12 | int tm_mon; 13 | int tm_year; 14 | int tm_wday; 15 | int tm_yday; 16 | int tm_isdst; 17 | }; 18 | 19 | #define RTC_RD_TIME _IOR('p', 0x09, struct rtc_time) /* Read RTC time */ 20 | #define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time) /* Set RTC time */ 21 | -------------------------------------------------------------------------------- /stat.1: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt STAT 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm stat 6 | .Nd display file status 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl L 10 | .Op Ar file... 11 | .Sh DESCRIPTION 12 | .Nm 13 | displays information about the given 14 | .Ar files 15 | or stdin if no 16 | .Ar files 17 | are specified. 18 | .Sh OPTIONS 19 | .Bl -tag -width Ds 20 | .It Fl L 21 | Follow links. 22 | .El 23 | .Sh SEE ALSO 24 | .Xr stat 2 25 | -------------------------------------------------------------------------------- /stat.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #ifndef major 5 | #include 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "util.h" 15 | 16 | static void 17 | show_stat_terse(const char *file, struct stat *st) 18 | { 19 | printf("%s ", file); 20 | printf("%lu %lu ", (unsigned long)st->st_size, 21 | (unsigned long)st->st_blocks); 22 | printf("%04o %u %u ", st->st_mode & 0777, st->st_uid, st->st_gid); 23 | printf("%llx ", (unsigned long long)st->st_dev); 24 | printf("%lu %lu ", (unsigned long)st->st_ino, (unsigned long)st->st_nlink); 25 | printf("%d %d ", major(st->st_rdev), minor(st->st_rdev)); 26 | printf("%ld %ld %ld ", st->st_atime, st->st_mtime, st->st_ctime); 27 | printf("%lu\n", (unsigned long)st->st_blksize); 28 | } 29 | 30 | static void 31 | show_stat(const char *file, struct stat *st) 32 | { 33 | char buf[100]; 34 | 35 | printf(" File: ‘%s’\n", file); 36 | printf(" Size: %lu\tBlocks: %lu\tIO Block: %lu\n", (unsigned long)st->st_size, 37 | (unsigned long)st->st_blocks, (unsigned long)st->st_blksize); 38 | printf("Device: %xh/%ud\tInode: %lu\tLinks %lu\n", major(st->st_dev), 39 | minor(st->st_dev), (unsigned long)st->st_ino, (unsigned long)st->st_nlink); 40 | printf("Access: %04o\tUid: %u\tGid: %u\n", st->st_mode & 0777, st->st_uid, st->st_gid); 41 | strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&st->st_atime)); 42 | printf("Access: %s\n", buf); 43 | strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&st->st_mtime)); 44 | printf("Modify: %s\n", buf); 45 | strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&st->st_ctime)); 46 | printf("Change: %s\n", buf); 47 | } 48 | 49 | static void 50 | usage(void) 51 | { 52 | eprintf("usage: %s [-L] [-t] [file...]\n", argv0); 53 | } 54 | 55 | int 56 | main(int argc, char *argv[]) 57 | { 58 | struct stat st; 59 | int i, ret = 0; 60 | int (*fn)(const char *, struct stat *) = lstat; 61 | char *fnname = "lstat"; 62 | void (*showstat)(const char *, struct stat *) = show_stat; 63 | 64 | ARGBEGIN { 65 | case 'L': 66 | fn = stat; 67 | fnname = "stat"; 68 | break; 69 | case 't': 70 | showstat = show_stat_terse; 71 | break; 72 | default: 73 | usage(); 74 | } ARGEND; 75 | 76 | if (argc == 0) { 77 | if (fstat(0, &st) < 0) 78 | eprintf("stat :"); 79 | show_stat("", &st); 80 | } 81 | 82 | for (i = 0; i < argc; i++) { 83 | if (fn(argv[i], &st) == -1) { 84 | weprintf("%s %s:", fnname, argv[i]); 85 | ret = 1; 86 | continue; 87 | } 88 | showstat(argv[i], &st); 89 | } 90 | 91 | return ret; 92 | } -------------------------------------------------------------------------------- /su.1: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt SU 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm su 6 | .Nd run a command with a substitute user and group ID 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl lp 10 | .Op Ar username 11 | .Sh DESCRIPTION 12 | .Nm 13 | allows to run commands with a substitute user and group ID. When called 14 | without arguments, 15 | .Nm 16 | defaults to running an interactive shell as root. For backward compatibility 17 | .Nm 18 | defaults to not change the current directory and to only set the environment 19 | variables 20 | .Ev HOME 21 | and 22 | .Ev SHELL 23 | (plus 24 | .Ev USER 25 | and 26 | .Ev LOGNAME 27 | if the target 28 | .Ar username 29 | is not root). 30 | .Sh OPTIONS 31 | .Bl -tag -width Ds 32 | .It Fl l 33 | Starts the shell as login shell with an environment similar to a real 34 | login. 35 | .It Fl p 36 | Preserves the whole environment. This option is ignored if the 37 | .Fl l 38 | option is specified. 39 | .El -------------------------------------------------------------------------------- /su.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "config.h" 13 | #include "passwd.h" 14 | #include "util.h" 15 | 16 | extern char **environ; 17 | 18 | static int lflag = 0; 19 | static int pflag = 0; 20 | 21 | static int 22 | dologin(struct passwd *pw) 23 | { 24 | char *shell = pw->pw_shell[0] == '\0' ? "/bin/sh" : pw->pw_shell; 25 | char *term = getenv("TERM"); 26 | clearenv(); 27 | setenv("HOME", pw->pw_dir, 1); 28 | setenv("SHELL", shell, 1); 29 | setenv("USER", pw->pw_name, 1); 30 | setenv("LOGNAME", pw->pw_name, 1); 31 | setenv("TERM", term ? term : "linux", 1); 32 | if (strcmp(pw->pw_name, "root") == 0) 33 | setenv("PATH", ENV_SUPATH, 1); 34 | else 35 | setenv("PATH", ENV_PATH, 1); 36 | if (chdir(pw->pw_dir) < 0) 37 | eprintf("chdir %s:", pw->pw_dir); 38 | execlp(shell, shell, "-l", NULL); 39 | weprintf("execlp %s:", shell); 40 | return (errno == ENOENT) ? 127 : 126; 41 | } 42 | 43 | static void 44 | usage(void) 45 | { 46 | eprintf("usage: %s [-lp] [username]\n", argv0); 47 | } 48 | 49 | int 50 | main(int argc, char *argv[]) 51 | { 52 | char *usr = "root", *pass; 53 | char *shell; 54 | struct passwd *pw; 55 | char *newargv[2]; 56 | uid_t uid; 57 | 58 | ARGBEGIN { 59 | case 'l': 60 | lflag = 1; 61 | break; 62 | case 'p': 63 | pflag = 1; 64 | break; 65 | default: 66 | usage(); 67 | } ARGEND; 68 | 69 | if (argc < 1) 70 | ; 71 | else if (argc == 1) 72 | usr = argv[0]; 73 | else 74 | usage(); 75 | 76 | errno = 0; 77 | pw = getpwnam(usr); 78 | if (!pw) { 79 | if (errno) 80 | eprintf("getpwnam: %s:", usr); 81 | else 82 | eprintf("who are you?\n"); 83 | } 84 | 85 | uid = getuid(); 86 | if (uid) { 87 | pass = getpass("Password: "); 88 | if (!pass) 89 | eprintf("getpass:"); 90 | if (pw_check(pw, pass) <= 0) 91 | exit(1); 92 | } 93 | 94 | if (initgroups(usr, pw->pw_gid) < 0) 95 | eprintf("initgroups:"); 96 | if (setgid(pw->pw_gid) < 0) 97 | eprintf("setgid:"); 98 | if (setuid(pw->pw_uid) < 0) 99 | eprintf("setuid:"); 100 | 101 | if (lflag) { 102 | return dologin(pw); 103 | } else { 104 | shell = pw->pw_shell[0] == '\0' ? "/bin/sh" : pw->pw_shell; 105 | newargv[0] = shell; 106 | newargv[1] = NULL; 107 | if (!pflag) { 108 | setenv("HOME", pw->pw_dir, 1); 109 | setenv("SHELL", shell, 1); 110 | if (strcmp(pw->pw_name, "root") != 0) { 111 | setenv("USER", pw->pw_name, 1); 112 | setenv("LOGNAME", pw->pw_name, 1); 113 | } 114 | } 115 | if (strcmp(pw->pw_name, "root") == 0) 116 | setenv("PATH", ENV_SUPATH, 1); 117 | else 118 | setenv("PATH", ENV_PATH, 1); 119 | execve(pflag ? getenv("SHELL") : shell, 120 | newargv, environ); 121 | weprintf("execve %s:", shell); 122 | return (errno == ENOENT) ? 127 : 126; 123 | } 124 | return 0; 125 | } -------------------------------------------------------------------------------- /swaplabel.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt SWAPLABEL 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm swaplabel 6 | .Nd set the label of a swap filesystem 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl L Ar label 10 | .Ar device 11 | .Sh DESCRIPTION 12 | .Nm 13 | is used to change the label of a swap device or file. 14 | .Sh OPTIONS 15 | .Bl -tag -width Ds 16 | .It Fl L Ar label 17 | Change the label. 18 | .El 19 | -------------------------------------------------------------------------------- /swaplabel.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "util.h" 11 | 12 | #define SWAP_MAGIC1 "SWAPSPACE2" 13 | #define SWAP_MAGIC2 "SWAP-SPACE" 14 | #define SWAP_MAGIC_LENGTH (10) 15 | #define SWAP_MAGIC_OFFSET (sysconf(_SC_PAGESIZE) - SWAP_MAGIC_LENGTH) 16 | #define SWAP_LABEL_LENGTH (16) 17 | #define SWAP_LABEL_OFFSET (1024 + 4 + 4 + 4 + 16) 18 | 19 | static void 20 | usage(void) 21 | { 22 | eprintf("usage: %s [-L label] device\n", argv0); 23 | } 24 | 25 | int 26 | main(int argc, char *argv[]) 27 | { 28 | int setlabel = 0; 29 | int fd; 30 | char magic[SWAP_MAGIC_LENGTH]; 31 | char *label; 32 | char *device; 33 | int i; 34 | 35 | ARGBEGIN { 36 | case 'L': 37 | setlabel = 1; 38 | label = EARGF(usage()); 39 | break; 40 | default: 41 | usage(); 42 | } ARGEND; 43 | 44 | if (argc < 1) 45 | usage(); 46 | device = argv[0]; 47 | 48 | fd = open(device, O_RDWR); 49 | if (fd < 0) 50 | eprintf("open %s:", device); 51 | 52 | if (lseek(fd, SWAP_MAGIC_OFFSET, SEEK_SET) != SWAP_MAGIC_OFFSET) 53 | eprintf("failed seeking to magic position:"); 54 | if (read(fd, magic, SWAP_MAGIC_LENGTH) != SWAP_MAGIC_LENGTH) 55 | eprintf("reading magic failed:"); 56 | if (memcmp(magic, SWAP_MAGIC1, 10) && memcmp(magic, SWAP_MAGIC2, 10)) 57 | eprintf("%s: is not a swap partition\n", device); 58 | if (lseek(fd, SWAP_LABEL_OFFSET, SEEK_SET) != SWAP_LABEL_OFFSET) 59 | eprintf("failed seeking to label position:"); 60 | 61 | if (!setlabel) { 62 | label = emalloc(SWAP_LABEL_LENGTH); 63 | if (read(fd, label, SWAP_LABEL_LENGTH) != SWAP_LABEL_LENGTH) 64 | eprintf("reading label failed:"); 65 | for (i = 0; i < SWAP_LABEL_LENGTH && label[i] != '\0'; i++) 66 | if (i == (SWAP_LABEL_LENGTH - 1) && label[i] != '\0') 67 | eprintf("invalid label\n"); 68 | printf("label: %s\n", label); 69 | free(label); 70 | } else { 71 | if (strlen(label) + 1 > SWAP_LABEL_LENGTH) 72 | eprintf("label too long\n"); 73 | if (write(fd, label, strlen(label) + 1) != (ssize_t)strlen(label) + 1) 74 | eprintf("writing label failed:"); 75 | } 76 | 77 | fsync(fd); 78 | close(fd); 79 | return 0; 80 | } 81 | -------------------------------------------------------------------------------- /swapoff.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt SWAPOFF 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm swapoff 6 | .Nd disable devices and files for paging and swapping 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Fl a | Ar device 10 | .Sh DESCRIPTION 11 | .Nm 12 | disables swapping on the specified devices and files. 13 | .Sh OPTIONS 14 | .Bl -tag -width Ds 15 | .It Fl a 16 | Disable swapping on all known swap devices and files as found in /etc/fstab. 17 | .El 18 | -------------------------------------------------------------------------------- /swapoff.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "util.h" 10 | 11 | static void 12 | usage(void) 13 | { 14 | eprintf("usage: %s -a | device\n", argv0); 15 | } 16 | 17 | int 18 | main(int argc, char *argv[]) 19 | { 20 | int i; 21 | int ret = 0; 22 | int all = 0; 23 | struct mntent *me; 24 | FILE *fp; 25 | 26 | ARGBEGIN { 27 | case 'a': 28 | all = 1; 29 | break; 30 | default: 31 | usage(); 32 | } ARGEND; 33 | 34 | if ((!all && argc < 1) || (all && argc > 0)) 35 | usage(); 36 | 37 | if (all) { 38 | fp = setmntent("/etc/fstab", "r"); 39 | if (!fp) 40 | eprintf("setmntent %s:", "/etc/fstab"); 41 | while ((me = getmntent(fp)) != NULL) { 42 | if (strcmp(me->mnt_type, MNTTYPE_SWAP) == 0) { 43 | if (swapoff(me->mnt_fsname) < 0) { 44 | weprintf("swapoff %s:", me->mnt_fsname); 45 | ret = 1; 46 | } 47 | } 48 | } 49 | endmntent(fp); 50 | } else { 51 | for (i = 0; i < argc; i++) { 52 | if (swapoff(argv[i]) < 0) { 53 | weprintf("swapoff %s:", argv[i]); 54 | ret = 1; 55 | } 56 | } 57 | } 58 | return ret; 59 | } 60 | -------------------------------------------------------------------------------- /swapon.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt SWAPON 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm swapon 6 | .Nd enable devices and files for paging and swapping 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl dp 10 | .Fl a | Ar device 11 | .Sh DESCRIPTION 12 | .Nm 13 | is used to specify devices on which paging and swapping are to take place. 14 | .Sh OPTIONS 15 | .Bl -tag -width Ds 16 | .It Fl a 17 | Make all devices marked as ``swap'' in 18 | .Pa /etc/fstab 19 | available, except for those with the ``noauto'' option. 20 | .It Fl d 21 | Discard freed swap pages before they are reused. 22 | .It Fl p 23 | Set higher priority than the default to the new swap area. 24 | .El 25 | -------------------------------------------------------------------------------- /swapon.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "util.h" 10 | 11 | static void 12 | usage(void) 13 | { 14 | eprintf("usage: %s [-dp] -a | device\n", argv0); 15 | } 16 | 17 | int 18 | main(int argc, char *argv[]) 19 | { 20 | int i; 21 | int ret = 0; 22 | int flags = 0; 23 | int all = 0; 24 | struct mntent *me; 25 | FILE *fp; 26 | 27 | ARGBEGIN { 28 | case 'a': 29 | all = 1; 30 | break; 31 | case 'd': 32 | flags |= SWAP_FLAG_DISCARD; 33 | break; 34 | case 'p': 35 | flags |= SWAP_FLAG_PREFER; 36 | break; 37 | default: 38 | usage(); 39 | } ARGEND; 40 | 41 | if ((!all && argc < 1) || (all && argc > 0)) 42 | usage(); 43 | 44 | if (all) { 45 | fp = setmntent("/etc/fstab", "r"); 46 | if (!fp) 47 | eprintf("setmntent %s:", "/etc/fstab"); 48 | while ((me = getmntent(fp)) != NULL) { 49 | if (strcmp(me->mnt_type, MNTTYPE_SWAP) == 0 50 | && (hasmntopt(me, MNTOPT_NOAUTO) == NULL)) { 51 | if (swapon(me->mnt_fsname, flags) < 0) { 52 | weprintf("swapon %s:", me->mnt_fsname); 53 | ret = 1; 54 | } 55 | } 56 | } 57 | endmntent(fp); 58 | } else { 59 | for (i = 0; i < argc; i++) { 60 | if (swapon(argv[i], flags) < 0) { 61 | weprintf("swapon %s:", argv[i]); 62 | ret = 1; 63 | } 64 | } 65 | } 66 | return ret; 67 | } 68 | -------------------------------------------------------------------------------- /switch_root.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt SWITCH_ROOT 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm switch_root 6 | .Nd switch to another filesystem as the root of the mount tree 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl c Ar console 10 | .Ar newroot init 11 | .Sh DESCRIPTION 12 | .Nm 13 | removes all files and directories on the current root filesystem and 14 | overmounts it with 15 | .Ar newroot . 16 | If a 17 | .Ar console 18 | is specified, redirect stdio and stderr to it. After the switch, execute 19 | .Ar init . 20 | .Pp 21 | .Nm 22 | can only be run as PID 1 in an initramfs or tmpfs with a regular and 23 | executable /sbin/init. 24 | .Sh OPTIONS 25 | .Bl -tag -width Ds 26 | .It Fl c 27 | Redirect stdio and stderr to 28 | .Ar console 29 | after switching to 30 | .Ar newroot . 31 | .El 32 | -------------------------------------------------------------------------------- /switch_root.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "util.h" 15 | 16 | #define RAMFS_MAGIC 0x858458f6 /* some random number */ 17 | #define TMPFS_MAGIC 0x01021994 18 | 19 | static void 20 | delete_content(const char *dir, dev_t curdevice) 21 | { 22 | char path[PATH_MAX]; 23 | DIR *d; 24 | struct stat st; 25 | struct dirent *dent; 26 | 27 | /* don't dive into other filesystems */ 28 | if (lstat(dir, &st) < 0 || st.st_dev != curdevice) 29 | return; 30 | if (!(d = opendir(dir))) 31 | return; 32 | while ((dent = readdir(d))) { 33 | if (strcmp(dent->d_name, ".") == 0 || 34 | strcmp(dent->d_name, "..") == 0) 35 | continue; 36 | 37 | /* build path and dive deeper */ 38 | if (strlcpy(path, dir, sizeof(path)) >= sizeof(path)) 39 | eprintf("path too long\n"); 40 | if (path[strlen(path) - 1] != '/') 41 | if (strlcat(path, "/", sizeof(path)) >= sizeof(path)) 42 | eprintf("path too long\n"); 43 | if (strlcat(path, dent->d_name, sizeof(path)) >= sizeof(path)) 44 | eprintf("path too long\n"); 45 | 46 | if (lstat(path, &st) < 0) 47 | weprintf("lstat %s:", path); 48 | 49 | if (S_ISDIR(st.st_mode)) { 50 | delete_content(path, curdevice); 51 | if (rmdir(path) < 0) 52 | weprintf("rmdir %s:", path); 53 | } else { 54 | if (unlink(path) < 0) 55 | weprintf("unlink %s:", path); 56 | } 57 | } 58 | closedir(d); 59 | } 60 | 61 | static void 62 | usage(void) 63 | { 64 | eprintf("usage: %s [-c console] [newroot] [init] (PID 1)\n", argv0); 65 | } 66 | 67 | int 68 | main(int argc, char *argv[]) 69 | { 70 | char *console = NULL; 71 | dev_t curdev; 72 | struct stat st; 73 | struct statfs stfs; 74 | 75 | ARGBEGIN { 76 | case 'c': 77 | console = EARGF(usage()); 78 | break; 79 | default: 80 | usage(); 81 | } ARGEND; 82 | 83 | /* check number of args and if we are PID 1 */ 84 | if (argc != 2 || getpid() != 1) 85 | usage(); 86 | 87 | /* chdir to newroot and make sure it's a different fs */ 88 | if (chdir(argv[0])) 89 | eprintf("chdir %s:", argv[0]); 90 | 91 | if (stat("/", &st)) 92 | eprintf("stat %s:", "/"); 93 | 94 | curdev = st.st_dev; 95 | if (stat(".", &st)) 96 | eprintf("stat %s:", "."); 97 | if (st.st_dev == curdev) 98 | usage(); 99 | 100 | /* avoids trouble with real filesystems */ 101 | if (stat("/init", &st) || !S_ISREG(st.st_mode)) 102 | eprintf("/init is not a regular file\n"); 103 | 104 | statfs("/", &stfs); 105 | if ((unsigned)stfs.f_type != RAMFS_MAGIC && (unsigned)stfs.f_type != TMPFS_MAGIC) 106 | eprintf("current filesystem is not a RAMFS or TMPFS\n"); 107 | 108 | /* wipe / */ 109 | delete_content("/", curdev); 110 | 111 | /* overmount / with newroot and chroot into it */ 112 | if (mount(".", "/", NULL, MS_MOVE, NULL)) 113 | eprintf("mount %s:", "."); 114 | 115 | if (chroot(".")) 116 | eprintf("chroot failed\n"); 117 | 118 | /* if -c is set, redirect stdin/stdout/stderr to console */ 119 | if (console) { 120 | close(0); 121 | if (open(console, O_RDWR) == -1) 122 | eprintf("open %s:", console); 123 | dup2(0, 1); 124 | dup2(0, 2); 125 | } 126 | 127 | /* execute init */ 128 | execv(argv[1], argv); 129 | eprintf("can't execute '%s':", argv[1]); 130 | return 1; 131 | } 132 | -------------------------------------------------------------------------------- /sysctl.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt SYSCTL 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm sysctl 6 | .Nd configure kernel parameters at runtime 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl p Ar file 10 | .Ar variable Ns Oo Ar =value Oc Ns ... 11 | .Sh DESCRIPTION 12 | .Nm 13 | modifies kernel parameters at runtime. The parameters available are those 14 | listed under 15 | .Pa /proc/sys/ . 16 | Procfs is required for sysctl support in Linux. You can use 17 | .Nm 18 | to both read and write sysctl data. 19 | .Sh OPTIONS 20 | .Bl -tag -width Ds 21 | .It Fl p 22 | Load the sysctl key=value pairs from 23 | .Ar file . 24 | .El 25 | -------------------------------------------------------------------------------- /sysctl.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "text.h" 10 | #include "util.h" 11 | 12 | static void 13 | replacestr(char *s, int a, int b) 14 | { 15 | for (; *s; s++) 16 | if (*s == a) 17 | *s = b; 18 | } 19 | 20 | static int 21 | getsysctl(char *variable, char **value) 22 | { 23 | char path[PATH_MAX]; 24 | char *p; 25 | char *buf, *tmp, c; 26 | int fd; 27 | ssize_t n; 28 | size_t sz, i; 29 | 30 | replacestr(variable, '.', '/'); 31 | 32 | strlcpy(path, "/proc/sys/", sizeof(path)); 33 | if (strlcat(path, variable, sizeof(path)) >= sizeof(path)) { 34 | replacestr(variable, '/', '.'); 35 | return -1; 36 | } 37 | 38 | replacestr(variable, '/', '.'); 39 | 40 | fd = open(path, O_RDONLY); 41 | if (fd < 0) 42 | return -1; 43 | 44 | i = 0; 45 | sz = 1; 46 | buf = NULL; 47 | while (1) { 48 | n = read(fd, &c, 1); 49 | if (n < 0) { 50 | close(fd); 51 | free(buf); 52 | return -1; 53 | } 54 | if (n == 0) 55 | break; 56 | if (i == sz - 1) { 57 | sz *= 2; 58 | tmp = realloc(buf, sz); 59 | if (!tmp) { 60 | close(fd); 61 | free(buf); 62 | return -1; 63 | } 64 | buf = tmp; 65 | } 66 | buf[i++] = c; 67 | } 68 | buf[i] = '\0'; 69 | 70 | p = strrchr(buf, '\n'); 71 | if (p) 72 | *p = '\0'; 73 | 74 | *value = buf; 75 | 76 | close(fd); 77 | 78 | return 0; 79 | } 80 | 81 | static int 82 | setsysctl(char *variable, char *value) 83 | { 84 | char path[PATH_MAX]; 85 | int fd; 86 | ssize_t n; 87 | 88 | replacestr(variable, '.', '/'); 89 | 90 | strlcpy(path, "/proc/sys/", sizeof(path)); 91 | if (strlcat(path, variable, sizeof(path)) >= sizeof(path)) { 92 | replacestr(variable, '/', '.'); 93 | return -1; 94 | } 95 | 96 | replacestr(variable, '/', '.'); 97 | 98 | fd = open(path, O_WRONLY); 99 | if (fd < 0) 100 | return -1; 101 | 102 | n = write(fd, value, strlen(value)); 103 | if ((size_t)n != strlen(value)) { 104 | close(fd); 105 | return -1; 106 | } 107 | 108 | close(fd); 109 | 110 | return 0; 111 | } 112 | 113 | static int 114 | parsepair(char *pair) 115 | { 116 | char *p; 117 | char *variable; 118 | char *value; 119 | 120 | for (p = pair; *p; p++) { 121 | if (p[0] == '.' && p[1] == '.') { 122 | weprintf("malformed input: %s\n", pair); 123 | return -1; 124 | } 125 | } 126 | p = strchr(pair, '='); 127 | if (p) { 128 | if (p[1] == '\0') { 129 | weprintf("malformed input: %s\n", pair); 130 | return -1; 131 | } 132 | *p = '\0'; 133 | value = &p[1]; 134 | } else { 135 | value = NULL; 136 | } 137 | variable = pair; 138 | if (value) { 139 | if (setsysctl(variable, value) < 0) { 140 | weprintf("failed to set sysctl for %s\n", variable); 141 | return -1; 142 | } 143 | } else { 144 | if (getsysctl(variable, &value) < 0) { 145 | weprintf("failed to get sysctl for %s\n", variable); 146 | return -1; 147 | } 148 | printf("%s = %s\n", variable, value); 149 | free(value); 150 | } 151 | 152 | return 0; 153 | } 154 | 155 | static void 156 | usage(void) 157 | { 158 | eprintf("usage: %s [-p file] variable[=value]...\n", argv0); 159 | } 160 | 161 | int 162 | main(int argc, char *argv[]) 163 | { 164 | FILE *fp; 165 | char *buf = NULL, *p; 166 | char *file = NULL; 167 | size_t size = 0; 168 | int i; 169 | int r = 0; 170 | 171 | ARGBEGIN { 172 | case 'p': 173 | file = EARGF(usage()); 174 | break; 175 | default: 176 | usage(); 177 | } ARGEND; 178 | 179 | if (!file && argc < 1) 180 | usage(); 181 | 182 | if (!file) { 183 | for (i = 0; i < argc; i++) 184 | if (parsepair(argv[i]) < 0) 185 | r = 1; 186 | } else { 187 | fp = fopen(file, "r"); 188 | if (!fp) 189 | eprintf("fopen %s:", file); 190 | while (agetline(&buf, &size, fp) != -1) { 191 | p = buf; 192 | for (p = buf; *p == ' ' || *p == '\t'; p++) 193 | ; 194 | if (*p == '#' || *p == '\n') 195 | continue; 196 | for (p = buf; *p; p++) { 197 | if (*p == '\n') { 198 | *p = '\0'; 199 | break; 200 | } 201 | } 202 | p = buf; 203 | if (parsepair(p) < 0) 204 | r = 1; 205 | } 206 | if (ferror(fp)) 207 | eprintf("%s: read error:", file); 208 | free(buf); 209 | fclose(fp); 210 | } 211 | 212 | return r; 213 | } 214 | -------------------------------------------------------------------------------- /text.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | 3 | struct linebuf { 4 | char **lines; 5 | long nlines; 6 | long capacity; 7 | }; 8 | #define EMPTY_LINEBUF {NULL, 0, 0,} 9 | void getlines(FILE *, struct linebuf *); 10 | 11 | ssize_t agetline(char **, size_t *, FILE *); 12 | 13 | void concat(FILE *, const char *, FILE *, const char *); 14 | -------------------------------------------------------------------------------- /truncate.1: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt TRUNCATE 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm truncate 6 | .Nd shrink or extend the size of a file to the specified size 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl c 10 | .Fl s Ar size 11 | .Ar file... 12 | .Sh DESCRIPTION 13 | .Nm 14 | shrinks or extends the size of each 15 | .Ar file 16 | specified size. A 17 | .Ar file 18 | argument that does not exist is created. If a 19 | .Ar file 20 | is larger than the specified 21 | .Ar size , 22 | the extra data is lost. If a 23 | .Ar file 24 | is shorter, it is extended and the extended part (hole) reads as zero bytes. 25 | .Sh OPTIONS 26 | .Bl -tag -width Ds 27 | .It Fl c 28 | Do not create any files. 29 | .It Fl s Ar size 30 | Set or adjust the file size by 31 | .Ar size 32 | bytes. 33 | .El 34 | .Sh SEE ALSO 35 | .Xr ftruncate 2 , 36 | .Xr truncate 2 -------------------------------------------------------------------------------- /truncate.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "util.h" 10 | 11 | static void 12 | usage(void) 13 | { 14 | eprintf("usage: %s [-c] -s size file...\n", argv0); 15 | } 16 | 17 | int 18 | main(int argc, char *argv[]) 19 | { 20 | int cflag = 0, sflag = 0; 21 | int fd, i, ret = 0; 22 | long size = 0; 23 | 24 | ARGBEGIN { 25 | case 's': 26 | sflag = 1; 27 | size = estrtol(EARGF(usage()), 10); 28 | break; 29 | case 'c': 30 | cflag = 1; 31 | break; 32 | default: 33 | usage(); 34 | } ARGEND; 35 | 36 | if (argc < 1 || sflag == 0) 37 | usage(); 38 | 39 | for (i = 0; i < argc; i++) { 40 | fd = open(argv[i], O_WRONLY | (cflag ? 0 : O_CREAT), 0644); 41 | if (fd < 0) { 42 | weprintf("open: cannot open `%s' for writing:", argv[i]); 43 | ret = 1; 44 | continue; 45 | } 46 | if (ftruncate(fd, size) < 0) { 47 | weprintf("ftruncate: cannot open `%s' for writing:", argv[i]); 48 | ret = 1; 49 | } 50 | close(fd); 51 | } 52 | return ret; 53 | } 54 | -------------------------------------------------------------------------------- /umount.8: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt UMOUNT 8 3 | .Os ubase 4 | .Sh NAME 5 | .Nm umount 6 | .Nd unmount file systems 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl fln 10 | .Ar target... 11 | .Nm 12 | .Op Fl fln 13 | .Fl a 14 | .Sh DESCRIPTION 15 | .Nm 16 | detaches the 17 | .Ar target 18 | filesystem(s). A file system is specified by giving the directory where it 19 | has been mounted. Giving the special device on which the file system 20 | lives may also work, but is obsolete, mainly because it will fail in 21 | case this device was mounted on more than one directory. 22 | .Sh OPTIONS 23 | .Bl -tag -width Ds 24 | .It Fl a 25 | All of the file systems described in 26 | .Pa /proc/mounts 27 | are unmounted. The proc filesystem is not unmounted. 28 | .It Fl f 29 | Force unmount (in case of an unreachable NFS server). 30 | .It Fl l 31 | Lazy unmount. Detach the filesystem from the fs hierarchy now, and cleanup 32 | all references to the filesystem as soon as it is not busy anymore. 33 | .It Fl n 34 | Unmount without writing in 35 | .Pa /etc/mtab . 36 | This is the default action. 37 | .El 38 | .Sh SEE ALSO 39 | .Xr umount 2 , 40 | .Xr mount 8 41 | -------------------------------------------------------------------------------- /umount.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "util.h" 10 | 11 | static int 12 | umountall(int flags) 13 | { 14 | FILE *fp; 15 | struct mntent *me; 16 | int ret = 0; 17 | char **mntdirs = NULL; 18 | int len = 0; 19 | 20 | fp = setmntent("/proc/mounts", "r"); 21 | if (!fp) 22 | eprintf("setmntent %s:", "/proc/mounts"); 23 | while ((me = getmntent(fp))) { 24 | if (strcmp(me->mnt_type, "proc") == 0) 25 | continue; 26 | mntdirs = erealloc(mntdirs, ++len * sizeof(*mntdirs)); 27 | mntdirs[len - 1] = estrdup(me->mnt_dir); 28 | } 29 | endmntent(fp); 30 | while (--len >= 0) { 31 | if (umount2(mntdirs[len], flags) < 0) { 32 | weprintf("umount2 %s:", mntdirs[len]); 33 | ret = 1; 34 | } 35 | free(mntdirs[len]); 36 | } 37 | free(mntdirs); 38 | return ret; 39 | } 40 | 41 | static void 42 | usage(void) 43 | { 44 | weprintf("usage: %s [-lfn] target...\n", argv0); 45 | weprintf("usage: %s -a [-lfn]\n", argv0); 46 | exit(1); 47 | } 48 | 49 | int 50 | main(int argc, char *argv[]) 51 | { 52 | int i; 53 | int aflag = 0; 54 | int flags = 0; 55 | int ret = 0; 56 | 57 | ARGBEGIN { 58 | case 'a': 59 | aflag = 1; 60 | break; 61 | case 'f': 62 | flags |= MNT_FORCE; 63 | break; 64 | case 'l': 65 | flags |= MNT_DETACH; 66 | break; 67 | case 'n': 68 | break; 69 | default: 70 | usage(); 71 | } ARGEND; 72 | 73 | if (argc < 1 && aflag == 0) 74 | usage(); 75 | 76 | if (aflag == 1) 77 | return umountall(flags); 78 | 79 | for (i = 0; i < argc; i++) { 80 | if (umount2(argv[i], flags) < 0) { 81 | weprintf("umount2 %s:", argv[i]); 82 | ret = 1; 83 | } 84 | } 85 | return ret; 86 | } 87 | -------------------------------------------------------------------------------- /unshare.1: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt UNSHARE 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm unshare 6 | .Nd run program with some namespaces unshared from parent 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl muinpU 10 | .Ar cmd 11 | .Op Ar args... 12 | .Sh DESCRIPTION 13 | .Nm 14 | unshares the indicated namespaces from the parent process and then executes 15 | the specified program. The namespaces to be unshared are indicated via 16 | options. 17 | .Sh OPTIONS 18 | .Bl -tag -width Ds 19 | .It Fl i 20 | Unshare the System V IPC namespace, so that the calling process has a 21 | private copy of the System V IPC namespace which is not shared with 22 | any other process. This flag has the same effect as the 23 | .Xr clone 2 24 | .Dv CLONE_NEWIPC 25 | flag. 26 | .It Fl m 27 | Unshare the mount namespace, so that the calling process has a private 28 | copy of its namespace which is not shared with any other process. 29 | This flag has the same effect as the 30 | .Xr clone 2 31 | .Dv CLONE_NEWNS 32 | flag. 33 | .It Fl n 34 | Unshare the network namespace, so that the calling process is moved 35 | into a new network namespace which is not shared with any previously 36 | existing process. This flag has the same effect as the 37 | .Xr clone 2 38 | .Dv CLONE_NEWNET 39 | flag. 40 | .It Fl u 41 | Unshare the UTS IPC namespace, so that the calling process has a 42 | private copy of the UTS namespace which is not shared with any other 43 | process. This flag has the same effect as the 44 | .Xr clone 2 45 | .Dv CLONE_NEWUTS 46 | flag. 47 | .It Fl p 48 | Create the process in a new PID namespace. This flag has the same 49 | effect as the 50 | .Xr clone 2 51 | .Dv CLONE_NEWPID 52 | flag. 53 | .It Fl U 54 | The process will have a distinct set of UIDs, GIDs and capabilities. 55 | .El 56 | .Sh SEE ALSO 57 | .Xr clone 2 , 58 | .Xr unshare 2 59 | -------------------------------------------------------------------------------- /unshare.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "util.h" 9 | 10 | static void 11 | usage(void) 12 | { 13 | eprintf("usage: %s [-muinpU] cmd [args...]\n", argv0); 14 | } 15 | 16 | int 17 | main(int argc, char *argv[]) 18 | { 19 | int flags = 0; 20 | 21 | ARGBEGIN { 22 | case 'm': 23 | flags |= CLONE_NEWNS; 24 | break; 25 | case 'u': 26 | flags |= CLONE_NEWUTS; 27 | break; 28 | case 'i': 29 | flags |= CLONE_NEWIPC; 30 | break; 31 | case 'n': 32 | flags |= CLONE_NEWNET; 33 | break; 34 | case 'p': 35 | flags |= CLONE_NEWPID; 36 | break; 37 | case 'U': 38 | flags |= CLONE_NEWUSER; 39 | break; 40 | default: 41 | usage(); 42 | } ARGEND; 43 | 44 | if (argc < 1) 45 | usage(); 46 | 47 | if (unshare(flags) < 0) 48 | eprintf("unshare:"); 49 | 50 | if (execvp(argv[0], argv) < 0) 51 | eprintf("execvp:"); 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /uptime.1: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt UPTIME 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm uptime 6 | .Nd tell how long the system has been running 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Sh DESCRIPTION 10 | .Nm 11 | gives a one line display of the following information. The current time, how 12 | long the system has been running, how many users are currently logged on and 13 | the system load averages for the past 1, 5 and 15 minutes. 14 | .Sh SEE ALSO 15 | .Xr ps 1 , 16 | .Xr utmp 5 17 | -------------------------------------------------------------------------------- /uptime.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "config.h" 11 | #include "util.h" 12 | 13 | static void 14 | usage(void) 15 | { 16 | eprintf("usage: %s\n", argv0); 17 | } 18 | 19 | int 20 | main(int argc, char *argv[]) 21 | { 22 | struct utmpx utx; 23 | FILE *ufp; 24 | struct sysinfo info; 25 | time_t tmptime; 26 | struct tm *now; 27 | unsigned int days, hours, minutes; 28 | int nusers = 0; 29 | size_t n; 30 | 31 | ARGBEGIN { 32 | default: 33 | usage(); 34 | } ARGEND; 35 | 36 | if (sysinfo(&info) < 0) 37 | eprintf("sysinfo:"); 38 | time(&tmptime); 39 | now = localtime(&tmptime); 40 | printf(" %02d:%02d:%02d up ", now->tm_hour, now->tm_min, now->tm_sec); 41 | info.uptime /= 60; 42 | minutes = info.uptime % 60; 43 | info.uptime /= 60; 44 | hours = info.uptime % 24; 45 | days = info.uptime / 24; 46 | if (days) 47 | printf("%d day%s, ", days, days != 1 ? "s" : ""); 48 | if (hours) 49 | printf("%2d:%02d, ", hours, minutes); 50 | else 51 | printf("%d min, ", minutes); 52 | 53 | if ((ufp = fopen(UTMP_PATH, "r"))) { 54 | while ((n = fread(&utx, sizeof(utx), 1, ufp)) > 0) { 55 | if (!utx.ut_user[0]) 56 | continue; 57 | if (utx.ut_type != USER_PROCESS) 58 | continue; 59 | nusers++; 60 | } 61 | if (ferror(ufp)) 62 | eprintf("%s: read error:", UTMP_PATH); 63 | fclose(ufp); 64 | printf(" %d user%s, ", nusers, nusers != 1 ? "s" : ""); 65 | } 66 | 67 | printf(" load average: %.02f, %.02f, %.02f\n", 68 | info.loads[0] / 65536.0f, 69 | info.loads[1] / 65536.0f, 70 | info.loads[2] / 65536.0f); 71 | 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include "arg.h" 3 | 4 | #define UTF8_POINT(c) (((c) & 0xc0) != 0x80) 5 | 6 | #undef MIN 7 | #define MIN(x,y) ((x) < (y) ? (x) : (y)) 8 | #undef MAX 9 | #define MAX(x,y) ((x) > (y) ? (x) : (y)) 10 | #undef LIMIT 11 | #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) 12 | 13 | #define LEN(x) (sizeof (x) / sizeof *(x)) 14 | 15 | /* eprintf.c */ 16 | extern char *argv0; 17 | 18 | /* agetcwd.c */ 19 | char *agetcwd(void); 20 | 21 | /* apathmax.c */ 22 | void apathmax(char **, long *); 23 | 24 | /* ealloc.c */ 25 | void *ecalloc(size_t, size_t); 26 | void *emalloc(size_t size); 27 | void *erealloc(void *, size_t); 28 | char *estrdup(const char *); 29 | 30 | /* eprintf.c */ 31 | void enprintf(int, const char *, ...); 32 | void eprintf(const char *, ...); 33 | void weprintf(const char *, ...); 34 | 35 | /* estrtol.c */ 36 | long estrtol(const char *, int); 37 | 38 | /* estrtoul.c */ 39 | unsigned long estrtoul(const char *, int); 40 | 41 | /* explicit_bzero.c */ 42 | #undef explicit_bzero 43 | void explicit_bzero(void *, size_t); 44 | 45 | /* putword.c */ 46 | void putword(const char *); 47 | 48 | /* recurse.c */ 49 | void recurse(const char *, void (*)(const char *)); 50 | 51 | /* strlcat.c */ 52 | #undef strlcat 53 | size_t strlcat(char *, const char *, size_t); 54 | size_t estrlcat(char *, const char *, size_t); 55 | 56 | /* strlcpy.c */ 57 | #undef strlcpy 58 | size_t strlcpy(char *, const char *, size_t); 59 | size_t estrlcpy(char *, const char *, size_t); 60 | 61 | /* strtonum.c */ 62 | #undef strtonum 63 | long long strtonum(const char *, long long, long long, const char **); 64 | long long enstrtonum(int, const char *, long long, long long); 65 | long long estrtonum(const char *, long long, long long); 66 | 67 | /* tty.c */ 68 | void devtotty(int, int *, int *); 69 | int ttytostr(int, int, char *, size_t); 70 | -------------------------------------------------------------------------------- /vmstat.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "util.h" 12 | 13 | struct vm { 14 | intmax_t cpu_user; 15 | intmax_t cpu_nice; 16 | intmax_t cpu_system; 17 | intmax_t cpu_idle; 18 | intmax_t cpu_iowait; 19 | intmax_t cpu_irq; 20 | intmax_t cpu_softirq; 21 | intmax_t cpu_steal; 22 | intmax_t cpu_guest; 23 | intmax_t cpu_guest_nice; 24 | intmax_t cpu_unknown; 25 | intmax_t page_in; 26 | intmax_t page_out; 27 | intmax_t swap_in; 28 | intmax_t swap_out; 29 | intmax_t intr; 30 | intmax_t ctxt_switches; 31 | intmax_t processes; 32 | intmax_t proc_running; 33 | intmax_t proc_blocked; 34 | intmax_t mem_free; 35 | intmax_t buffers; 36 | intmax_t cached; 37 | intmax_t active; 38 | intmax_t inactive; 39 | intmax_t swap_total; 40 | intmax_t swap_free; 41 | intmax_t sreclaimable; 42 | }; 43 | 44 | static intmax_t kb_per_page; 45 | static intmax_t hz; 46 | 47 | static int 48 | stpstarts(char *str, const char *head, char **end) 49 | { 50 | size_t n = strlen(head); 51 | if (!strncmp(str, head, n)) { 52 | *end = &str[n]; 53 | return 1; 54 | } 55 | return 0; 56 | } 57 | 58 | static intmax_t 59 | read_ints(const char *s, intmax_t *arr, size_t n) 60 | { 61 | const char *beginning = s; 62 | intmax_t rest = 0; 63 | size_t tmp; 64 | int negative; 65 | 66 | memset(arr, 0, n * sizeof(*arr)); 67 | 68 | for (; n--; arr++) { 69 | while (*s && !isdigit(*s)) 70 | s++; 71 | negative = (s != beginning && s[-1] == '-'); 72 | while (isdigit(*s)) 73 | *arr = *arr * 10 + (*s++ - '0'); 74 | if (negative) 75 | *arr = -*arr; 76 | } 77 | 78 | for (; *s; rest += tmp) { 79 | tmp = 0; 80 | while (*s && !isdigit(*s)) 81 | s++; 82 | negative = (s != beginning && s[-1] == '-'); 83 | while (isdigit(*s)) 84 | tmp = tmp * 10 + (*s++ - '0'); 85 | if (negative) 86 | tmp = -tmp; 87 | } 88 | 89 | return rest; 90 | } 91 | 92 | static void 93 | load_vm(struct vm *s) 94 | { 95 | static intmax_t debt = 0; 96 | 97 | int have_page = 0, have_swap = 0; 98 | char *line = NULL, *p; 99 | size_t size = 0; 100 | ssize_t len; 101 | FILE *fp; 102 | 103 | memset(s, 0, sizeof(*s)); 104 | 105 | fp = fopen("/proc/stat", "r"); 106 | if (!fp) 107 | eprintf("fopen /proc/stat:"); 108 | while ((len = getline(&line, &size, fp)) >= 0) { 109 | if (stpstarts(line, "cpu ", &p)) { 110 | s->cpu_unknown = read_ints(p, &s->cpu_user, 10); 111 | } else if (stpstarts(line, "page ", &p)) { 112 | read_ints(p, &s->page_in, 2); 113 | have_page = 1; 114 | } else if (stpstarts(line, "swap ", &p)) { 115 | read_ints(p, &s->swap_in, 2); 116 | have_swap = 1; 117 | } else if (stpstarts(line, "intr ", &p)) { 118 | read_ints(p, &s->intr, 1); 119 | } else if (stpstarts(line, "ctxt ", &p)) { 120 | read_ints(p, &s->ctxt_switches, 1); 121 | } else if (stpstarts(line, "processes ", &p)) { 122 | read_ints(p, &s->processes, 1); 123 | } else if (stpstarts(line, "proc_running ", &p)) { 124 | read_ints(p, &s->proc_running, 1); 125 | } else if (stpstarts(line, "proc_blocked ", &p)) { 126 | read_ints(p, &s->proc_blocked, 1); 127 | } 128 | } 129 | if (ferror(fp)) 130 | eprintf("getline /proc/stat:"); 131 | fclose(fp); 132 | 133 | if (!have_page || !have_swap) { 134 | fp = fopen("/proc/vmstat", "r"); 135 | if (!fp) 136 | eprintf("fopen /proc/vmstat:"); 137 | while ((len = getline(&line, &size, fp)) >= 0) { 138 | if (!have_page && stpstarts(line, "pgpgin ", &p)) 139 | read_ints(p, &s->page_in, 1); 140 | else if (!have_page && stpstarts(line, "pgpgout ", &p)) 141 | read_ints(p, &s->page_out, 1); 142 | else if (!have_swap && stpstarts(line, "pswpin ", &p)) 143 | read_ints(p, &s->swap_in, 1); 144 | else if (!have_swap && stpstarts(line, "pswpout ", &p)) 145 | read_ints(p, &s->swap_out, 1); 146 | } 147 | if (ferror(fp)) 148 | eprintf("getline /proc/vmstat:"); 149 | fclose(fp); 150 | } 151 | 152 | fp = fopen("/proc/meminfo", "r"); 153 | if (!fp) 154 | eprintf("fopen /proc/meminfo:"); 155 | while ((len = getline(&line, &size, fp)) >= 0) { 156 | if (stpstarts(line, "MemFree:", &p)) 157 | read_ints(p, &s->mem_free, 1); 158 | else if (stpstarts(line, "Buffers:", &p)) 159 | read_ints(p, &s->buffers, 1); 160 | else if (stpstarts(line, "Cached:", &p)) 161 | read_ints(p, &s->cached, 1); 162 | else if (stpstarts(line, "Active:", &p)) 163 | read_ints(p, &s->active, 1); 164 | else if (stpstarts(line, "Inactive:", &p)) 165 | read_ints(p, &s->inactive, 1); 166 | else if (stpstarts(line, "SwapTotal:", &p)) 167 | read_ints(p, &s->swap_total, 1); 168 | else if (stpstarts(line, "SwapFree:", &p)) 169 | read_ints(p, &s->swap_free, 1); 170 | else if (stpstarts(line, "SReclaimable:", &p)) 171 | read_ints(p, &s->sreclaimable, 1); 172 | } 173 | if (ferror(fp)) 174 | eprintf("getline /proc/meminfo:"); 175 | fclose(fp); 176 | 177 | /* yes, this is actually needed */ 178 | s->cpu_idle += debt; 179 | debt = 0; 180 | if (s->cpu_idle < 0) { 181 | debt = s->cpu_idle; 182 | s->cpu_idle = 0; 183 | } 184 | 185 | free(line); 186 | } 187 | 188 | static void 189 | print_vm(struct vm *s1, struct vm *s0, int active_mem, int timestamp, int print_header) 190 | { 191 | struct vm s = *s1; 192 | intmax_t ticks; 193 | char timezone[21]; 194 | char timestr[21]; 195 | struct tm *tm; 196 | time_t now; 197 | size_t n; 198 | 199 | ticks = s.cpu_user -= s0->cpu_user; 200 | ticks += s.cpu_nice -= s0->cpu_nice; 201 | ticks += s.cpu_system -= s0->cpu_system; 202 | ticks += s.cpu_idle -= s0->cpu_idle; 203 | ticks += s.cpu_iowait -= s0->cpu_iowait; 204 | ticks += s.cpu_irq -= s0->cpu_irq; 205 | ticks += s.cpu_softirq -= s0->cpu_softirq; 206 | ticks += s.cpu_steal -= s0->cpu_steal; 207 | ticks += s.cpu_guest -= s0->cpu_guest; 208 | ticks += s.cpu_guest_nice -= s0->cpu_guest_nice; 209 | ticks += s.cpu_unknown -= s0->cpu_unknown; 210 | s.processes -= s0->processes; 211 | s.intr -= s0->intr; 212 | s.ctxt_switches -= s0->ctxt_switches; 213 | s.page_in -= s0->page_in; 214 | s.page_out -= s0->page_out; 215 | 216 | s.cpu_user += s.cpu_nice; 217 | s.cpu_guest += s0->cpu_guest_nice; 218 | s.cpu_idle += !ticks; 219 | ticks += !ticks; 220 | 221 | if (timestamp) { 222 | now = time(NULL); 223 | tm = localtime(&now); 224 | strftime(timestr, sizeof(timestr), " %Y-%m-%d %H:%M:%S", tm); 225 | strftime(timezone, sizeof(timezone), "%Z", tm); 226 | n = strlen(timezone) + 1; 227 | memmove(&timezone[sizeof(timezone) - n], timezone, n); 228 | memset(timezone, ' ', sizeof(timezone) - n); 229 | } 230 | 231 | #define PERCENT(X) ((X) * 100 + ticks / 2) / ticks 232 | #define HERTZ(X) ((X) * hz + ticks / 2) / ticks 233 | 234 | if (!print_header) 235 | goto print; 236 | printf("----procs---- -------------------memory------------------ ---swap-- -----io---- --system- --------------cpu--------------%s\n", 237 | timestamp ? " -----timestamp-----" : ""); 238 | printf(" r b fk swpd free " "%s " "%s si so bi bo in cs us sy id wa in si st gt%s\n", 239 | active_mem ? "inact" : " buff", active_mem ? "active" : " cache", timestamp ? timezone : ""); 240 | print: 241 | printf("%2ji %2ji %7ji %10ji " "%10ji " "%10ji " "%10ji %4ji %4ji %5ji %5ji ""%4ji %4ji %3ji %3ji %3ji %3ji %3ji %3ji %3ji %3ji%s\n", 242 | s.proc_running, s.proc_blocked, s.processes, 243 | s.swap_total - s.swap_free, s.mem_free, active_mem ? s.inactive : s.buffers, active_mem ? s.active : s.cached + s.sreclaimable, 244 | HERTZ(s.swap_in * kb_per_page), HERTZ(s.swap_out * kb_per_page), 245 | HERTZ(s.page_in), HERTZ(s.page_out), 246 | HERTZ(s.intr), HERTZ(s.ctxt_switches), 247 | PERCENT(s.cpu_user), PERCENT(s.cpu_system), PERCENT(s.cpu_idle), 248 | PERCENT(s.cpu_iowait), PERCENT(s.cpu_irq), PERCENT(s.cpu_softirq), 249 | PERCENT(s.cpu_steal), PERCENT(s.cpu_guest), 250 | timestamp ? timestr : ""); 251 | 252 | #undef PERCENT 253 | #undef HERTZ 254 | } 255 | 256 | static void 257 | usage(void) 258 | { 259 | eprintf("usage: %s [-ant] [delay [count]]\n", argv0); 260 | } 261 | 262 | int 263 | main(int argc, char *argv[]) 264 | { 265 | static struct vm vm[2]; 266 | static struct timespec delay; 267 | char *end; 268 | double tmp; 269 | unsigned long long int count = 0, i = 0; 270 | int one_header = 0; 271 | int active_mem = 0; 272 | int timestamp = 0; 273 | 274 | ARGBEGIN { 275 | case 'a': 276 | active_mem = 1; 277 | break; 278 | case 'n': 279 | one_header = 1; 280 | break; 281 | case 't': 282 | timestamp = 1; 283 | break; 284 | case 'w': 285 | /* Ignored for compatibility (allow output to be wider than 80 columns) */ 286 | break; 287 | default: 288 | usage(); 289 | } ARGEND; 290 | 291 | if (argc > 2) 292 | usage(); 293 | 294 | kb_per_page = (intmax_t)(sysconf(_SC_PAGESIZE) / 1024); 295 | hz = (intmax_t)sysconf(_SC_CLK_TCK); 296 | 297 | if (argc) { 298 | errno = 0; 299 | tmp = strtod(argv[0], &end); 300 | if (errno || *end || tmp <= 0) 301 | eprintf("%s: not a valid positive number\n", argv[0]); 302 | delay.tv_sec = (time_t)tmp; 303 | tmp = (tmp - (double)delay.tv_sec) * 1000000000.; 304 | delay.tv_nsec = (long int)tmp; 305 | if (delay.tv_nsec > 999999999L) 306 | delay.tv_nsec = 999999999L; 307 | 308 | if (argc > 1) 309 | count = (unsigned long long int)atoll(argv[1]); 310 | } 311 | 312 | for (;;) { 313 | load_vm(&vm[i & 1]); 314 | print_vm(&vm[i & 1], &vm[~i & 1], active_mem, timestamp, one_header ? !i : (i % 50 == 0)); 315 | i++; 316 | if (!argc || (argc == 2 && i == count)) 317 | break; 318 | clock_nanosleep(CLOCK_MONOTONIC, 0, &delay, NULL); 319 | } 320 | 321 | return 0; 322 | } 323 | -------------------------------------------------------------------------------- /vtallow.1: -------------------------------------------------------------------------------- 1 | .Dd December 5, 2014 2 | .Dt VTALLOW 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm vtallow 6 | .Nd enable or disable the VT switch 7 | .Sh SYNOPSIS 8 | .Nm vtallow 9 | .Ar n | Ar y 10 | .Sh DESCRIPTION 11 | .Nm 12 | controls the VT switch lock. 13 | .Sh OPTIONS 14 | .Bl -tag -width Ds 15 | .It Ar n 16 | Disable VT switching. 17 | .It Ar y 18 | Enable VT switching. 19 | .El 20 | .Sh SEE ALSO 21 | .Xr chvt 1 22 | -------------------------------------------------------------------------------- /vtallow.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "util.h" 12 | 13 | #define CONSOLE "/dev/console" 14 | 15 | #define VT_LOCKSWITCH 0x560B /* disallow vt switching */ 16 | #define VT_UNLOCKSWITCH 0x560C /* allow vt switching */ 17 | 18 | static void 19 | usage(void) 20 | { 21 | eprintf("usage: %s n | y\n", argv0); 22 | } 23 | 24 | int 25 | main(int argc, char *argv[]) 26 | { 27 | int fd; 28 | int allow; 29 | 30 | ARGBEGIN { 31 | default: 32 | usage(); 33 | } ARGEND; 34 | 35 | if (argc != 1) 36 | usage(); 37 | 38 | if (!strcmp(argv[0], "y")) 39 | allow = 1; 40 | else if (!strcmp(argv[0], "n")) 41 | allow = 0; 42 | else 43 | usage(); 44 | 45 | if ((fd = open(CONSOLE, O_WRONLY)) < 0) 46 | eprintf("open %s:", CONSOLE); 47 | if (ioctl(fd, allow ? VT_UNLOCKSWITCH : VT_LOCKSWITCH) < 0) 48 | eprintf("cannot %s VT switch:", 49 | allow ? "unlock" : "lock"); 50 | close(fd); 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /watch.1: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt WATCH 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm watch 6 | .Nd execute a program periodically, showing output fullscreen 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl n Ar interval 10 | .Op Fl t 11 | .Ar command 12 | .Sh DESCRIPTION 13 | .Nm 14 | runs 15 | .Ar command 16 | repeatedly, displaying its output one screenfull at a time. This allows you 17 | to watch the program output change over time. By default the program is run 18 | every 2 seconds and will run until terminated. 19 | .Sh OPTIONS 20 | .Bl -tag -width Ds 21 | .It Fl n Ar interval 22 | Specify the update interval. 23 | .It Fl t 24 | Turn off the header showing the interval, command and current time at the top 25 | of the display, as well as the following blank line. This is the default 26 | action. 27 | .El 28 | -------------------------------------------------------------------------------- /watch.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "util.h" 8 | 9 | static void 10 | usage(void) 11 | { 12 | eprintf("usage: %s [-t] [-n interval] command\n", argv0); 13 | } 14 | 15 | int 16 | main(int argc, char *argv[]) 17 | { 18 | char cmd[BUFSIZ]; 19 | char *end; 20 | useconds_t interval = 2 * 1E6; 21 | float period; 22 | int i; 23 | 24 | ARGBEGIN { 25 | case 't': 26 | break; 27 | case 'n': 28 | period = strtof(EARGF(usage()), &end); 29 | if (*end != '\0' || errno != 0) 30 | eprintf("invalid interval\n"); 31 | if (period < 0) 32 | period = 0.1f; 33 | interval = period * 1E6; 34 | break; 35 | default: 36 | usage(); 37 | } ARGEND; 38 | 39 | if (argc < 1) 40 | usage(); 41 | 42 | if (strlcpy(cmd, argv[0], sizeof(cmd)) >= sizeof(cmd)) 43 | eprintf("command too long\n"); 44 | for (i = 1; i < argc; i++) { 45 | if (strlcat(cmd, " ", sizeof(cmd)) >= sizeof(cmd)) 46 | eprintf("command too long\n"); 47 | if (strlcat(cmd, argv[i], sizeof(cmd)) >= sizeof(cmd)) 48 | eprintf("command too long\n"); 49 | } 50 | 51 | for (;;) { 52 | printf("\x1b[2J\x1b[H"); /* clear */ 53 | fflush(NULL); 54 | system(cmd); 55 | usleep(interval); 56 | } 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /who.1: -------------------------------------------------------------------------------- 1 | .Dd February 2, 2015 2 | .Dt WHO 1 3 | .Os ubase 4 | .Sh NAME 5 | .Nm who 6 | .Nd print who has logged on 7 | .Sh SYNOPSIS 8 | .Nm 9 | .Op Fl lm 10 | .Sh DESCRIPTION 11 | .Nm 12 | prints a list of who has logged on, their controlling tty, and the 13 | time at which they logged on. 14 | .Sh OPTIONS 15 | .Bl -tag -width Ds 16 | .It Fl l 17 | Print LOGIN processes as well. 18 | .It Fl m 19 | Only show users on current tty. 20 | .El 21 | .Sh SEE ALSO 22 | .Xr utmp 5 23 | .Sh BUGS 24 | .Nm 25 | relies on the utmp file to be updated responsibly. This 26 | doesn't always happen, which can cause 27 | .Nm 28 | to print completely bogus data. 29 | -------------------------------------------------------------------------------- /who.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "config.h" 10 | #include "util.h" 11 | 12 | static void 13 | usage(void) 14 | { 15 | eprintf("usage: %s [-ml]\n", argv0); 16 | } 17 | 18 | int 19 | main(int argc, char *argv[]) 20 | { 21 | struct utmp usr; 22 | FILE *ufp; 23 | char timebuf[sizeof "yyyy-mm-dd hh:mm"]; 24 | char *tty, *ttmp; 25 | int mflag = 0, lflag = 0; 26 | time_t t; 27 | 28 | ARGBEGIN { 29 | case 'm': 30 | mflag = 1; 31 | tty = ttyname(0); 32 | if (!tty) 33 | eprintf("ttyname: stdin:"); 34 | if ((ttmp = strrchr(tty, '/'))) 35 | tty = ttmp+1; 36 | break; 37 | case 'l': 38 | lflag = 1; 39 | break; 40 | default: 41 | usage(); 42 | } ARGEND; 43 | 44 | if (argc > 0) 45 | usage(); 46 | 47 | if (!(ufp = fopen(UTMP_PATH, "r"))) 48 | eprintf("fopen: %s:", UTMP_PATH); 49 | 50 | while (fread(&usr, sizeof(usr), 1, ufp) == 1) { 51 | if (!*usr.ut_name || !*usr.ut_line || 52 | usr.ut_line[0] == '~') 53 | continue; 54 | if (mflag != 0 && strcmp(usr.ut_line, tty) != 0) 55 | continue; 56 | if (!!strcmp(usr.ut_name, "LOGIN") == lflag) 57 | continue; 58 | t = usr.ut_time; 59 | strftime(timebuf, sizeof timebuf, "%Y-%m-%d %H:%M", localtime(&t)); 60 | printf("%-8s %-12s %-16s\n", usr.ut_name, usr.ut_line, timebuf); 61 | } 62 | fclose(ufp); 63 | return 0; 64 | } 65 | --------------------------------------------------------------------------------