mirror of
				https://github.com/jart/cosmopolitan.git
				synced 2025-10-25 18:50:57 +00:00 
			
		
		
		
	Add pipelining to cocmd
This commit is contained in:
		
							parent
							
								
									b4e38851ff
								
							
						
					
					
						commit
						aa34340f3d
					
				
					 4 changed files with 90 additions and 68 deletions
				
			
		|  | @ -1124,9 +1124,13 @@ static void SetPromises(const char *promises) { | ||||||
|  * OpenBSD just kills the process while logging a helpful message to |  * OpenBSD just kills the process while logging a helpful message to | ||||||
|  * /var/log/messages explaining which promise category you needed. |  * /var/log/messages explaining which promise category you needed. | ||||||
|  * |  * | ||||||
|  * By default exit and exit_group are always allowed. This is useful |  * By default exit() is allowed. This is useful for processes that | ||||||
|  * for processes that perform pure computation and interface with the |  * perform pure computation and interface with the parent via shared | ||||||
|  * parent via shared memory. |  * memory. On Linux we mean sys_exit (_Exit1), not sys_exit_group | ||||||
|  |  * (_Exit). The difference is effectively meaningless, since _Exit() | ||||||
|  |  * will attempt both. All it means is that, if you're using threads, | ||||||
|  |  * then a `pledge("", 0)` thread can't kill all your threads unless you | ||||||
|  |  * `pledge("stdio", 0)`. | ||||||
|  * |  * | ||||||
|  * Once pledge is in effect, the chmod functions (if allowed) will not |  * Once pledge is in effect, the chmod functions (if allowed) will not | ||||||
|  * permit the sticky/setuid/setgid bits to change. Linux will EPERM here |  * permit the sticky/setuid/setgid bits to change. Linux will EPERM here | ||||||
|  |  | ||||||
|  | @ -26,12 +26,6 @@ | ||||||
| #include "libc/sysv/consts/map.h" | #include "libc/sysv/consts/map.h" | ||||||
| #include "libc/sysv/consts/prot.h" | #include "libc/sysv/consts/prot.h" | ||||||
| 
 | 
 | ||||||
| static char *_stkbase; |  | ||||||
| 
 |  | ||||||
| __attribute__((__constructor__)) static void init(void) { |  | ||||||
|   _stkbase = (char *)kFixedmapStart; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * Allocates stack. |  * Allocates stack. | ||||||
|  * |  * | ||||||
|  | @ -47,13 +41,12 @@ __attribute__((__constructor__)) static void init(void) { | ||||||
|  */ |  */ | ||||||
| void *_mapstack(void) { | void *_mapstack(void) { | ||||||
|   char *p; |   char *p; | ||||||
|   if ((p = mmap(_stkbase, GetStackSize(), PROT_READ | PROT_WRITE, |   if ((p = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, | ||||||
|                 MAP_STACK | MAP_ANONYMOUS | MAP_FIXED, -1, 0)) != MAP_FAILED) { |                 MAP_STACK | MAP_ANONYMOUS, -1, 0)) != MAP_FAILED) { | ||||||
|     if (IsAsan()) { |     if (IsAsan()) { | ||||||
|       __asan_poison(p + GetStackSize() - 16, 16, kAsanStackOverflow); |       __asan_poison(p + GetStackSize() - 16, 16, kAsanStackOverflow); | ||||||
|       __asan_poison(p, 4096, kAsanStackOverflow); |       __asan_poison(p, 4096, kAsanStackOverflow); | ||||||
|     } |     } | ||||||
|     _stkbase += GetStackSize() * 4; |  | ||||||
|     return p; |     return p; | ||||||
|   } else { |   } else { | ||||||
|     return 0; |     return 0; | ||||||
|  |  | ||||||
|  | @ -328,7 +328,6 @@ TEST(pledge, msyscall) { | ||||||
| TEST(pledge, chmod_ignoresDangerBits) { | TEST(pledge, chmod_ignoresDangerBits) { | ||||||
|   if (IsOpenbsd()) return;  // b/c testing linux bpf
 |   if (IsOpenbsd()) return;  // b/c testing linux bpf
 | ||||||
|   int ws, pid; |   int ws, pid; | ||||||
|   struct stat st; |  | ||||||
|   ASSERT_SYS(0, 3, creat("foo", 0644)); |   ASSERT_SYS(0, 3, creat("foo", 0644)); | ||||||
|   ASSERT_NE(-1, (pid = fork())); |   ASSERT_NE(-1, (pid = fork())); | ||||||
|   if (!pid) { |   if (!pid) { | ||||||
|  | @ -390,6 +389,10 @@ TEST(pledge, open_cpath) { | ||||||
|   if (!pid) { |   if (!pid) { | ||||||
|     ASSERT_SYS(0, 0, pledge("stdio cpath", 0)); |     ASSERT_SYS(0, 0, pledge("stdio cpath", 0)); | ||||||
|     ASSERT_SYS(0, 3, open("foo", O_WRONLY | O_TRUNC | O_CREAT, 0644)); |     ASSERT_SYS(0, 3, open("foo", O_WRONLY | O_TRUNC | O_CREAT, 0644)); | ||||||
|  |     ASSERT_SYS(0, 0, fstat(3, &st)); | ||||||
|  |     ASSERT_EQ(0100644, st.st_mode); | ||||||
|  |     // make sure open() can't apply the setuid bit
 | ||||||
|  |     ASSERT_SYS(EPERM, -1, open("bar", O_WRONLY | O_TRUNC | O_CREAT, 04644)); | ||||||
|     _Exit(0); |     _Exit(0); | ||||||
|   } |   } | ||||||
|   EXPECT_NE(-1, wait(&ws)); |   EXPECT_NE(-1, wait(&ws)); | ||||||
|  |  | ||||||
|  | @ -38,41 +38,79 @@ | ||||||
| 
 | 
 | ||||||
| char *p; | char *p; | ||||||
| char *q; | char *q; | ||||||
|  | size_t n; | ||||||
| char *cmd; | char *cmd; | ||||||
| char *args[8192]; | char *args[8192]; | ||||||
| const char *prog; | const char *prog; | ||||||
| char argbuf[ARG_MAX]; | char argbuf[ARG_MAX]; | ||||||
| bool unsupported[256]; | bool unsupported[256]; | ||||||
| 
 | 
 | ||||||
|  | void Write(const char *s, ...) { | ||||||
|  |   va_list va; | ||||||
|  |   va_start(va, s); | ||||||
|  |   do { | ||||||
|  |     write(2, s, strlen(s)); | ||||||
|  |   } while ((s = va_arg(va, const char *))); | ||||||
|  |   va_end(va); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| wontreturn void UnsupportedSyntax(unsigned char c) { | wontreturn void UnsupportedSyntax(unsigned char c) { | ||||||
|  |   char cbuf[2]; | ||||||
|   char ibuf[13]; |   char ibuf[13]; | ||||||
|  |   cbuf[0] = c; | ||||||
|  |   cbuf[1] = 0; | ||||||
|   FormatOctal32(ibuf, c, true); |   FormatOctal32(ibuf, c, true); | ||||||
|   fputs(prog, stderr); |   Write(prog, ": unsupported shell syntax '", cbuf, "' (", ibuf, "): ", cmd, | ||||||
|   fputs(": unsupported shell syntax '", stderr); |         "\n", 0); | ||||||
|   fputc(c, stderr); |   exit(4); | ||||||
|   fputs("' (", stderr); | } | ||||||
|   fputs(ibuf, stderr); | 
 | ||||||
|   fputs("): ", stderr); | wontreturn void SysExit(int rc, const char *call, const char *thing) { | ||||||
|   fputs(cmd, stderr); |   int err; | ||||||
|   fputs("\n", stderr); |   char ibuf[12]; | ||||||
|   exit(1); |   const char *estr; | ||||||
|  |   err = errno; | ||||||
|  |   FormatInt32(ibuf, err); | ||||||
|  |   estr = strerdoc(err); | ||||||
|  |   if (!estr) estr = "EUNKNOWN"; | ||||||
|  |   Write(thing, ": ", call, "() failed: ", estr, " (", ibuf, ")\n", 0); | ||||||
|  |   exit(rc); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Open(const char *path, int fd, int flags) { | void Open(const char *path, int fd, int flags) { | ||||||
|   const char *err; |   const char *err; | ||||||
|   close(fd); |   close(fd); | ||||||
|   if (open(path, flags, 0644) == -1) { |   if (open(path, flags, 0644) == -1) { | ||||||
|     err = strerdoc(errno); |     SysExit(7, "open", path); | ||||||
|     fputs(prog, stderr); |  | ||||||
|     fputs(": failed to open '", stderr); |  | ||||||
|     fputs(path, stderr); |  | ||||||
|     fputs("': ", stderr); |  | ||||||
|     fputs(err, stderr); |  | ||||||
|     fputs("\n", stderr); |  | ||||||
|     exit(1); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | wontreturn void Exec(void) { | ||||||
|  |   const char *s; | ||||||
|  |   if (!n) { | ||||||
|  |     Write(prog, ": error: too few args\n", 0); | ||||||
|  |     exit(5); | ||||||
|  |   } | ||||||
|  |   execv(args[0], args); | ||||||
|  |   SysExit(127, "execve", args[0]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Pipe(void) { | ||||||
|  |   int pid, pfds[2]; | ||||||
|  |   if (pipe2(pfds, O_CLOEXEC)) { | ||||||
|  |     SysExit(8, "pipe2", prog); | ||||||
|  |   } | ||||||
|  |   if ((pid = vfork()) == -1) { | ||||||
|  |     SysExit(9, "vfork", prog); | ||||||
|  |   } | ||||||
|  |   if (!pid) { | ||||||
|  |     dup2(pfds[1], 1); | ||||||
|  |     Exec(); | ||||||
|  |   } | ||||||
|  |   dup2(pfds[0], 0); | ||||||
|  |   n = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| char *Tokenize(void) { | char *Tokenize(void) { | ||||||
|   int t; |   int t; | ||||||
|   char *r; |   char *r; | ||||||
|  | @ -97,6 +135,14 @@ char *Tokenize(void) { | ||||||
|         } else if (*p == '\\') { |         } else if (*p == '\\') { | ||||||
|           if (!p[1]) UnsupportedSyntax(*p); |           if (!p[1]) UnsupportedSyntax(*p); | ||||||
|           *q++ = *++p; |           *q++ = *++p; | ||||||
|  |         } else if (*p == '|') { | ||||||
|  |           if (q > r) { | ||||||
|  |             *q = 0; | ||||||
|  |             return r; | ||||||
|  |           } else { | ||||||
|  |             Pipe(); | ||||||
|  |             ++p; | ||||||
|  |           } | ||||||
|         } else { |         } else { | ||||||
|           *q++ = *p; |           *q++ = *p; | ||||||
|         } |         } | ||||||
|  | @ -104,8 +150,8 @@ char *Tokenize(void) { | ||||||
| 
 | 
 | ||||||
|       case STATE_STR: |       case STATE_STR: | ||||||
|         if (!*p) { |         if (!*p) { | ||||||
|           fputs("cmd: error: unterminated string\n", stderr); |           Write("cmd: error: unterminated string\n", 0); | ||||||
|           exit(1); |           exit(6); | ||||||
|         } |         } | ||||||
|         if (*p == '\'') { |         if (*p == '\'') { | ||||||
|           t = STATE_SHELL; |           t = STATE_SHELL; | ||||||
|  | @ -121,8 +167,8 @@ char *Tokenize(void) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int main(int argc, char *argv[]) { | int main(int argc, char *argv[]) { | ||||||
|   char *s, *arg; |   char *arg; | ||||||
|   size_t i, j, n; |   size_t i, j; | ||||||
|   prog = argc > 0 ? argv[0] : "cocmd.com"; |   prog = argc > 0 ? argv[0] : "cocmd.com"; | ||||||
| 
 | 
 | ||||||
|   for (i = 1; i < 32; ++i) { |   for (i = 1; i < 32; ++i) { | ||||||
|  | @ -136,7 +182,6 @@ int main(int argc, char *argv[]) { | ||||||
|   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; | ||||||
|  | @ -147,24 +192,19 @@ int main(int argc, char *argv[]) { | ||||||
|   unsupported['!'] = true; |   unsupported['!'] = true; | ||||||
| 
 | 
 | ||||||
|   if (argc != 3) { |   if (argc != 3) { | ||||||
|     fputs(prog, stderr); |     Write(prog, ": error: wrong number of args\n", 0); | ||||||
|     fputs(": error: wrong number of args\n", stderr); |     exit(10); | ||||||
|     return 1; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   if (strcmp(argv[1], "-c")) { |   if (strcmp(argv[1], "-c")) { | ||||||
|     fputs(prog, stderr); |     Write(prog, ": error: argv[1] should -c\n", 0); | ||||||
|     fputs(": error: argv[1] should -c\n", stderr); |     exit(11); | ||||||
|     return 1; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   p = cmd = argv[2]; |   p = cmd = argv[2]; | ||||||
|   if (strlen(cmd) >= ARG_MAX) { |   if (strlen(cmd) >= ARG_MAX) { | ||||||
|     fputs(prog, stderr); |     Write(prog, ": error: cmd too long: ", cmd, "\n", 0); | ||||||
|     fputs(": error: cmd too long: ", stderr); |     exit(12); | ||||||
|     fputs(cmd, stderr); |  | ||||||
|     fputs("\n", stderr); |  | ||||||
|     return 1; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   n = 0; |   n = 0; | ||||||
|  | @ -188,31 +228,13 @@ int main(int argc, char *argv[]) { | ||||||
|         Open(arg + 1, 0, O_RDONLY); |         Open(arg + 1, 0, O_RDONLY); | ||||||
|       } else { |       } else { | ||||||
|         args[n++] = arg; |         args[n++] = arg; | ||||||
|  |         args[n] = 0; | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       fputs(prog, stderr); |       Write(prog, ": error: too many args\n", 0); | ||||||
|       fputs(": error: too many args\n", stderr); |       exit(13); | ||||||
|       return 1; |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   if (!n) { |   Exec(); | ||||||
|     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; |  | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue