GNU/Linux >> Znalost Linux >  >> Linux

ps:celý příkaz je příliš dlouhý

V systému Linux pomocí ps od procps(-ng) :

ps -fwwp 2755

Ve verzích Linuxu starších než 4.2 je to stále omezeno (kernel (/proc/2755/cmdline ) až 4k) a nemůžete získat více, než když požádáte proces, aby vám to řekl, nebo použijete debugger.

$ sh -c 'sleep 1000' $(seq 4000) &
[1] 31149
$ gdb -p $! /bin/sh
[...]
Attaching to program: /bin/dash, process 31149
[...]
(gdb) bt
#0  0x00007f40d11f40aa in wait4 () at ../sysdeps/unix/syscall-template.S:81
[...]
#7  0x00007f40d115c995 in __libc_start_main (main=0x4022c0, argc=4003, ubp_av=0x7fff5b9f5a88, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fff5b9f5a78)
at libc-start.c:260
#8  0x00000000004024a5 in ?? ()
#9  0x00007fff5b9f5a78 in ?? ()
#10 0x0000000000000000 in ?? ()
(gdb) frame 7
#7  0x00007f40d115c995 in __libc_start_main (main=0x4022c0, argc=4003, ubp_av=0x7fff5b9f5a88, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fff5b9f5a78)
at libc-start.c:260
(gdb) x/4003s *ubp_av
0x7fff5b9ff83e: "sh"
0x7fff5b9ff841: "-c"
0x7fff5b9ff844: "sleep 1000"
0x7fff5b9ff84f: "1"
0x7fff5b9ff851: "2"
[...]
0x7fff5ba04212: "3999"
0x7fff5ba04217: "4000"

Chcete-li vytisknout 4. argument s až 5000 znaky:

(gdb) set print elements 5000
(gdb) p ubp_av[3]

Pokud chcete něco nevtíravého, můžete zkusit získat informace z /proc/2755/mem (všimněte si, že pokud kernel.yama.ptrace_scope není nastaveno na 0, budete k tomu potřebovat oprávnění superuživatele). Toto níže pro mě funguje (vytiskne všechny argumenty a proměnné prostředí), ale podle mého názoru neexistuje žádná velká záruka (chyby a neočekávané vstupy jsou ponechány jako cvičení pro čtenáře):

$ perl -e '$p=shift;open MAPS, "/proc/$p/maps";
          ($m)=grep /\[stack\]/, <MAPS>;
          ($a,$b)=map hex, $m =~ /[\da-f]+/g;
          open MEM, "/proc/$p/mem" or die "open mem: $!";
          seek MEM,$a,0; read MEM, $c,$b-$a;
          print((split /\0{2,}/,$c)[-1])' "$!" | tr \\0 \\n | head
sh
-c
sleep 1000
1
2
3
4
5
6
7

(nahraďte "$!" s ID procesu). Výše uvedené využívá skutečnosti, že Linux vkládá řetězce, na které ukazuje argv[] , envp[] a spuštěný název souboru ve spodní části zásobníku procesu.

Výše uvedené hledá v tomto zásobníku nejspodnější řetězec mezi dvěma sadami dvou nebo více po sobě jdoucích bajtů NUL. Nefunguje to, pokud je některý z argumentů nebo řetězců env prázdný, protože pak budete mít uprostřed těchto argv nebo envp sekvenci 2 bajtů NUL. Také nevíme, kde končí řetězce argv a kde začínají řetězce envp.

Řešením by bylo upřesnit tuto heuristiku tím, že se zpětně podíváme na skutečný obsah argv[] (ukazatele). Toto níže funguje alespoň na architektuře i386 a amd64 pro spustitelné soubory ELF:

perl -le '$p=shift;open MAPS, "/proc/$p/maps";
      ($m)=grep /\[stack\]/, <MAPS>;
      ($a,$b)=map hex, $m =~ /[\da-f]+/g;
      open MEM, "/proc/$p/mem" or die "open mem: $!";
      seek MEM,$a,0; read MEM, $c,$b-$a;
      $c =~ /.*\0\0\K[^\0].*\0[^\0]*$/s;
      @a=unpack"L!*",substr$c,0,$-[0];
      for ($i = $#a; $i >=0 && $a[$i] != $a+$-[0];$i--) {}
      for ($i--; $i >= 0 && ($a[$i]>$a || $a[$i]==0); $i--) {}
      $argc=$a[$i++];
      print for unpack"(Z*)$argc",substr$c,$a[$i]-$a;' "$!"

V zásadě to dělá totéž jako výše, ale jakmile najde první řetězec argv[] (nebo alespoň jeden z argv[] nebo envp[] řetězce, pokud jsou prázdné), zná svou adresu, takže hledá ukazatel se stejnou hodnotou zpět v horním zbytku zásobníku. Pak se dívá zpět, dokud nenajde číslo, které nemůže být ukazatelem na ně, a to je argc . Další celé číslo je pak argv[0] . A znát argv[0] a argc , může zobrazit seznam argumentů.

To nefunguje, pokud proces zapsal do svého argv[] možná přepíše některé oddělovače NUL nebo pokud argc je 0 (argc je obecně alespoň 1, aby zahrnoval argv[0] ), ale měl by fungovat v obecném případě alespoň pro spustitelné soubory ELF.

Ve verzi 4.2 a novějších /proc/<pid>/cmdline již není zkrácen, ale ps sám má maximální šířku displeje 128 kB.


Přidejte jeden nebo dva -w vlajky. Dělá to výstup širší. např. ps auxww .


V jádře Linuxu 4.2 a novějším /proc/<pid>/cmdline již není zkrácen a následující funguje dobře:

xargs -0 printf '%s\n' < /proc/2755/cmdline

Linux
  1. Proč dlouhé zpoždění poté, co příkaz nebyl nalezen?

  2. Ubuntu – seznam argumentů je příliš dlouhý?

  3. Linuxový příkaz mv

  1. Linux du command

  2. Linuxový ip příkaz

  3. Linux cd příkaz

  1. Chyba SFTP Přijatá zpráva je příliš dlouhá

  2. Chyba příliš dlouhého seznamu argumentů pro příkazy rm, cp, mv

  3. Intermittent OSError:[Errno 7] Příliš dlouhý seznam argumentů s krátkým příkazem (~125 znaků)