Утилиты Linux, которые мы используем, не зная о них

Утилиты Linux, которые мы используем, не зная о них

Debian-Lab

В OS Linux существует ряд инс­тру­мен­тов с инте­рес­ной судь­бой: поч­ти все хоть раз видели резуль­тат их работы, но мало кто зна­ет, чем это было сде­лано. В данной статье мы рас­смот­рим нес­коль­ко таких ути­лит.

Генератор паролей

Ге­нера­торов паролей сей­час в избытке. Осо­бен­но удив­ляет мно­жес­тво веб‑при­ложе­ний для этой цели. Сер­вис random.org чес­тно приз­нает­ся, что генери­рует пароли на сто­роне сер­вера и исполь­зовать их для чего‑то серь­езно­го про­тиво­пока­зано. Дру­гие сер­висы заяв­ляют, буд­то генери­руют пароли локаль­но с помощью JavaScript, но сто­ит ли верить им на сло­во и гаран­тиру­ет ли их под­ход, что уте­чек мож­но не опа­сать­ся, — воп­рос неп­ростой.

В то же вре­мя генера­тор слу­чай­ных паролей при­сутс­тву­ет в репози­тори­ях всех дис­три­бути­вов Linux еще с девянос­тых и называ­ется pwgen. Мно­гие пароли, которые ты получал в сво­ей жиз­ни, с боль­шой веро­ятностью сге­нери­ровал имен­но он.

Что инте­рес­но, его автор — Те­одор Цо, тот самый, который раз­работал фай­ловую сис­тему ext2 и ее жур­налиру­емые вер­сии ext3 и ext4.

К при­меру, pwgen 16 1 сге­нери­рует один пароль из шес­тнад­цати сим­волов.

$ pwgen 16 1

iy1naeZeeNguchae

Ес­ли не ука­зывать вто­рой аргу­мент (количес­тво паролей), то по умол­чанию в инте­рак­тивном режиме pwgen сге­нери­рует целых восемь­десят паролей — четыре колон­ки по двад­цать строк. По замыс­лу авто­ров, это дол­жно защитить поль­зовате­ля от любите­лей заг­лядывать в чужой экран. Поль­зователь генери­рует целую таб­лицу паролей и копиру­ет или запоми­нает из нее один слу­чай­ный. В этом слу­чае зло­умыш­ленник или не в меру любопыт­ный кол­лега по офи­су никак не смо­жет узнать, какой пароль из вось­ми десят­ков выб­рал поль­зователь. Во вре­мена мас­совой уда­лен­ной работы этот аргу­мент кажет­ся нес­коль­ко натяну­тым, да и вызыва­ет сом­нения, что пароли так уж прос­то запом­нить.

В сов­ремен­ных усло­виях куда полез­нее опция -s/--secure, которая генери­рует пол­ностью слу­чай­ные пароли без пре­тен­зий на удо­бочи­таемость. К ней же мож­но добавить -B/--ambiguous, которая исклю­чает из вывода похожие на вид сим­волы вро­де O/0 и 1/I.

$ pwgen -sB 16 1

PiVRps3erAngsmeb

Самораспаковывающиеся архивы

Проп­риетар­ные прог­раммы для Linux неред­ко рас­простра­няют­ся в виде исполня­емых уста­нов­щиков. Таким спо­собом их авто­ры избе­гают необ­ходимос­ти собирать более чем один фор­мат пакета. Прог­раммы на плат­формен­но незави­симых язы­ках вро­де Java так­же могут исполь­зовать один гра­фичес­кий уста­нов­щик на всех ОС — раз­лича­ется спо­соб его запус­ка.

Та­ким спо­собом рас­простра­нялись пакеты с драй­верами NVIDIA, некото­рые игры, зна­читель­ная часть пакетов Sun Microsystems / Oracle (NetBeans, SunStudio и дру­гие). Чаще все­го у них было рас­ширение .run, иног­да прос­то .sh.

Как пра­вило, такой уста­нов­щик пред­став­ляет собой саморас­паковы­вающий­ся архив. На Windows монолит­ные уста­нов­щики и саморас­паковы­вающиеся архи­вы обыч­но содер­жали дво­ичный код прог­раммы для рас­паков­ки архи­ва. UNIX-подоб­ные ОС всег­да вклю­чают в себя как минимум tar и gzip, как тре­бует стан­дарт POSIX, поэто­му мож­но обой­тись скрип­том на стан­дар­тном же Bourne shell.

Я дол­го думал, что инс­тру­мен­ты для соз­дания этих уста­нов­щиков тоже проп­риетар­ные. Так бы я и думал, если бы не нат­кнул­ся на сво­бод­ные про­екты с такими же уста­нов­щиками. Соз­дателем этих пакетов ока­зал­ся один и тот же инс­тру­мент с откры­тым исходным кодом — Makeself.

Makeself пред­став­ляет собой срав­нитель­но неболь­шой скрипт. Как ни стран­но, авто­ры до сих пор его не заб­росили, и в пос­ледних вер­сиях Makeself под­держи­вает сжа­тие с помощью xz и кон­троль­ные сум­мы SHA-256 вмес­то тра­дици­онных gzip и MD5.

