Fórum Root.cz
Hlavní témata => Software => Téma založeno: Ħαℓ₸℮ℵ ␏⫢ ⦚ 05. 11. 2025, 23:48:59
-
jak zachránit historii z běžícího bashe ? Ten bash byl spuštěn v době dřív kdy načetl histfile z dřívějška. Tudíž v něm je otisk history . Nyní je $HISTFILE přepsaný. Bohužel aktuální bash skončil.
0. ten bash proces stále beží, loginctl ho má pod sebou v exited session která šla přes ssh. asi má uzavřené IO. (exited asi 2 dny) ale pořád visí
metoda 1. Udělal jsem si gcore PID a přes strings/nano/less vidím položky historie=částečný úspěch ale v strings roztroušené a v různém pořadí asi a uvozené stringy číslem unix timesamptu #17....... (což popírá, že jsou roztroušené v jiném pořadí), nano zase mám spoustu balastu, nonprintable chars a taky nevidím vše pohromadě.
..... ls -l /proc/PID/fd ukazuje u 0 1 2 položek cíl pts/1 (deleted) je to problém - heknout se na stdin stdout když proc fd ukazuje deleted ?
Jak na to ???
2 cesty mě napadají:
1 gdb -p běžící bash. a nějak tomu procesu oživit stdin a stdout (nebo prostě zavolat funkci "intepretuj příkaz history")a pokusit se zapsat history a čekat s chřtánem na stdout. AI mi k tomu napsala třeba call (int) system("ls") - bojim se že to je ekvivalent exec ls a to víme co s bashem udělá.... fungovalo by syste(history) ? kde uvidím stdout ..Nebo přes nějaké duplikování deskriptorů
metoda 2: parsing core dumpu( který jsem si i přes gcore udělal pro případ, že třeba vypne se proud ::) ).. s využitím gdb gdb bin/bash corefile ; print history_list ; x/20s 0x67...123 jak mi to radilo ale nevidím nic čitelného
0x622212369770 <history_list>: "\363\017\036\372H\213\005\255o\005"
0x62221236977b <history_list+11>: "\303\017\037@"
0x622212369780 <current_history>: "\363\017\036\372Hc\025\211o\005"
0x62221236978b <current_history+11>: ";\025\177o\005"...
0x6222123697a8 <current_history+40>: "1\300\303\017\037D"
0x6222123697af: ""
0x6222123697b0 <previous_history>: "\363\017\036\372\213\005Zo\005"
0x6222123697ba <previous_history+10>: "1҅\300t\026\203\350\001H\213\025^o\005"
0x6222123697ca <previous_history+26>: "\211\005Do\005"
0x6222123697d0 <previous_history+32>: "H\230H\213\024\302H\211\320\303f\017\037D"
0x6222123697df: ""
0x6222123697e0 <next_history>: "\363\017\036\372\213\005*o\005"
0x6222123697ea <next_history+10>: ";\005 o\005"
0x6222123697f0 <next_history+16>: "t\036\203\300\001H\213\025,o\005"
0x6222123697fc <next_history+28>: "\211\005\022o\005"
0x622212369802 <next_history+34>: "H\230H\213\004\302\303\017\037\200"
0x62221236980d <next_history+45>: ""
0x62221236980e <next_history+46>: ""
(gdb)
3. má přímo bash někde v paměti proměnnou obsahující string $HISTFILE
4. je problém dostat z toho core dumpu správné pořadí té historie, protože půjde o nějaký linked list, ještě případně zpřeházený podle toho jak se ignoredups příkazy posouvají na konec. ?
HISTORIE má defaulních 500 položek.
-
Je to off topic, ale lidi, používejte konečně fish, kde to jde...
-
Dotaz: pokud mám ten core dump , je možné z něj nějak jen uložit menší výsek paměti ( jako je anotovaný kus toho výpisu<current_history><prev_history>,<next_history> a <history_list>) , abych musel procházet méně balastu přes strings/hexdump? On má 2900kB nebo 4500kB (gcore -a)
root@x:~/core# (strings core|sort|uniq) |wc
13921 19899 220162
root@x:~/core# (strings core-a|sort|uniq) |wc
18201 24637 244798
... diff -y <(strings core|sort|uniq) <(strings core-a|sort\uniq) |less...... motají se tam i completions
SIce je to OT od záchrany dataco ten fish umí zázračného ? Problém je, že 1 jsem neměl nakonfigurovaný pořadně .bashrc (HISTSIZE na 20000 by jen oddálilo problém nebo by mi jen zaneřádilo HISTFILE třeba jen 1500 řádky), jen ignoredups, nemám append nebo ten PSPROMPT na chytré slučování (problematika na korektní zápis do historie pokud běží víc bashů současně)...
Ale tohle je prostě moje blbost, že jsem copy paste scriptu do terminálu nezavolal unset HISTFILE (a i tak si nejsem jistý že by to na 100% pomohlo, ten skript mohl si spustit novou instanci bashe nebo co já vím) a ten skript zřejmě někde měl řádek exit nebo jiný return, který uzavřel aktuální bash a zapsal historii (který byla vyšší než 500 řádků) ...Situace taková je, že nyní HISTFILE obsahuje posledních 500 řádků toho copy paste skriptu. fujtajbl
-
To, že vidíš history_list by mělo stačit i pokud nemáš nic víc. To je funkce vracející ukazatel na uloženou historii, což je pole ukazatelů na HIST_ENTRY, ve které první položka je string.
(gdb) call ((void*(*)(void))history_list)()
$1 = (void *) 0x555555a2fd20
(gdb) p *(char**)(((void**)0x555555a2fd20)[0])
$2 = 0x55555577b390 "cd .."
(gdb) p *(char**)(((void**)0x555555a2fd20)[1])
$3 = 0x5555556e6e20 "ll"
(gdb) p *(char**)(((void**)0x555555a2fd20)[2])
$4 = 0x55555579fdf0 "make CFLAGS=\"-O0 -ggdb\""
-
Skvělé... (nefunguje to sice na gdb uleželého core dump,abych nic nepokazil, ale zkouším to na jiné instanci běžícího bashe),ale budu tomít i očíslované a s pořadím . super
Jen mě zajímá, pro automazaci:
1. je možné obsah příkazu "p" uložit do souboru z gdb abych se neuklikal nebo to nekopíroval scrollbuffer terminálu a složitě to neparsoval
2.je možné použít příkaz "p" na steroidech, aby vypsalo přímo celé pole naráz?
právě teď asi kixnul ten počítač, jak jsem to te´d zkoušel umřel ssh spojení a nejde ping ! je možné že to crashlo kvůli přistupu do paměti? EDIT: otázka platí, je možné tímto shodit celý PC (ne jen bash) .. Cant access memory
Cannot access memory at address 0x31303d6d722e2a3a
(gdb) p *(char**)(((void**)$1)[25])
(gdb) p *(char**)(((void**)$1)[1])
$2 = 0x5d376548cfd0 "\t\t\t\t\tstatusLine += 'Output: <span>' + actualWattage + 'W</span>';"
Cannot access memory at address 0x31303d6d722e2a3a
(gdb) p *(char**)(((void**)$1)[299])
Cannot access memory at address 0x31303d687a6c2e2a
(gdb) p *(char**)(((void**)$1)[29])
Uff, jsou to nějaký glitše v síti , vypadává asi kabel-link-utpčko
10x za posledních 3 minuty, předtím ne
vmbr0: port 1(enp2s0) entered forwarding state
igc 0000:02:00.0 enp2s0: NIC Link is Down
vmbr0: port 1(enp2s0) entered disabled state
igc 0000:02:00.0 enp2s0: NIC Link is Up 100 Mbps Full Duplex, Flow Control: RX/TX
vmbr0: port 1(enp2s0) entered blocking state
vmbr0: port 1(enp2s0) entered forwarding state
igc 0000:02:00.0 enp2s0: NIC Link is Down
vmbr0: port 1(enp2s0) entered disabled state
igc 0000:02:00.0 enp2s0: NIC Link is Up 100 Mbps Full Duplex, Flow Control: RX/TX
vmbr0: port 1(enp2s0) entered blocking state
vmbr0: port 1(enp2s0) entered forwarding state
igc 0000:02:00.0 enp2s0: NIC Link is Down
vmbr0: port 1(enp2s0) entered disabled state
igc 0000:02:00.0 enp2s0: NIC Link is Up 100 Mbps Full Duplex, Flow Control: RX/TX
vmbr0: port 1(enp2s0) entered blocking state
vmbr0: port 1(enp2s0) entered forwarding state
igc 0000:02:00.0 enp2s0: NIC Link is Down
vmbr0: port 1(enp2s0) entered disabled state
igc 0000:02:00.0 enp2s0: NIC Link is Up 100 Mbps Full Duplex, Flow Control: RX/TX
vmbr0: port 1(enp2s0) entered blocking state
vmbr0: port 1(enp2s0) entered forwarding state
-
OK POVEDLO SE. přímo v gdb: set logging on ; a klasicky while $i <500 {p p *(char**)(((void**) 0x62222b86fc70)[$i] ; $i+=1;) end
-
Mimochodem jaký je rozdíl mezi print a call? Nějak mi nesedí vysvětlení ai, že jedno volá a může mít side affecty a druhé je jen evaluace.
Avšak mé netrénované gdboko nevidí rozdíl
(gdb) call ((void*(*)(void))history_list)()
$413 = (void *) 0x62222b86fc70
(gdb) print ((void*(*)(void))history_list)()
$414 = (void *) 0x62222b86fc70
$415 = (void *(*)(void)) 0x622312369770 <history_list>
(gdb) call ((void*(*)(void))history_list)
$416 = (void *(*)(void)) 0x622312369770 <history_list>
print 2
call 2 #totéž
A ještě, je mozné toto provést na snapshotu (coredumpu)? tedy za předpokladu, že první krok(volání history_list) nepůjde udělat, ale tu druhou část (když budu znát ten pointer)