mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-05 18:58:30 +00:00
Make build hermetic without shell scripts
- Fix some minor issues in ar.com - Have execve() look for `ape` command - Rewrite NT paths using /c/ rather /??/c:/ - Replace broken GCC symlinks with .sym files - Rewrite $PATH environment variables on startup - Make $(APE_NO_MODIFY_SELF) the default bootloader - Add all build command dependencies to build/bootstrap - Get the repository mostly building from source on non-Linux
This commit is contained in:
parent
d44ff6ce1f
commit
d230a01222
160 changed files with 2754 additions and 1342 deletions
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/arraylist2.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
|
@ -26,12 +27,16 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/madv.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
@ -53,6 +58,8 @@
|
|||
* This tool also adds a feature: it ignores directory parameters. This
|
||||
* is important because good Makefiles on Linux will generally have the
|
||||
* directory be a .a prerequisite so archives rebuild on file deletion.
|
||||
*
|
||||
* @see https://www.unix.com/man-page/opensolaris/3head/ar.h/
|
||||
*/
|
||||
|
||||
struct Args {
|
||||
|
@ -80,29 +87,68 @@ struct Header {
|
|||
char fmag[2];
|
||||
};
|
||||
|
||||
static void *Realloc(void *p, size_t n) {
|
||||
void *q;
|
||||
if (!(q = realloc(p, n))) {
|
||||
fputs("error: ar: out of memory\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
static void *Malloc(size_t n) {
|
||||
return Realloc(0, n);
|
||||
}
|
||||
|
||||
static void NewArgs(struct Args *l, size_t n) {
|
||||
l->i = 0;
|
||||
l->n = MAX(2, n);
|
||||
l->p = Malloc(l->n * sizeof(*l->p));
|
||||
l->p[0] = 0;
|
||||
}
|
||||
|
||||
static void NewInts(struct Ints *l, size_t n) {
|
||||
l->i = 0;
|
||||
l->n = n;
|
||||
l->p = xmalloc(n * sizeof(int));
|
||||
l->n = MAX(2, n);
|
||||
l->p = Malloc(l->n * sizeof(*l->p));
|
||||
l->p[0] = 0;
|
||||
}
|
||||
|
||||
static void NewString(struct String *s, size_t n) {
|
||||
s->i = 0;
|
||||
s->n = n;
|
||||
s->p = xmalloc(n);
|
||||
s->n = MAX(2, n);
|
||||
s->p = Malloc(s->n * sizeof(*s->p));
|
||||
s->p[0] = 0;
|
||||
}
|
||||
|
||||
static void AppendInt(struct Ints *l, int i) {
|
||||
APPEND(&l->p, &l->i, &l->n, &i);
|
||||
assert(l->n > 1);
|
||||
if (l->i + 1 >= l->n) {
|
||||
do {
|
||||
l->n += l->n >> 1;
|
||||
} while (l->i + 1 >= l->n);
|
||||
l->p = Realloc(l->p, l->n * sizeof(*l->p));
|
||||
}
|
||||
l->p[l->i++] = i;
|
||||
l->p[l->i] = 0;
|
||||
}
|
||||
|
||||
static void AppendArg(struct Args *l, char *s) {
|
||||
APPEND(&l->p, &l->i, &l->n, &s);
|
||||
assert(l->n > 1);
|
||||
if (l->i + 1 >= l->n) {
|
||||
do {
|
||||
l->n += l->n >> 1;
|
||||
} while (l->i + 1 >= l->n);
|
||||
l->p = Realloc(l->p, l->n * sizeof(*l->p));
|
||||
}
|
||||
l->p[l->i++] = s;
|
||||
l->p[l->i] = 0;
|
||||
}
|
||||
|
||||
static void MakeHeader(struct Header *h, const char *name, int ref, int mode,
|
||||
int size) {
|
||||
size_t n;
|
||||
char ibuf[13], *p;
|
||||
memset(h, ' ', sizeof(*h));
|
||||
n = strlen(name);
|
||||
memcpy(h->name, name, n);
|
||||
|
@ -113,11 +159,15 @@ static void MakeHeader(struct Header *h, const char *name, int ref, int mode,
|
|||
h->date[0] = '0';
|
||||
h->uid[0] = '0';
|
||||
h->gid[0] = '0';
|
||||
FormatOctal32(h->mode, mode & 0777, false);
|
||||
p = FormatOctal32(ibuf, mode & 0777, false);
|
||||
CHECK_LE(p - ibuf, sizeof(h->mode));
|
||||
memcpy(h->mode, ibuf, p - ibuf);
|
||||
}
|
||||
h->fmag[0] = '`';
|
||||
h->fmag[1] = '\n';
|
||||
FormatUint32(h->size, size);
|
||||
p = FormatUint32(ibuf, size);
|
||||
CHECK_LE(p - ibuf, sizeof(h->size));
|
||||
memcpy(h->size, ibuf, p - ibuf);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
@ -151,15 +201,24 @@ int main(int argc, char *argv[]) {
|
|||
struct Header *header1, *header2;
|
||||
int i, j, fd, err, name, outfd, tablebufsize;
|
||||
|
||||
if (argc == 2 && !strcmp(argv[1], "-n")) exit(0);
|
||||
// TODO(jart): Delete this.
|
||||
if (argc == 2 && !strcmp(argv[1], "-n")) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// we only support one mode of operation, which is creating a new
|
||||
// deterministic archive. this tool is so fast that we don't need
|
||||
// database-like tools when editing static archives
|
||||
if (!(argc > 2 && strcmp(argv[1], "rcsD") == 0)) {
|
||||
fprintf(stderr, "%s%s%s\n", "Usage: ", argv[0], " rcsD ARCHIVE FILE...");
|
||||
return 1;
|
||||
fputs("usage: ", stderr);
|
||||
if (argc > 0) fputs(argv[0], stderr);
|
||||
fputs(" rcsD ARCHIVE FILE...", stderr);
|
||||
exit(EX_USAGE);
|
||||
}
|
||||
|
||||
outpath = argv[2];
|
||||
bzero(&args, sizeof(args));
|
||||
st = xmalloc(sizeof(struct stat));
|
||||
NewArgs(&args, 4);
|
||||
st = Malloc(sizeof(struct stat));
|
||||
NewInts(&modes, 128);
|
||||
NewInts(&names, 128);
|
||||
NewInts(&sizes, 128);
|
||||
|
@ -206,10 +265,10 @@ int main(int argc, char *argv[]) {
|
|||
// compute length of output archive
|
||||
outsize = 0;
|
||||
tablebufsize = 4 + symnames.i * 4;
|
||||
tablebuf = xmalloc(tablebufsize);
|
||||
offsets = xmalloc(args.i * 4);
|
||||
header1 = xmalloc(sizeof(struct Header));
|
||||
header2 = xmalloc(sizeof(struct Header));
|
||||
tablebuf = Malloc(tablebufsize);
|
||||
offsets = Malloc(args.i * 4);
|
||||
header1 = Malloc(sizeof(struct Header));
|
||||
header2 = Malloc(sizeof(struct Header));
|
||||
iov[0].iov_base = "!<arch>\n";
|
||||
outsize += (iov[0].iov_len = 8);
|
||||
iov[1].iov_base = header1;
|
||||
|
|
|
@ -56,9 +56,11 @@ TOOL_BUILD_DIRECTDEPS = \
|
|||
THIRD_PARTY_GDTOA \
|
||||
THIRD_PARTY_GETOPT \
|
||||
THIRD_PARTY_MBEDTLS \
|
||||
THIRD_PARTY_MUSL \
|
||||
THIRD_PARTY_STB \
|
||||
THIRD_PARTY_XED \
|
||||
THIRD_PARTY_ZLIB \
|
||||
THIRD_PARTY_ZLIB_GZ \
|
||||
TOOL_BUILD_LIB
|
||||
|
||||
TOOL_BUILD_DEPS := \
|
||||
|
@ -78,7 +80,7 @@ o/$(MODE)/tool/build/%.com.dbg: \
|
|||
o/$(MODE)/tool/build/build.pkg \
|
||||
o/$(MODE)/tool/build/%.o \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/tool/build/blinkenlights.com.dbg: \
|
||||
|
@ -105,7 +107,7 @@ o/$(MODE)/tool/build/ar.com.dbg: \
|
|||
o/$(MODE)/tool/build/build.pkg \
|
||||
o/$(MODE)/tool/build/ar.o \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/tool/build/package.com.dbg: \
|
||||
|
@ -113,7 +115,7 @@ o/$(MODE)/tool/build/package.com.dbg: \
|
|||
o/$(MODE)/tool/build/build.pkg \
|
||||
o/$(MODE)/tool/build/package.o \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/tool/build/mkdeps.com.dbg: \
|
||||
|
@ -121,7 +123,7 @@ o/$(MODE)/tool/build/mkdeps.com.dbg: \
|
|||
o/$(MODE)/tool/build/build.pkg \
|
||||
o/$(MODE)/tool/build/mkdeps.o \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/tool/build/compile.com.dbg: \
|
||||
|
@ -129,7 +131,7 @@ o/$(MODE)/tool/build/compile.com.dbg: \
|
|||
o/$(MODE)/tool/build/build.pkg \
|
||||
o/$(MODE)/tool/build/compile.o \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/tool/build/zipobj.com.dbg: \
|
||||
|
@ -137,7 +139,7 @@ o/$(MODE)/tool/build/zipobj.com.dbg: \
|
|||
o/$(MODE)/tool/build/build.pkg \
|
||||
o/$(MODE)/tool/build/zipobj.o \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
$(APE_NO_MODIFY_SELF)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/tool/build/emulator.o: \
|
||||
|
|
220
tool/build/cocmd.c
Normal file
220
tool/build/cocmd.c
Normal file
|
@ -0,0 +1,220 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Cosmopolitan Command Interpreter
|
||||
*
|
||||
* This is a lightweight command interpreter for GNU Make. It has just
|
||||
* enough shell script language support to support our build config.
|
||||
*/
|
||||
|
||||
#define STATE_SHELL 0
|
||||
#define STATE_STR 1
|
||||
|
||||
char *p;
|
||||
char *q;
|
||||
char *cmd;
|
||||
char *args[8192];
|
||||
const char *prog;
|
||||
char argbuf[ARG_MAX];
|
||||
bool unsupported[256];
|
||||
|
||||
wontreturn void UnsupportedSyntax(unsigned char c) {
|
||||
char ibuf[13];
|
||||
FormatOctal32(ibuf, c, true);
|
||||
fputs(prog, stderr);
|
||||
fputs(": unsupported shell syntax '", stderr);
|
||||
fputc(c, stderr);
|
||||
fputs("' (", stderr);
|
||||
fputs(ibuf, stderr);
|
||||
fputs("): ", stderr);
|
||||
fputs(cmd, stderr);
|
||||
fputs("\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void Open(const char *path, int fd, int flags) {
|
||||
const char *err;
|
||||
close(fd);
|
||||
if (open(path, flags, 0644) == -1) {
|
||||
err = strerdoc(errno);
|
||||
fputs(prog, stderr);
|
||||
fputs(": failed to open '", stderr);
|
||||
fputs(path, stderr);
|
||||
fputs("': ", stderr);
|
||||
fputs(err, stderr);
|
||||
fputs("\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
char *Tokenize(void) {
|
||||
int t;
|
||||
char *r;
|
||||
while (*p == ' ' || *p == '\t' || *p == '\n' ||
|
||||
(p[0] == '\\' && p[1] == '\n')) {
|
||||
++p;
|
||||
}
|
||||
if (!*p) return 0;
|
||||
t = STATE_SHELL;
|
||||
for (r = q;; ++p) {
|
||||
switch (t) {
|
||||
|
||||
case STATE_SHELL:
|
||||
if (unsupported[*p & 255]) {
|
||||
UnsupportedSyntax(*p);
|
||||
}
|
||||
if (!*p || *p == ' ' || *p == '\t') {
|
||||
*q++ = 0;
|
||||
return r;
|
||||
} else if (*p == '\'') {
|
||||
t = STATE_STR;
|
||||
} else if (*p == '\\') {
|
||||
if (!p[1]) UnsupportedSyntax(*p);
|
||||
*q++ = *++p;
|
||||
} else {
|
||||
*q++ = *p;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_STR:
|
||||
if (!*p) {
|
||||
fputs("cmd: error: unterminated string\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
if (*p == '\'') {
|
||||
t = STATE_SHELL;
|
||||
} else {
|
||||
*q++ = *p;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char *s, *arg;
|
||||
size_t i, j, n;
|
||||
prog = argc > 0 ? argv[0] : "cocmd.com";
|
||||
|
||||
for (i = 1; i < 32; ++i) {
|
||||
unsupported[i] = true;
|
||||
}
|
||||
unsupported['\t'] = false;
|
||||
unsupported[0177] = true;
|
||||
unsupported['~'] = true;
|
||||
unsupported['`'] = true;
|
||||
unsupported['#'] = true;
|
||||
unsupported['$'] = true;
|
||||
unsupported['*'] = true;
|
||||
unsupported['('] = true;
|
||||
unsupported[')'] = true;
|
||||
unsupported['|'] = true;
|
||||
unsupported['['] = true;
|
||||
unsupported[']'] = true;
|
||||
unsupported['{'] = true;
|
||||
unsupported['}'] = true;
|
||||
unsupported[';'] = true;
|
||||
unsupported['"'] = true;
|
||||
unsupported['?'] = true;
|
||||
unsupported['!'] = true;
|
||||
|
||||
if (argc != 3) {
|
||||
fputs(prog, stderr);
|
||||
fputs(": error: wrong number of args\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "-c")) {
|
||||
fputs(prog, stderr);
|
||||
fputs(": error: argv[1] should -c\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
p = cmd = argv[2];
|
||||
if (strlen(cmd) >= ARG_MAX) {
|
||||
fputs(prog, stderr);
|
||||
fputs(": error: cmd too long: ", stderr);
|
||||
fputs(cmd, stderr);
|
||||
fputs("\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
q = argbuf;
|
||||
while ((arg = Tokenize())) {
|
||||
if (n + 1 < ARRAYLEN(args)) {
|
||||
if (!strcmp(arg, "2>&1")) {
|
||||
close(1);
|
||||
dup(2);
|
||||
} else if (!strcmp(arg, ">&2")) {
|
||||
close(2);
|
||||
dup(1);
|
||||
} else if (arg[0] == '2' && arg[1] == '>' && arg[2] == '>') {
|
||||
Open(arg + 3, 2, O_WRONLY | O_CREAT | O_APPEND);
|
||||
} else if (arg[0] == '>' && arg[1] == '>') {
|
||||
Open(arg + 2, 1, O_WRONLY | O_CREAT | O_APPEND);
|
||||
} else if (arg[0] == '2' && arg[1] == '>') {
|
||||
Open(arg + 2, 2, O_WRONLY | O_CREAT | O_TRUNC);
|
||||
} else if (arg[0] == '>') {
|
||||
Open(arg + 1, 1, O_WRONLY | O_CREAT | O_TRUNC);
|
||||
} else if (arg[0] == '<') {
|
||||
Open(arg + 1, 0, O_RDONLY);
|
||||
} else {
|
||||
args[n++] = arg;
|
||||
}
|
||||
} else {
|
||||
fputs(prog, stderr);
|
||||
fputs(": error: too many args\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!n) {
|
||||
fputs(prog, stderr);
|
||||
fputs(": error: too few args\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
execv(args[0], args);
|
||||
if (!n) {
|
||||
s = strerdoc(errno);
|
||||
fputs(prog, stderr);
|
||||
fputs(": execve '", stderr);
|
||||
fputs(args[0], stderr);
|
||||
fputs("' failed: ", stderr);
|
||||
fputs(s, stderr);
|
||||
fputs("\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 127;
|
||||
}
|
|
@ -32,6 +32,7 @@
|
|||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/color.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
|
@ -170,9 +171,7 @@ char *output;
|
|||
char *outpath;
|
||||
char *command;
|
||||
char *shortened;
|
||||
char *cachedcmd;
|
||||
char *colorflag;
|
||||
char *originalcmd;
|
||||
char ccpath[PATH_MAX];
|
||||
|
||||
struct stat st;
|
||||
|
@ -582,7 +581,7 @@ int Launch(void) {
|
|||
timer.it_interval.tv_sec = timeout;
|
||||
setitimer(ITIMER_REAL, &timer, 0);
|
||||
}
|
||||
pid = fork();
|
||||
pid = vfork();
|
||||
|
||||
#if 0
|
||||
int fd;
|
||||
|
@ -665,6 +664,8 @@ int Launch(void) {
|
|||
kill(pid, SIGKILL);
|
||||
gotalrm = 1;
|
||||
}
|
||||
} else if (errno == ECHILD) {
|
||||
break;
|
||||
} else {
|
||||
/* this should never happen */
|
||||
PrintRed();
|
||||
|
@ -1040,44 +1041,6 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* help error reporting code find symbol table
|
||||
*/
|
||||
if (startswith(cmd, "o/")) {
|
||||
if (endswith(cmd, ".com")) {
|
||||
s = xstrcat(cmd, ".dbg");
|
||||
} else {
|
||||
s = xstrcat(cmd, ".com.dbg");
|
||||
}
|
||||
if (fileexists(s)) {
|
||||
AddEnv(xstrcat("COMDBG=", getcwd(0, 0), '/', s));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* create assimilated atomic copies of ape binaries
|
||||
*/
|
||||
if (!IsWindows() && endswith(cmd, ".com")) {
|
||||
if (!startswith(cmd, "o/")) {
|
||||
cachedcmd = xstrcat("o/", cmd);
|
||||
} else {
|
||||
cachedcmd = xstrcat(xstripext(cmd), ".elf");
|
||||
}
|
||||
if (FileExistsAndIsNewerThan(cachedcmd, cmd)) {
|
||||
cmd = cachedcmd;
|
||||
} else {
|
||||
originalcmd = cmd;
|
||||
FormatInt64(buf, getpid());
|
||||
cmd = xstrcat(originalcmd, ".tmp.", buf);
|
||||
if (copyfile(originalcmd, cmd, COPYFILE_PRESERVE_TIMESTAMPS) == -1) {
|
||||
fputs("error: compile.com failed to copy ape executable\n", stderr);
|
||||
unlink(cmd);
|
||||
exit(97);
|
||||
}
|
||||
}
|
||||
args.p[0] = cmd;
|
||||
}
|
||||
|
||||
/*
|
||||
* make sense of standard i/o file descriptors
|
||||
* we want to permit pipelines but prevent talking to terminal
|
||||
|
@ -1117,26 +1080,6 @@ int main(int argc, char *argv[]) {
|
|||
* run command
|
||||
*/
|
||||
ws = Launch();
|
||||
if (ws != -1 && WIFEXITED(ws) && WEXITSTATUS(ws) == 127) {
|
||||
if (startswith(cmd, "o/third_party/gcc") &&
|
||||
fileexists("third_party/gcc/unbundle.sh")) {
|
||||
system("third_party/gcc/unbundle.sh");
|
||||
ws = Launch();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* cleanup temporary copy of ape executable
|
||||
*/
|
||||
if (originalcmd) {
|
||||
if (cachedcmd && WIFEXITED(ws) && !WEXITSTATUS(ws) &&
|
||||
IsNativeExecutable(cmd)) {
|
||||
makedirs(xdirname(cachedcmd), 0755);
|
||||
rename(cmd, cachedcmd);
|
||||
} else {
|
||||
unlink(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* propagate exit
|
||||
|
|
234
tool/build/cp.c
Normal file
234
tool/build/cp.c
Normal file
|
@ -0,0 +1,234 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/copyfile.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/musl/ftw.h"
|
||||
|
||||
#define USAGE \
|
||||
" SRC... DST\n\
|
||||
\n\
|
||||
SYNOPSIS\n\
|
||||
\n\
|
||||
Copies Files\n\
|
||||
\n\
|
||||
FLAGS\n\
|
||||
\n\
|
||||
-?\n\
|
||||
-h help\n\
|
||||
-f force\n\
|
||||
-r recursive\n\
|
||||
-n no clobber\n\
|
||||
-a preserve all\n\
|
||||
-p preserve owner and timestamps\n\
|
||||
\n"
|
||||
|
||||
int flags;
|
||||
bool force;
|
||||
int striplen;
|
||||
bool recursive;
|
||||
const char *prog;
|
||||
char mkbuf[PATH_MAX];
|
||||
char srcdir[PATH_MAX];
|
||||
char dstdir[PATH_MAX];
|
||||
char srcfile[PATH_MAX];
|
||||
char dstfile[PATH_MAX];
|
||||
char linkbuf[PATH_MAX];
|
||||
|
||||
void Cp(char *, char *);
|
||||
|
||||
bool IsDirectory(const char *path) {
|
||||
int e;
|
||||
bool res;
|
||||
struct stat st;
|
||||
e = errno;
|
||||
res = stat(path, &st) != -1 && S_ISDIR(st.st_mode);
|
||||
errno = e;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool IsSymlink(const char *path) {
|
||||
int e;
|
||||
bool res;
|
||||
struct stat st;
|
||||
e = errno;
|
||||
res = fstatat(AT_FDCWD, path, &st, AT_SYMLINK_NOFOLLOW) != -1 &&
|
||||
S_ISLNK(st.st_mode);
|
||||
errno = e;
|
||||
return res;
|
||||
}
|
||||
|
||||
wontreturn void PrintUsage(int rc, FILE *f) {
|
||||
fputs("usage: ", f);
|
||||
fputs(prog, f);
|
||||
fputs(USAGE, f);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "?hfnaprR")) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
force = true;
|
||||
break;
|
||||
case 'r':
|
||||
case 'R':
|
||||
recursive = true;
|
||||
break;
|
||||
case 'n':
|
||||
flags |= COPYFILE_NOCLOBBER;
|
||||
break;
|
||||
case 'a':
|
||||
case 'p':
|
||||
flags |= COPYFILE_PRESERVE_OWNER;
|
||||
flags |= COPYFILE_PRESERVE_TIMESTAMPS;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
PrintUsage(EXIT_SUCCESS, stdout);
|
||||
default:
|
||||
PrintUsage(EX_USAGE, stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Visit(const char *fpath, const struct stat *sb, int tflag,
|
||||
struct FTW *ftwbuf) {
|
||||
char *src;
|
||||
strcpy(srcfile, fpath);
|
||||
src = srcfile + striplen;
|
||||
strcpy(dstfile, dstdir);
|
||||
if (!endswith(dstfile, "/")) {
|
||||
strcat(dstfile, "/");
|
||||
}
|
||||
strcat(dstfile, src);
|
||||
strcpy(srcfile, fpath);
|
||||
switch (tflag) {
|
||||
case FTW_D:
|
||||
return 0;
|
||||
case FTW_F:
|
||||
case FTW_SL:
|
||||
case FTW_SLN:
|
||||
Cp(srcfile, dstfile);
|
||||
return 0;
|
||||
default:
|
||||
fputs(fpath, stderr);
|
||||
fputs(": can't handle file type\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
char *Join(const char *a, const char *b) {
|
||||
size_t n, m;
|
||||
n = strlen(a);
|
||||
m = strlen(b);
|
||||
if (n + 1 + m + 1 > sizeof(dstfile)) {
|
||||
fputs("error: cp: path too long\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
stpcpy(stpcpy(stpcpy(dstfile, a), "/"), b);
|
||||
return dstfile;
|
||||
}
|
||||
|
||||
void Cp(char *src, char *dst) {
|
||||
ssize_t rc;
|
||||
const char *s;
|
||||
if (strlen(src) + 1 > PATH_MAX) _Exit(2);
|
||||
if (strlen(dst) + 1 > PATH_MAX) _Exit(2);
|
||||
basename(src);
|
||||
basename(dst);
|
||||
if (IsDirectory(src)) {
|
||||
if (!recursive) {
|
||||
fputs(prog, stderr);
|
||||
fputs(": won't copy directory without -r flag.\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
strcpy(dstdir, dst);
|
||||
if (IsDirectory(dst)) {
|
||||
strcpy(srcdir, src);
|
||||
basename(srcdir);
|
||||
striplen = 0;
|
||||
strcpy(srcdir, basename(src));
|
||||
} else {
|
||||
strcpy(srcdir, src);
|
||||
basename(srcdir);
|
||||
striplen = strlen(srcdir);
|
||||
strcpy(srcdir, "");
|
||||
}
|
||||
if (nftw(src, Visit, 20, 0) == -1) {
|
||||
fputs(prog, stderr);
|
||||
fputs(": nftw failed: ", stderr);
|
||||
fputs(strerdoc(errno), stderr);
|
||||
fputs("\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (IsDirectory(dst)) {
|
||||
dst = Join(dst, basename(src));
|
||||
}
|
||||
if (!force && access(dst, W_OK) == -1 && errno != ENOENT) goto OnFail;
|
||||
strcpy(mkbuf, dst);
|
||||
if (makedirs(dirname(mkbuf), 0755) == -1) goto OnFail;
|
||||
if (IsSymlink(src)) {
|
||||
if ((rc = readlink(src, linkbuf, sizeof(linkbuf) - 1)) == -1) goto OnFail;
|
||||
linkbuf[rc] = 0;
|
||||
if (symlink(linkbuf, dst) == -1) goto OnFail;
|
||||
} else {
|
||||
if (copyfile(src, dst, flags) == -1) goto OnFail;
|
||||
}
|
||||
return;
|
||||
OnFail:
|
||||
s = strerdoc(errno);
|
||||
fputs(prog, stderr);
|
||||
fputs(": ", stderr);
|
||||
fputs(src, stderr);
|
||||
fputs(" ", stderr);
|
||||
fputs(dst, stderr);
|
||||
fputs(": ", stderr);
|
||||
fputs(s, stderr);
|
||||
fputs("\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
prog = argc > 0 ? argv[0] : "cp.com";
|
||||
GetOpts(argc, argv);
|
||||
if (argc - optind < 2) PrintUsage(EX_USAGE, stderr);
|
||||
for (i = optind; i < argc - 1; ++i) {
|
||||
Cp(argv[i], argv[argc - 1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
46
tool/build/echo.c
Normal file
46
tool/build/echo.c
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i, j;
|
||||
FILE *stream = stdout;
|
||||
bool wantnewline = true;
|
||||
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (!strcmp(argv[i], "-n")) {
|
||||
wantnewline = false;
|
||||
} else if (!strcmp(argv[i], "-2")) {
|
||||
stream = stderr;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; i + j < argc; ++j) {
|
||||
if (j) fputc(' ', stream);
|
||||
fputs(argv[i + j], stream);
|
||||
}
|
||||
if (wantnewline) {
|
||||
fputc('\n', stream);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
310
tool/build/gzip.c
Normal file
310
tool/build/gzip.c
Normal file
|
@ -0,0 +1,310 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/zlib/zlib.h"
|
||||
|
||||
#define USAGE \
|
||||
" PATH...\n\
|
||||
\n\
|
||||
SYNOPSIS\n\
|
||||
\n\
|
||||
Compress Files\n\
|
||||
\n\
|
||||
FLAGS\n\
|
||||
\n\
|
||||
-?\n\
|
||||
-h help\n\
|
||||
-f force\n\
|
||||
-c use stdout\n\
|
||||
-d decompress\n\
|
||||
-A append mode\n\
|
||||
-x exclusive mode\n\
|
||||
-k keep input file\n\
|
||||
-0 disable compression\n\
|
||||
-1 fastest compression\n\
|
||||
-4 coolest compression\n\
|
||||
-9 maximum compression\n\
|
||||
-a ascii mode (ignored)\n\
|
||||
-F fixed strategy (advanced)\n\
|
||||
-L filtered strategy (advanced)\n\
|
||||
-R run length strategy (advanced)\n\
|
||||
-H huffman only strategy (advanced)\n\
|
||||
\n"
|
||||
|
||||
bool opt_keep;
|
||||
bool opt_force;
|
||||
char opt_level;
|
||||
bool opt_append;
|
||||
char opt_strategy;
|
||||
bool opt_exclusive;
|
||||
bool opt_usestdout;
|
||||
bool opt_decompress;
|
||||
|
||||
const char *prog;
|
||||
char databuf[32768];
|
||||
char pathbuf[PATH_MAX];
|
||||
|
||||
wontreturn void PrintUsage(int rc, FILE *f) {
|
||||
fputs("usage: ", f);
|
||||
fputs(prog, f);
|
||||
fputs(USAGE, f);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "?hfcdakxALFRHF0123456789")) != -1) {
|
||||
switch (opt) {
|
||||
case 'k':
|
||||
opt_keep = true;
|
||||
break;
|
||||
case 'f':
|
||||
opt_force = true;
|
||||
break;
|
||||
case 'A':
|
||||
opt_append = true;
|
||||
break;
|
||||
case 'c':
|
||||
opt_usestdout = true;
|
||||
break;
|
||||
case 'x':
|
||||
opt_exclusive = true;
|
||||
break;
|
||||
case 'd':
|
||||
opt_decompress = true;
|
||||
break;
|
||||
case 'F':
|
||||
opt_strategy = 'F'; // Z_FIXED
|
||||
break;
|
||||
case 'L':
|
||||
opt_strategy = 'f'; // Z_FILTERED
|
||||
break;
|
||||
case 'R':
|
||||
opt_strategy = 'R'; // Z_RLE
|
||||
break;
|
||||
case 'H':
|
||||
opt_strategy = 'h'; // Z_HUFFMAN_ONLY
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
opt_level = opt;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
PrintUsage(EXIT_SUCCESS, stdout);
|
||||
default:
|
||||
PrintUsage(EX_USAGE, stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Compress(const char *inpath) {
|
||||
FILE *input;
|
||||
gzFile output;
|
||||
int rc, n, errnum;
|
||||
const char *outpath;
|
||||
char *p, openflags[5];
|
||||
outpath = 0;
|
||||
if (inpath) {
|
||||
input = fopen(inpath, "rb");
|
||||
} else if (opt_usestdout && (opt_force || !isatty(1))) {
|
||||
opt_usestdout = true;
|
||||
inpath = "/dev/stdin";
|
||||
input = stdin;
|
||||
} else {
|
||||
fputs(prog, stderr);
|
||||
fputs(": compressed data not written to a terminal."
|
||||
" Use -f to force compression.\n",
|
||||
stderr);
|
||||
exit(1);
|
||||
}
|
||||
p = openflags;
|
||||
*p++ = opt_append ? 'a' : 'w';
|
||||
*p++ = 'b';
|
||||
if (opt_exclusive) *p++ = 'x';
|
||||
if (opt_level) *p++ = opt_level;
|
||||
if (opt_strategy) *p++ = opt_strategy;
|
||||
*p = 0;
|
||||
if (opt_usestdout) {
|
||||
outpath = "/dev/stdout";
|
||||
output = gzdopen(0, openflags);
|
||||
} else {
|
||||
if (strlen(inpath) + 3 + 1 > PATH_MAX) _Exit(2);
|
||||
stpcpy(stpcpy(pathbuf, inpath), ".gz");
|
||||
outpath = pathbuf;
|
||||
output = gzopen(outpath, openflags);
|
||||
}
|
||||
if (!output) {
|
||||
fputs(outpath, stderr);
|
||||
fputs(": gzopen() failed\n", stderr);
|
||||
fputs(strerdoc(errno), stderr);
|
||||
fputs("\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
do {
|
||||
rc = fread(databuf, 1, sizeof(databuf), input);
|
||||
if (rc == -1) {
|
||||
errnum = 0;
|
||||
fputs(inpath, stderr);
|
||||
fputs(": read failed: ", stderr);
|
||||
fputs(strerdoc(ferror(input)), stderr);
|
||||
fputs("\n", stderr);
|
||||
_Exit(1);
|
||||
}
|
||||
if (!gzwrite(output, databuf, rc)) {
|
||||
fputs(outpath, stderr);
|
||||
fputs(": gzwrite failed: ", stderr);
|
||||
fputs(gzerror(output, &errnum), stderr);
|
||||
fputs("\n", stderr);
|
||||
_Exit(1);
|
||||
}
|
||||
} while (rc == sizeof(databuf));
|
||||
if (input != stdin) {
|
||||
if (fclose(input)) {
|
||||
fputs(inpath, stderr);
|
||||
fputs(": close failed\n", stderr);
|
||||
_Exit(1);
|
||||
}
|
||||
}
|
||||
if (gzclose(output)) {
|
||||
fputs(outpath, stderr);
|
||||
fputs(": gzclose failed\n", stderr);
|
||||
_Exit(1);
|
||||
}
|
||||
if (!opt_keep && !opt_usestdout && (opt_force || !access(inpath, W_OK))) {
|
||||
unlink(inpath);
|
||||
}
|
||||
}
|
||||
|
||||
void Decompress(const char *inpath) {
|
||||
FILE *output;
|
||||
gzFile input;
|
||||
int rc, n, errnum;
|
||||
const char *outpath;
|
||||
outpath = 0;
|
||||
if (inpath) {
|
||||
input = gzopen(inpath, "rb");
|
||||
} else {
|
||||
opt_usestdout = true;
|
||||
inpath = "/dev/stdin";
|
||||
input = gzdopen(0, "rb");
|
||||
}
|
||||
if (!input) {
|
||||
fputs(inpath, stderr);
|
||||
fputs(": gzopen() failed\n", stderr);
|
||||
fputs(strerdoc(errno), stderr);
|
||||
fputs("\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
if (opt_usestdout) {
|
||||
output = stdout;
|
||||
outpath = "/dev/stdout";
|
||||
} else if (endswith(inpath, ".gz")) {
|
||||
n = strlen(inpath);
|
||||
if (n - 3 + 1 > PATH_MAX) _Exit(2);
|
||||
memcpy(pathbuf, inpath, n - 3);
|
||||
pathbuf[n - 3] = 0;
|
||||
outpath = pathbuf;
|
||||
if (!(output = fopen(outpath, opt_append ? "wa" : "wb"))) {
|
||||
fputs(outpath, stderr);
|
||||
fputs(": open failed: ", stderr);
|
||||
fputs(strerdoc(errno), stderr);
|
||||
fputs("\n", stderr);
|
||||
_Exit(1);
|
||||
}
|
||||
} else {
|
||||
fputs(inpath, stderr);
|
||||
fputs(": needs to end with .gz unless -c is passed\n", stderr);
|
||||
_Exit(1);
|
||||
}
|
||||
do {
|
||||
rc = gzread(input, databuf, sizeof(databuf));
|
||||
if (rc == -1) {
|
||||
errnum = 0;
|
||||
fputs(inpath, stderr);
|
||||
fputs(": gzread failed: ", stderr);
|
||||
fputs(gzerror(input, &errnum), stderr);
|
||||
fputs("\n", stderr);
|
||||
_Exit(1);
|
||||
}
|
||||
if (fwrite(databuf, rc, 1, output) != 1) {
|
||||
fputs(outpath, stderr);
|
||||
fputs(": write failed: ", stderr);
|
||||
fputs(strerdoc(ferror(output)), stderr);
|
||||
fputs("\n", stderr);
|
||||
_Exit(1);
|
||||
}
|
||||
} while (rc == sizeof(databuf));
|
||||
if (gzclose(input)) {
|
||||
fputs(inpath, stderr);
|
||||
fputs(": gzclose failed\n", stderr);
|
||||
_Exit(1);
|
||||
}
|
||||
if (output != stdout) {
|
||||
if (fclose(output)) {
|
||||
fputs(outpath, stderr);
|
||||
fputs(": close failed\n", stderr);
|
||||
_Exit(1);
|
||||
}
|
||||
}
|
||||
if (!opt_keep && !opt_usestdout && (opt_force || !access(inpath, W_OK))) {
|
||||
unlink(inpath);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
prog = argc > 0 ? argv[0] : "cp.com";
|
||||
GetOpts(argc, argv);
|
||||
if (opt_decompress) {
|
||||
if (optind == argc) {
|
||||
Decompress(0);
|
||||
} else {
|
||||
for (i = optind; i < argc; ++i) {
|
||||
Decompress(argv[i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (optind == argc) {
|
||||
Compress(0);
|
||||
} else {
|
||||
for (i = optind; i < argc; ++i) {
|
||||
Compress(argv[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -28,6 +28,7 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
|
@ -225,7 +226,7 @@ wontreturn void OnMissingFile(const char *list, const char *src) {
|
|||
* automatically restart itself.
|
||||
*/
|
||||
if (list) {
|
||||
fprintf(stderr, "%s %s...\n", "Refreshing", list);
|
||||
kprintf("%s %s...\n", "Refreshing", list);
|
||||
unlink(list);
|
||||
}
|
||||
exit(1);
|
||||
|
@ -249,7 +250,9 @@ void LoadRelationships(int argc, char *argv[]) {
|
|||
while ((src = getargs_next(&ga))) {
|
||||
if (ShouldSkipSource(src)) continue;
|
||||
srcid = GetSourceId(src, strlen(src));
|
||||
if ((fd = open(src, O_RDONLY)) == -1) OnMissingFile(ga.path, src);
|
||||
if ((fd = open(src, O_RDONLY)) == -1) {
|
||||
OnMissingFile(ga.path, src);
|
||||
}
|
||||
CHECK_NE(-1, (rc = read(fd, buf, MAX_READ)));
|
||||
close(fd);
|
||||
size = rc;
|
||||
|
@ -282,13 +285,13 @@ void GetOpts(int argc, char *argv[]) {
|
|||
buildroot = optarg;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s: %s [-r %s] [-o %s] [%s...]\n", "Usage", argv[0],
|
||||
kprintf("%s: %s [-r %s] [-o %s] [%s...]\n", "Usage", argv[0],
|
||||
"BUILDROOT", "OUTPUT", "PATHSFILE");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (isempty(out)) fprintf(stderr, "need -o FILE"), exit(1);
|
||||
if (isempty(buildroot)) fprintf(stderr, "need -r o/$(MODE)"), exit(1);
|
||||
if (isempty(out)) kprintf("need -o FILE"), exit(1);
|
||||
if (isempty(buildroot)) kprintf("need -r o/$(MODE)"), exit(1);
|
||||
}
|
||||
|
||||
const char *StripExt(const char *s) {
|
||||
|
@ -352,7 +355,7 @@ bool HasSameContent(void) {
|
|||
s = GetFileSizeOrZero(out);
|
||||
if (s == appendz(bout).i) {
|
||||
if (s) {
|
||||
CHECK_NE(-1, (fd = open(out, O_RDONLY)));
|
||||
CHECK_NE(-1, (fd = open(out, O_RDONLY)), "open(%#s)", out);
|
||||
CHECK_NE(MAP_FAILED, (m = mmap(0, s, PROT_READ, MAP_SHARED, fd, 0)));
|
||||
r = !bcmp(bout, m, s);
|
||||
munmap(m, s);
|
||||
|
@ -394,7 +397,7 @@ int main(int argc, char *argv[]) {
|
|||
appendw(&bout, '\n');
|
||||
}
|
||||
/* if (!fileexists(out) || !HasSameContent()) { */
|
||||
CHECK_NE(-1, (fd = open(out, O_CREAT | O_WRONLY, 0644)));
|
||||
CHECK_NE(-1, (fd = open(out, O_CREAT | O_WRONLY, 0644)), "open(%#s)", out);
|
||||
CHECK_NE(-1, ftruncate(fd, appendz(bout).i));
|
||||
CHECK_NE(-1, xwrite(fd, bout, appendz(bout).i));
|
||||
CHECK_NE(-1, close(fd));
|
||||
|
|
82
tool/build/mkdir.c
Normal file
82
tool/build/mkdir.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
#if 0
|
||||
/*─────────────────────────────────────────────────────────────────╗
|
||||
│ To the extent possible under law, Justine Tunney has waived │
|
||||
│ all copyright and related or neighboring rights to this file, │
|
||||
│ as it is written in the following disclaimers: │
|
||||
│ • http://unlicense.org/ │
|
||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||
╚─────────────────────────────────────────────────────────────────*/
|
||||
#endif
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
|
||||
#define USAGE \
|
||||
" [-p] [-m MODE] DIR...\n\
|
||||
Utility for creating directories.\n\
|
||||
\n\
|
||||
FLAGS\n\
|
||||
\n\
|
||||
-h Help\n\
|
||||
-m MODE Octal mode\n\
|
||||
-p Make parent directories\n"
|
||||
|
||||
const char *prog;
|
||||
|
||||
wontreturn void PrintUsage(int rc, FILE *f) {
|
||||
fputs("Usage: ", f);
|
||||
fputs(prog, f);
|
||||
fputs(USAGE, f);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i, mode = 0755;
|
||||
int (*mkdirp)(const char *, unsigned) = mkdir;
|
||||
prog = argc > 0 ? argv[0] : "mkdir.com";
|
||||
|
||||
while ((i = getopt(argc, argv, "?hpm:")) != -1) {
|
||||
switch (i) {
|
||||
case 'p':
|
||||
mkdirp = makedirs;
|
||||
break;
|
||||
case 'm':
|
||||
mode = strtol(optarg, 0, 8);
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
PrintUsage(0, stdout);
|
||||
default:
|
||||
PrintUsage(EX_USAGE, stderr);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind == argc) {
|
||||
fputs(prog, stderr);
|
||||
fputs(": missing argument\n", stderr);
|
||||
fputs("Try '", stderr);
|
||||
fputs(prog, stderr);
|
||||
fputs(" -h' for more information.\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = optind; i < argc; ++i) {
|
||||
if (mkdirp(argv[i], mode) == -1) {
|
||||
fputs(prog, stderr);
|
||||
fputs(": cannot create directory '", stderr);
|
||||
fputs(argv[i], stderr);
|
||||
fputs("' ", stderr);
|
||||
fputs(strerdoc(errno), stderr);
|
||||
fputc('\n', stderr);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
37
tool/build/pwd.c
Normal file
37
tool/build/pwd.c
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Tool for printing current directory.
|
||||
*/
|
||||
|
||||
char path[PATH_MAX];
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char *p;
|
||||
if ((p = getcwd(path, sizeof(path)))) {
|
||||
fputs(p, stdout);
|
||||
fputc('\n', stdout);
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
103
tool/build/rm.c
Normal file
103
tool/build/rm.c
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
|
||||
#define USAGE \
|
||||
" FILE...\n\
|
||||
\n\
|
||||
SYNOPSIS\n\
|
||||
\n\
|
||||
Removes Files\n\
|
||||
\n\
|
||||
FLAGS\n\
|
||||
\n\
|
||||
-?\n\
|
||||
-h help\n\
|
||||
-f force\n\
|
||||
\n"
|
||||
|
||||
bool force;
|
||||
const char *prog;
|
||||
|
||||
wontreturn void PrintUsage(int rc, FILE *f) {
|
||||
fputs("usage: ", f);
|
||||
fputs(prog, f);
|
||||
fputs(USAGE, f);
|
||||
exit(rc);
|
||||
}
|
||||
|
||||
void GetOpts(int argc, char *argv[]) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "?hf")) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
force = true;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
PrintUsage(EXIT_SUCCESS, stdout);
|
||||
default:
|
||||
PrintUsage(EX_USAGE, stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Remove(const char *path) {
|
||||
const char *s;
|
||||
if (!force && access(path, W_OK) == -1) goto OnFail;
|
||||
if (unlink(path) == -1) goto OnFail;
|
||||
return;
|
||||
OnFail:
|
||||
if (force && errno == ENOENT) return;
|
||||
s = strerdoc(errno);
|
||||
fputs(prog, stderr);
|
||||
fputs(": cannot remove '", stderr);
|
||||
fputs(path, stderr);
|
||||
fputs("': ", stderr);
|
||||
fputs(s, stderr);
|
||||
fputs("\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
prog = argc > 0 ? argv[0] : "rm.com";
|
||||
|
||||
if (argc < 2) {
|
||||
fputs(prog, stderr);
|
||||
fputs(": missing operand\n"
|
||||
"Try 'rm -h' for more information.\n",
|
||||
stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
GetOpts(argc, argv);
|
||||
|
||||
for (i = optind; i < argc; ++i) {
|
||||
Remove(argv[i]);
|
||||
}
|
||||
}
|
|
@ -305,6 +305,7 @@ void Recv(void *output, size_t outputsize) {
|
|||
// pass along eof condition to zlib
|
||||
INFOF("mbedtls_ssl_read");
|
||||
received = mbedtls_ssl_read(&ezssl, buf, sizeof(buf));
|
||||
if (!received) TlsDie("got unexpected eof", received);
|
||||
if (received < 0) TlsDie("read failed", received);
|
||||
// decompress packet completely
|
||||
// into a dynamical size buffer
|
||||
|
|
46
tool/build/touch.c
Normal file
46
tool/build/touch.c
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Command for updating timestamps on files.
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i;
|
||||
const char *s, *prog;
|
||||
prog = argc > 0 ? argv[0] : "touch.com";
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (touch(argv[i], 0666) == -1) {
|
||||
s = strerdoc(errno);
|
||||
fputs(prog, stderr);
|
||||
fputs(": cannot touch '", stderr);
|
||||
fputs(argv[i], stderr);
|
||||
fputs("': ", stderr);
|
||||
fputs(s, stderr);
|
||||
fputs("\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
89
tool/build/unbundle.c
Normal file
89
tool/build/unbundle.c
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/musl/ftw.h"
|
||||
|
||||
const char *prog;
|
||||
char tmpdir[PATH_MAX];
|
||||
char binpath[PATH_MAX];
|
||||
|
||||
bool IsDirectory(const char *path) {
|
||||
int e;
|
||||
bool res;
|
||||
struct stat st;
|
||||
e = errno;
|
||||
res = stat(path, &st) != -1 && S_ISDIR(st.st_mode);
|
||||
errno = e;
|
||||
return res;
|
||||
}
|
||||
|
||||
void Execute(char *argv[]) {
|
||||
int ws;
|
||||
if (!vfork()) {
|
||||
execv(argv[0], argv);
|
||||
_Exit(127);
|
||||
}
|
||||
wait(&ws);
|
||||
if (!WIFEXITED(ws) || WEXITSTATUS(ws)) {
|
||||
fputs(argv[0], stderr);
|
||||
fputs(": command failed\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int Visit(const char *fpath, const struct stat *sb, int tflag,
|
||||
struct FTW *ftwbuf) {
|
||||
if (tflag == FTW_F && endswith(fpath, ".gz")) {
|
||||
Execute((char *[]){"build/bootstrap/gzip.com", "-d", fpath, 0});
|
||||
strcpy(binpath, fpath);
|
||||
binpath[strlen(binpath) - 3] = 0;
|
||||
chmod(binpath, 0755);
|
||||
} else if (tflag == FTW_F && endswith(fpath, ".sym")) {
|
||||
strcpy(binpath, fpath);
|
||||
binpath[strlen(binpath) - 4] = 0;
|
||||
symlink(xslurp(fpath, 0), binpath);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (!IsLinux()) return 0;
|
||||
prog = argc > 0 ? argv[0] : "unbundle.com";
|
||||
if (IsDirectory("o/third_party/gcc")) return 0;
|
||||
makedirs("o/third_party", 0755);
|
||||
FormatInt32(stpcpy(tmpdir, "o/third_party/gcc."), getpid());
|
||||
Execute(
|
||||
(char *[]){"build/bootstrap/cp.com", "-r", "third_party/gcc", tmpdir, 0});
|
||||
if (nftw(tmpdir, Visit, 20, 0) == -1) {
|
||||
fputs(prog, stderr);
|
||||
fputs(": nftw failed: ", stderr);
|
||||
fputs(strerdoc(errno), stderr);
|
||||
fputs("\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
rename(tmpdir, "o/third_party/gcc");
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
|
@ -51,8 +52,8 @@ const char *path_prefix_;
|
|||
struct timespec timestamp;
|
||||
size_t kZipCdirHdrLinkableSizeBootstrap;
|
||||
|
||||
wontreturn void PrintUsage(int rc, FILE *f) {
|
||||
fprintf(f, "%s%s%s\n", "Usage: ", program_invocation_name,
|
||||
wontreturn void PrintUsage(int rc) {
|
||||
kprintf("%s%s%s\n", "Usage: ", program_invocation_name,
|
||||
" [-n] [-B] [-C INT] [-P PREFIX] [-o FILE] [-s SYMBOL] [-y YOINK] "
|
||||
"[FILE...]");
|
||||
exit(rc);
|
||||
|
@ -99,9 +100,9 @@ void GetOpts(int *argc, char ***argv) {
|
|||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
PrintUsage(EXIT_SUCCESS, stdout);
|
||||
PrintUsage(EXIT_SUCCESS);
|
||||
default:
|
||||
PrintUsage(EX_USAGE, stderr);
|
||||
PrintUsage(EX_USAGE);
|
||||
}
|
||||
}
|
||||
*argc -= optind;
|
||||
|
@ -137,7 +138,7 @@ void ProcessFile(struct ElfWriter *elf, const char *path) {
|
|||
if (S_ISDIR(st.st_mode)) {
|
||||
st.st_size = 0;
|
||||
if (!endswith(name, "/")) {
|
||||
name = gc(xasprintf("%s/", name));
|
||||
name = gc(xstrcat(name, '/'));
|
||||
}
|
||||
}
|
||||
elfwriter_zip(elf, name, name, strlen(name), map, st.st_size, st.st_mode,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue