编译内核以增加命令行最大长度

编译内核以增加命令行最大长度

跟进https://stackoverflow.com/questions/14176089/system-command-line-max-length-in-perl,其中表示 exec/命令行参数的最大长度由 控制ARG_MAX

所以我想增加这样的命令行最大长度,似乎重新编译内核是唯一的选择。很好。但是我的问题是关于ARG_MAX,因为每个人都说这是需要增加的,但我从http://www.in-ulm.de/~mascheck/various/argmax/#linux那,

ARG_MAX在 2.6.23 之前的内核代码中未使用。在 Linux 2.6.23 之后,ARG_MAX不再进行硬编码。

那么ARG_MAX不再使用了吗?那么如何增加 exec/命令行参数的最大长度?因为我的命令行最大长度被限制为比我喜欢的更小的值。

谢谢

答案1

由于 linux-2.6.23ARG_MAX不一定是预先确定的常数,因此允许参数的总大小最多为堆栈大小的 1/4(请参阅ulimit -s,堆栈大小以 kB 为单位;但/proc/1/limits更明确)。但是,ARG_MAX不仅仅是针对进程参数,它还包含环境变量,您可能需要将其考虑在内。

POSIX 定义了什么ARG_MAX含义以及可接受的下限(_POSIX_ARG_MAX4096)。其静态值(历史上)可通过#define系统标头中的它也在 Linux 内核头文件中设置。其有效值可通过以下方式获得:sysconf()getconf ARG_MAX从命令行。

如果你检查 glibc 标头(sys/param.h),你会看到以下内容:

/* The kernel headers defines ARG_MAX.  The value is wrong, though.  */
#ifdef __undef_ARG_MAX
# undef ARG_MAX
# undef __undef_ARG_MAX
#endif

这是来自 glibc-2.17 的,它出现在 2.11 (2009) 左右,第一次支持它可追溯到 2.8 (2008),在 2.14 (2011) 之前,上述逻辑中有一个错误,导致它无法按预期工作。目的是确保ARG_MAX如果它不是常量,则未定义,因此程序应该依赖sysconf()。(即使它已定义,也可能只是一个保证的下限,程序应该使用它sysconf()来确定变量的上限,请参阅sysconf(3)

gcc您可以使用(仅限、bash/zsh语法)检查 C 编译器看到的内容:

$ gcc -E -dM -x c <(echo "#include <sys/param.h>") | fgrep ARG
#define ARG_MAX 131072
#define NCARGS ARG_MAX
#define _POSIX_ARG_MAX 4096

以上输出来自旧系统 (2.6.27),该系统具有内核支持,但没有完整的运行时 (glibc 支持)。如果您看不到任何ARG_MAX行,则这不是预先确定的限制,您应该使用 (sysconf) getconf ARG_MAX

$ getconf ARG_MAX
2097152

检查支持情况的一个有用方法也是:

$ xargs --show-limits < /dev/null
Your environment variables take up 2542 bytes
POSIX upper limit on argument length (this system): 2092562
POSIX smallest allowable upper limit on argument length (all systems): 4096
Maximum length of command we could actually use: 2090020
Size of command buffer we are actually using: 131072

这是来自具有更高限制的 linux-2.6.37/glib-2.13 系统。请注意输出的最后一行,xargs默认(构建时)为“合理”限制,可能是因为它启动的任何进程都无法处理非常大的值。您可以在运行时使用该-s选项修改它。此外,如果您有ulimit -s有效的,这些数字可能会更低。这应该自 findutils-4.3.9 (2007) 起可正常工作。另请参阅:http://www.gnu.org/software/coreutils/faq/coreutils-faq.html#Argument-list-too-long

检查 perl:

% perl -MPOSIX -e 'print ARG_MAX . "\n"';
131072

以上内容来自旧系统,新系统应该显示:

% perl -MPOSIX -e 'print ARG_MAX . "\n"';
Your vendor has not defined POSIX macro ARG_MAX, used at -e line 1

总结一下:

  • 如果您运行的是 2.6.23 之后的内核,内核将允许在创建进程时传递更大的大小。这是一个必要但不充分健康)状况。
  • 父进程不得强制执行任何不正确的运行时限制(例如使用硬编码ARG_MAX),而应检查exec() E2BIG错误代码,并且应该sysconf(_SC_ARG_MAX)如果需要的话
  • 子进程不得强制执行任何不正确的运行时限制,特别是其处理内核提供的参数的启动代码不得具有不正确的硬编码限制(例如,在设置argc运行argc时使用的环境区域时)。这通常在 libc(glibc)中完成。
  • 对于父进程和子进程,您可能还需要从 libc(或同等版本)配置和构建时间支持。对于 glibc,这至少需要 glibc-2.8(尽管应该可以解决这个问题,但可能并不简单或干净)

问题组合是更新的(linux >=2.6.23)内核,但缺少或怀疑有 glibc 支持(glibc<=2.14)

如果你运行的是旧内核,首先确保你的供应商没有反向移植该功能。否则,原则上你可以修改内核限制并重新编译,您可能还需要修改至少一些系统标题或源代码以获得工作支持。


程序应该能够处理任意值,但情况并非总是如此:http://pubs.opengroup.org/onlinepubs/009695399/basedefs/limits.h.html

应用程序不应该为限制假设任何特定的值。[...] 但应注意,列出的许多限制并不是不变的,并且在运行时,限制的值可能与此标头中给出的值不同,原因如下:

  • 该限制与路径名有关。
  • 编译机器和运行机器之间的限制不同。

由于这些原因,应用程序可以使用 fpathconf()、pathconf() 和 sysconf() 函数来确定运行时限制的实际值。

相关内容