Мож­но даже не уста­нав­ливать его, а прос­то ско­пиро­вать фай­лы makeself.sh и makeself-header.sh в каталог про­екта. Про­демонс­три­рую на прос­том при­мере. Нам пот­ребу­ется целевой файл (условно test.sh) и скрипт уста­нов­ки, который будет выпол­нять­ся пос­ле рас­паков­ки во вре­мен­ный каталог.

├── makeself-header.sh

├── makeself.sh

└── my-package

├── setup.sh

└── test.sh

Про­цесс уста­нов­ки пол­ностью на совес­ти поль­зовате­ля. Для прос­тоты огра­ничим­ся копиро­вани­ем в /tmp. Скрипт выпол­няет­ся в катало­ге с рас­пакован­ными фай­лами, поэто­му все пути будут отно­ситель­ными.

#!/bin/sh

cp test.sh /tmp/

Те­перь соз­дадим наш уста­нов­щик. Син­таксис коман­ды — makeself.sh <каталог с файлами> <имя выходного файла> <название проекта> <команда для выполнения после распаковки>.

Путь к коман­де для выпол­нения пос­ле рас­паков­ки тоже пишет­ся отно­ситель­но катало­га с рас­пакован­ными фай­лами. Это единс­твен­ный тон­кий момент в работе с Makeself. Имен­но поэто­му мы помес­тили скрипт setup.sh в каталог с фай­лами для упа­ков­ки — Makeself вос­при­нима­ет этот аргу­мент имен­но как коман­ду, а не встра­ивает скрипт в заголо­вок уста­нов­щика.

$ ./makeself.sh ./my-package/ my-package.run "My Package" "./setup.sh"

Header is 678 lines long

About to compress 12 KB of data...

Adding files to archive named "my-package.run"...

./setup.sh

./test.sh

CRC: 2448166092

MD5: f46655bb0b96ea7bee4d1f6f112eebe4

Self-extractable archive "my-package.run" successfully created.

$ ./my-package.run

Verifying archive integrity... 100% MD5 checksums are OK. All good.

Uncompressing My Package 100%

$ file /tmp/test.sh

/tmp/test.sh: POSIX shell script, ASCII text executable

Есть ли смысл исполь­зовать Makeself во вре­мена snap, Flatpak и AppImage? Я вижу два вари­анта, ког­да Makeself все еще акту­ален. Пер­вый — рас­простра­нение само­уста­нав­лива­ющих­ся хот­фиксов в осо­бых слу­чаях, ког­да нор­маль­ный пакет соб­рать невоз­можно или нераци­ональ­но. Вто­рой — под­дер­жка проп­риетар­ных ОС. Скрип­ты Makeself с опци­ями по умол­чанию будут работать на любой POSIX-сов­мести­мой сис­теме, поэто­му, если от тебя тре­буют уста­нов­щик для Solaris или HP-UX, это самый прос­той спо­соб их соз­дать.

Малоизвестные форматы архивов

Не­кото­рые фор­маты архи­вов прош­ли через пик популяр­ности и оста­лись в прош­лом. В UNIX тра­дици­онно для соз­дания архи­ва (то есть объ­еди­нения нес­коль­ких фай­лов в один) и для сжа­тия исполь­зовались раз­ные инс­тру­мен­ты. Из‑за это­го инс­тру­мен­ты сжа­тия могут появ­лять­ся и уста­ревать, не вызывая проб­лем, — нет пот­ребнос­ти оставлять под­дер­жку уста­рев­ших алго­рит­мов в новых архи­вато­рах. Если и понадо­бит­ся рас­паковать дан­ные ста­рым алго­рит­мом, всег­да мож­но пос­тавить отдель­ную ути­литу.

Ес­ли в ходе архе­оло­гичес­ких рас­копок тебе попадет­ся файл .tar.Z, мож­но пос­тавить ncompress и выпол­нить compress -d file.tar.Z, пос­ле чего понадо­бит­ся толь­ко стан­дар­тный tar. В дру­гих слу­чаях ори­гиналь­ный алго­ритм LZW никому в голову не при­дет.

Иное дело с собс­твен­но фор­матами архи­вов. В отли­чие от алго­рит­мов сжа­тия, спо­собы соб­рать один файл из нес­коль­ких слож­но срав­нивать меж­ду собой. Фор­мат ZIP не под­держи­вает пра­ва фай­лов, а tar — под­держи­вает, в этом смыс­ле tar.gz луч­ше ZIP. При этом при­думать фор­мат, который был бы объ­ективно и бес­спор­но луч­ше tar, дос­таточ­но слож­но.

Од­нако есть фор­мат фай­ла, а есть инс­тру­мен­ты для работы с ним. И поведе­ние tar, и фор­мат соз­дава­емых фай­лов стан­дарти­зова­ны в POSIX, что и дела­ет его популяр­ным на всех UNIX-подоб­ных сис­темах. К тому же ути­лита tar дос­таточ­но удоб­на в исполь­зовании. По край­ней мере tar cvf и tar xvf быс­тро запоми­нает каж­дый поль­зователь.

