set prototyped hdr nc,exec_attr mem exception.name,_exception.name math.h lib setreuid,setregid,nice,fork,spawnveg,fchdir lib pathnative,pathposix,uwin_path,uwin_unpath,fts_notify lib memcntl sys/mman.h lib getexecuser,free_execattr exec_attr.h -lsecdb reference unistd.h extern nice int (int) extern setreuid int (uid_t,uid_t) extern setregid int (gid_t,gid_t) tst note{ determining extra bytes per argument for arguments list }end output{ /* * Figure out if this OS requires extra bytes per argument * in the arguments list of a process. * Outputs an appropriate #define ARG_EXTRA_BYTES. * Without this, 'command -x' failed with E2BIG on macOS, Linux and Solaris * even if all the arguments should fit in ARG_MAX based on their length. */ /* AST includes */ #include #include #include #include #include /* Standard includes */ #include int main(int argc,char *argv[]) { int extra_bytes = 0, envlen, argmax, i; pid_t childpid; error_info.id="ARG_EXTRA_BYTES test (parent)"; while(1) { envlen = 0; for(i=0; argv[i]; i++) envlen += strlen(argv[i]) + 1 + extra_bytes; envlen += 1 + extra_bytes; /* final null element */ for(i=0; environ[i]; i++) envlen += strlen(environ[i]) + 1 + extra_bytes; envlen += 1 + extra_bytes; /* final null element */ argmax = (int)astconf_long(CONF_ARG_MAX) - envlen; if (argmax < 2048) { error(ERROR_ERROR|2, "argmax too small"); return 1; } if(!(childpid = fork())) { /* child */ int bytec; error_info.id="ARG_EXTRA_BYTES test (child)"; argv = (char **)stakalloc((argmax / 2 + 1) * sizeof(char*)); argc = bytec = 0; while(bytec < argmax) { if(argc==0) argv[argc] = "/usr/bin/env"; else if(argc==1) argv[argc] = "true"; else argv[argc] = "x"; /* also add 1 for terminating zero byte */ bytec += strlen(argv[argc]) + 1 + extra_bytes; argc++; } argv[argc] = (char*)0; if(execve(argv[0], argv, environ) < 0) { if(errno == E2BIG) return 1; else { error(ERROR_SYSTEM|2, "execve failed"); return 2; } } error(ERROR_SYSTEM|2, "[BUG] we should never get here!"); return 2; } else { /* parent */ int exitstatus; if (waitpid(childpid,&i,0) < 0) { error(ERROR_SYSTEM|2, "waitpid failed"); return 1; } if (!WIFEXITED(i) || (exitstatus = WEXITSTATUS(i)) > 1) { error(ERROR_ERROR|2, "child process exited abnormally"); return 1; } if (exitstatus == 0) break; /* yay :) */ extra_bytes++; if (extra_bytes > 256) { error(ERROR_ERROR|2, "giving up"); return 1; } } } sfprintf(sfstdout, "#define ARG_EXTRA_BYTES\t%d\t/* extra bytes per argument for arguments list */\n", extra_bytes); return 0; } }end fail{ echo "#define ARG_EXTRA_BYTES 16 /* BUG: test failed; assuming 16 */" }end