getconf ARG_MAX # Mac OS X 10.6.7: 262144 bytes sysctl -n kern.argmax # get the (rough) maximum number of bytes for an argument list in the current shell # uses command line tools only; for a C version see argmax.c below # cf. http://www.in-ulm.de/~mascheck/various/argmax/ ( argmaxbytes="$(expr $(getconf ARG_MAX) - $(env | wc -c) - $(env | wc -l) \* 4 - 2048)" printf '\n%s\n\n' "argmaxbytes: $argmaxbytes" bash -c ':' _ $(jot -n -s '' ${argmaxbytes} 1 1) printf '%s\n\n' "exit status: $?" ) # get the exact maximum number of bytes for an argument list in the current shell # see also argmax.c below ( exec 2> >(nl -n ln) exitval=1 argmaxbytes=$(getconf ARG_MAX) until [[ $exitval -eq 0 ]]; do bash -c ':' _ $(jot -n -s '' ${argmaxbytes} 1 1) exitval=$? (( argmaxbytes = argmaxbytes - 1 )) done (( argmaxbytes = argmaxbytes + 1 )) printf '\n%s\n' "argmaxbytes: $argmaxbytes" printf '\n%s\n' "test 1 using argmaxbytes:" bash -c ':' _ $(jot -n -s '' ${argmaxbytes} 1 1) echo "exit status: $?" printf '\n%s\n' "test 2 using argmaxbytes + 1:" (( argmaxbytes = argmaxbytes + 1 )) bash -c ':' _ $(jot -n -s '' ${argmaxbytes} 1 1) echo "exit status: $?" )
argmax.c
/* argmax - get the maximum number of bytes for an argument list in the current shell References: - man execve - http://www.in-ulm.de/~mascheck/various/argmax/ - http://man.yolinux.com/cgi-bin/man2html?cgi_command=execve - http://www.semicomplete.com/blog/geekery/shebang-fix.html - http://semicomplete.googlecode.com/svn/codesamples/shebang.c compile with: gcc -O3 -Wall -Wextra -Werror -ansi -pedantic -std=c99 -o argmax argmax.c command line tests: getconf ARG_MAX # Mac OS X 10.6.7: 262144 bytes sysctl -n kern.argmax # enable "for debugging only" code in C source code ./argmax echo 5 1>/dev/null ./argmax "printf '%s\n'" 5 1>/dev/null ./argmax echo $(getconf ARG_MAX) 1>/dev/null # cf. http://www.in-ulm.de/~mascheck/various/argmax/ ( argmaxbytes="$(expr $(getconf ARG_MAX) - $(env | wc -c) - $(env | wc -l) \* 4 - 2048)" printf '\n%s\n\n' "argmaxbytes: $argmaxbytes" ./argmax echo "${argmaxbytes}" 1>/dev/null printf '%s\n\n' "exit status: $?" ) # get the exact maximum number of bytes for an argument list in the current shell ( exec 2> >(nl -n ln) exitval=1 argmaxbytes=$(getconf ARG_MAX) until [[ $exitval -eq 0 ]]; do ./argmax echo "$argmaxbytes" 1>/dev/null exitval=$? (( argmaxbytes = argmaxbytes - 1 )) done (( argmaxbytes = argmaxbytes + 1 )) printf '\n%s\n' "argmaxbytes: $argmaxbytes" printf '\n%s\n' "test 1 using argmaxbytes:" ./argmax echo "$argmaxbytes" 1>/dev/null; echo "exit status: $?" printf '\n%s\n' "test 2 using argmaxbytes + 1:" ./argmax echo $((argmaxbytes + 1)) 1>/dev/null; echo "exit status: $?" ) */ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/wait.h> char *const *environ; int main(int argc, char **argv) { if (argc != 3) return 1; int i=0, j=0, bytes=0, idx=0; bytes = atoi(argv[2]); // create a character string containing: cmd + 1 space + args + '\0' // + 2 for added space and final null byte '\0' // example: // "./argmax echo 5 1>/dev/null" on the command line will be converted into: // char cmd[11] = {'e', 'c', 'h', 'o', ' ', '1', '1', '1', '1', '1', '\0' }; char cmd[strlen(argv[1]) + bytes + 2]; // create char array with command as argv[1] + one space idx=-1; for (i = 1; i < 2; i++) { for (j = 0; argv[i][j]; j++) { cmd[idx+=1]=argv[i][j]; } cmd[idx+=1]='\x20'; } idx=idx; for (i = 1; i <= bytes; i++) { cmd[idx+=1] = '1'; } cmd[idx+=1]='\0'; // add a final zero byte '\0' /* // for debugging only for (i = 0; cmd[i]; i++) { fprintf(stderr, "%i: %c\n", i, cmd[i]); } if (cmd[idx+=1] == '\0') fprintf(stderr, "%i: %s\n", i, "'\\0'");; fprintf(stderr, "sizeof(cmd): %zu\n", sizeof(cmd)); fprintf(stderr, "last array index: %i\n", idx); //fprintf(stderr, "cmd: %s\n", cmd); */ char *newargv[4] = {0}; newargv[0] = "/bin/sh"; newargv[1] = "-c"; newargv[2] = cmd; newargv[3] = 0; execve("/bin/sh", newargv, environ); perror("execve"); /* execve() only returns on error */ exit(errno); /* // fork-exec alternative int status = 0; if(!fork()) // run child { execve("/bin/sh", newargv, environ); perror("execve"); /* execve() only returns on error */ //printf("errno: %i\n", errno); _exit(errno); } wait(&status); //fprintf(stderr, "child's exit code: %d\n", WEXITSTATUS(status)); exit(WEXITSTATUS(status)); */ }