cpio

Ты уди­вишь­ся, но tar — это не самый рас­простра­нен­ный фор­мат архи­вов в Linux. Сре­ди поль­зовате­лей — да, но боль­ше все­го дан­ных хра­нит­ся в фор­мате cpio, с которым ред­ко при­ходит­ся работать вруч­ную.

Поч­ти на каж­дой машине с Linux есть файл в этом фор­мате, пос­коль­ку имен­но его ядро исполь­зует для initrd (inirial RAM disk). Его же исполь­зует фор­мат пакетов RPM. Как говорит до­кумен­тация ядра, опре­деля­ющим фак­тором была прос­тота фор­мата.

А вот поль­зовать­ся ути­лита­ми, которые с ним работа­ют, сов­сем не прос­то. Вот как надо вызывать ути­литу cpio, что­бы соз­дать архив:

find /path/to/dir -depth -print | cpio -o > /path/to/archive.cpio

Для скрип­та сбор­ки — сой­дет, даже в чем‑то удоб­но. Для руч­ного исполь­зования... tar cvf явно про­ще и пок­рыва­ет боль­шую часть пот­ребнос­тей поль­зовате­ля.

ar

Дру­гой рас­простра­нен­ный фор­мат, который ник­то не исполь­зует нап­рямую, — ar. Его реали­зация вхо­дит в сос­тав пакета GNU binutils. Как он ока­зал­ся в пакете с ути­лита­ми для работы с исполня­емы­ми фай­лами? Дело в том, что он исполь­зует­ся для соз­дания ста­тичес­ких биб­лиотек.

Ни­како­го осо­бен­ного фор­мата «ста­тичес­кой биб­лиоте­ки» в ELF не сущес­тву­ет. Каж­дый файл с исходным кодом ком­пилиру­ется в отдель­ный объ­ектный файл в том же фор­мате ELF. Фай­лы вро­де libfoo.a — это на самом деле архи­вы в фор­мате ar, которые содер­жат нес­коль­ко объ­ектных фай­лов. Таким обра­зом, поль­зователь может писать gcc -o myprog myprog.o /usr/lib/foo/static/libfoo.a.

Вто­рой поль­зователь это­го фор­мата — пакет­ный менед­жер dpkg. Если файл .rpm — это сжа­тый cpio, то .deb — сжа­тый ar.

Внешние отладочные символы

Один из пер­вых уро­ков начина­юще­го раз­работ­чика для UNIX: хочешь сде­лать исполня­емый файл мень­ше — выпол­ни strip myfile. Ценой потери воз­можнос­ти работы с ним в отладчи­ке, конеч­но.

Со вре­менем начина­ющий обя­затель­но уви­дит в репози­тори­ях пакеты с внеш­ними отла­доч­ными сим­волами. Как они дела­ются? С помощью ути­литы objcopy из Binutils.

Рас­смот­рим на при­мере тра­дици­онной прог­раммы Hello world.

#include <stdio.h>

int main(void) {

printf("hello world\n");

}

Ском­пилиру­ем исполня­емый файл с отла­доч­ной информа­цией.

$ gcc -g -o hello ./hello.c

[dmbaturin@careless makeself-test]$ file ./hello

./hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=a8e65e032c2a154eecc1ed609aac1a1687e5c2fd, for GNU/Linux 3.2.0, with debug_info, not stripped

Те­перь извле­чем отла­доч­ные сим­волы во внеш­ний файл hello.debugи уда­лим их из исходно­го.

$ objcopy --only-keep-debug ./hello hello.debug

$ file ./hello.debug

./hello.debug: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter empty, BuildID[sha1]=a8e65e032c2a154eecc1ed609aac1a1687e5c2fd, for GNU/Linux 3.2.0, with debug_info, not stripped

$ ldd ./hello.debug

statically linked

Ес­ли запус­тить исходный файл в отладчи­ке GDB, мы получим сооб­щение об отсутс­тву­ющих отла­доч­ных сим­волах. Но если заг­рузить сим­волы коман­дой symbol-file hello.debug, мы смо­жем отла­живать его как обыч­но.

$ gdb ./hello

GNU gdb (GDB) Fedora 9.1-6.fc32

For help, type "help".

Type "apropos word" to search for commands related to "word"...

Reading symbols from ./hello...

(No debugging symbols found in ./hello)

(gdb) symbol-file hello.debug

Reading symbols from hello.debug...

(gdb) b main

Breakpoint 1 at 0x40112a: file ./hello.c, line 4.

(gdb) r

Starting program: /home/dmbaturin/tmp/hello

Breakpoint 1, main () at ./hello.c:4

4 printf("hello world\n");

(gdb)

Заключение

Впол­не воз­можно, что ни один из этих инс­тру­мен­тов тебе не при­годит­ся. А может, как раз их тебе и не хва­тало или не хва­тает тому, кто зав­тра при­дет к тебе с воп­росом «а чем сде­лали вот этот файл?». В любом слу­чае о них луч­ше знать, чем не знать!

Источник статьи: xakep.ru

⏳ Наш основной канал - @debian_lab

Report Page