Линукс и DevOps Дни
2.23K subscribers
108 photos
8 videos
194 links
Самобытно про разработку, devops, linux, скрипты, тестирование, сисадминство, техдирство, пиэмство и за айтишную жизу.
Download Telegram
🙂 Мухаха, наебнёмка SSH

Вводные: У клиента есть сервак с авторизацией по ssh ключам. С виду все настроено верно. Катают ансиблом.

Проблема: При подключении к серверу, продолжает запрашиваться пароль. Хотя явно указан ключ для подключения, а на сервере прописан публичный ключ клиента в authorized_keys.

Проблема на самом деле распространенная. Для отладки открываем логи авторизаций и смотрим что происходит. И да, никто блядь не читает логи, а сразу начинают искать суслика, которого нет. ЧИТАЙ ЛОГИ!

Понятно дело, в логах видим ошибку:

message repeated 4 times: Authentication refused: bad ownership or modes for file /root/.ssh/authorized_keys


С этой ошибкой ты всяко бодался. Смотрим права. И действительно, на файле authorized_keys стоят 3 топора (777). А должно быть 600. Как фиксить, ежу понятно.

✔️ \033[1m Но сейчас про другое \033[0m

Как сказать пингвину, чтобы он забил хуй на проверку прав для этих ключей?

А вот так, добавляем в /etc/ssh/sshd_config строчку:

StrictModes no


Ну и рестартим демона systemctl restart sshd

Всё. Теперь можешь играться с правами ключей. Хоть 000 выстави. Права проверяться не будут и тебя успешно пропустят без пароля.

Когда StrictModes установлено в no, SSH сервер не будет так строго проверять права доступа к этим файлам и каталогам. Это означает, что, например, если домашний каталог пользователя имеет права доступа, которые обычно не допускаются (например, другие пользователи могут читать каталог), SSH сервер все равно будет работать.

Установка StrictModes no уменьшает уровень безопасности, так как позволяет некоторым нежелательным правам доступа с точки зрения безопасности, но это может быть полезно в некоторых сценариях, например, при развертывании на тестовых серверах или в средах, где безопасность не является приоритетом.


Короче для дебага фишка мастхев, если в логах хуй с маслом, включаем эту опцию и проверяем, действительно ли дело в правах на ключи или дело в кривых руках.

Финк диферент!

tags: #linux #debug

@ВАSНDАYS | BАSHDАYS.CОM
Привет отдыхающим. Хош не хош, а постом вас нужно порадовать и желательно интересным. Вот сейчас и порадую, самое время.

Сегодня будем дебажить и багфиксить. Узнаем что такое core файлы в Linux и как с ними взаимодействовать.

Иногда в Linux появляются какие-то странные файлы, с названием core.xxx, порой их бывает прям дохуя. Обычно их все сносят и не задумываются чо это за высер такой.

А этот высер можно либо отключить, либо залезть в него рукой и поковырять. На самом деле все эти «Корки», очень полезный материал для изучения и отладки падающих приложений.

✔️ Что такое «Корки»

Нет это не порода собаки. Всё просто, это файл, который содержит дамп памяти процесса в моменте, когда он уебался. То есть произошел segmentation fault.

Имея этот файл на руках, можно запатчить, забагфиксить либо понять откуда растут ноги у ошибки.

Как включить core файлы.

Хуй знает. Обычно это делается через файл /etc/sysctl.conf, добавляем:

kernel.core_pattern=core


Либо из консоли брякнуть:

sysctl -w kernel.core_pattern=core


В этом случае, если процесс/программа уебалась, то в папке с этим приложением появится файл core.xxx.

Важно! Выполняем:

ulimit -c


Если вернуло 0, то хуй те, а не «корка». Чтобы все сработало, выполняем команду:

ulimit -c unlimited


Так. У нас всё готово, по идее «корки» теперь будут создаваться. Если не создаются, то ты что-то сделал не так, либо в твоем дистрибутиве это делается иначе. Но я думаю это везде одинаково. Пробуй.

Пишем простой код на СИськах

#include <stdio.h>

int main() {
int *ptr = NULL;
*ptr = 10;
return 0;
}


Компилируем:

gcc -g -o bashdays bashdays.c


Ключ -g включает отладочную информацию. Без этого ключа хуй мы чо отдебажим.

В коде выше, я пытаюсь присвоить значение 10 по адресу, на который указывает указатель ptr, но ptr не инициализирован и содержит значение NULL. В попытке разыменования указателя на NULL мы получим segmentation fault.


Сложно? Забей, нам важно понять как работать с «корками» и дебажить.

Так. Запускаем бинарник.

./bashdays


Хуяк и словили Segmentation fault (core dumped). Видишь в скобках core dumped? ВОТ ОНО! Рядом с бинарником появился файл core.1302. Полезли копаться в этом высере!

Запускаем отладчик:

gdb ./bashdays core.1302

``
Происходит магия. Чето там бежит и льется. Без паники! Смотрим несколько последних строчек:

Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x0000563ebf37f13d in main () at coretest.c:5
5 *ptr = 10;


Тааак… и видим из-за чего была вызвана ошибка. Даже строчку показывает, которая справедлива для исходника, хотя мы смотрим бинарник.

Проверяем указатель ptr, вводим в отладчике:

(gdb) print ptr
$1 = (int *) 0x0


И видим что указатель ptr имеет значение NULL (0x0). Это и вызвало ошибку сегментации при попытке разыменования.

Теперь когда у нас есть эта инфа, мы знаем, что проблема заключается в попытке доступа к памяти по-нулевому указателю и можно это забагфиксить.

Самое простое решение, это добавить проверку и убедиться, что указатель ptr указывает на допустимую область памяти. Прежде чем разыменовывать его. Выделяем память для ptr с помощью функции malloc().

#include <stdio.h>
#include <stdlib.h>

int main() {
int *ptr = malloc(sizeof(int)); // выделяем память для указателя
if (ptr != NULL) { // если память выделена, присваиваем значение
*ptr = 10;
free(ptr); // освобождаем память
} else {
printf("Алярма! Память не выделяется\n");
}
return 0;
}


Вот и забагфиксили, компилируем, запускаем.

Ошибка сегментации исчезла. Улыбаемся и в очередной раз гордимся - какие же мы охуительные.

Но не достаточно! Чтобы прям вообще преисполниться, нужно запатчить бинарник через hex редактор.

Как это сделать, покажу совсем скоро, а то пост пиздец толстый получился.

У меня всё. Изучай.

tags: #linux #debug

@ВАSНDАYS | BАSHDАYS.CОM
Сегодня дождливый день, даже материться не хочется.

Поэтому потыкаем strace и файловый менеджер.

Для экспериментов я взял десктопный линукс на 22 убунте + gnome. Внутри моего гнома зашит файловый менеджер Nautilus. Но подойдет абсолютно любой дистрибутив и любой файловый менеджер например kde/dolphin.

Для начала создаём файл:

echo -ne '\x42\x5a\x68' > /tmp/bashdays


Этот файл я приправил магическими числами hex:42 5a 68, что равносильно формату файла: bz2.

Так, запускаем:

strace -o'|cat' -P /tmp/bashdays -qqqyf nautilus /tmp 2> /dev/null


Не забудь указать актуальное название своего файлового менеджера, у меня nautilus, у тебя может быть другой.

После запуска в файловом браузере откроется папка tmp, в ней мы увидим наш файл bashdays. Иконка у этого файла соответствует иконке bz2 архива.

Теперь возвращаемся в терминал с strace и смотрим что произошло.

openat("/tmp/bashdays", O_RDONLY) = 25</tmp/bashdays>
read(25</tmp/bashdays>, "BZh", 4096) = 3
close(25</tmp/bashdays>) = 0


В выводе наблюдаем обращение к файлу /tmp/bashdays, дополнительно видим что файл был прочитан. Также видим что была определена сигнатура файла BZh.

Отлично! Мы на верном пути. Теперь закрываем файловый менеджер, тормозит ранее запущенный strace. И добавляем к файлу расширение txt.

mv /tmp/bashdays /tmp/bashdays.txt


Снова запускаем strace:

strace -o'|cat' -P /tmp/bashdays.txt -qqqyf nautilus /tmp 2> /dev/null


И видим другую картину:

statx("/tmp/bashdays.txt")


Отсутствуют системные вызовы связанные с чтением файла. А файловый менеджер интерпретировал это как текстовый файл. Сменилась иконка.

Если сейчас кликнуть на этом файле 2 раза, то файл откроется в текстовом редакторе.

✔️ Делаем выводы

Если у файла есть расширение, то файловый менеджер полагается на него и не производит никаких действий с файлом.

А если расширение не указано, то происходит анализ содержимого. В моём случае файловый менеджер нашел сигнатуру bz2 и автоматически решил что это архив.

Чтобы определить тип файла, можешь воспользоваться командой:

file /tmp/bashdays.txt


Вот такая вот логика зашита в кишочках.

Хорошей тебе рабочей недели, изучай!

tags: #linux #debug

🔔
10 мест в твоём городе где можно потрахаться.

Лидером, конечно же остается Linux.

А сегодня на повестке дня, снова твой любимый strace и замечательная опция -T, которая позволяет находить ботлнэк (узкое место).

В посте будут встречаться лютые «франкенштейны», но ты сразу не уходи, я кратенько всё разжую и ты проникнешься. Бля буду!

Опция -T выводит разницу во времени между запуском и завершением системного вызова. Применяется для того, чтобы увидеть момент, когда конкретный вызов начал тормозить (встал раком) на фоне предыдущих.


Запускаем «франкенштейна»

strace -s0 -o'|nl >&2' -Tyqqqfe write dd if=/dev/random bs=4096 count=23 status=none | while read -rn1;do : ;done


✔️ Для начала давай разберем эту кишку:

s0 = размер буфера, строки не обрезаются
o/nl/&2 = вывод в стандартную ошибку на утилиту nl
nl = утилита нумерует строки
T = затраченное время на системный вызов
y = показывать симлинки для файловых дескрипторов
qqq = отключаем лешний шлак
f = трассируем дочерние процессы
e = трассировка только write
dd = читает из random блоками 4096 и пишем по 23 блока

дальше скармливаем это while

while = читает данные побайтно (-n1) без обработки символов конца строки (-r)

Вывод сокращаю, чтобы не так погано смотрелось:

01  write() = 4096 <0.004691>
02 write() = 4096 <0.000010>
03 write() = 4096 <0.000009>
04 write() = 4096 <0.000009>
05 write() = 4096 <0.000009>
06 write() = 4096 <0.000009>
07 write() = 4096 <0.000009>
08 write() = 4096 <0.000009>
09 write() = 4096 <0.000009>
10 write() = 4096 <0.000009>
11 write() = 4096 <0.000009>
12 write() = 4096 <0.000009>
13 write() = 4096 <0.000009>
14 write() = 4096 <0.000009>
15 write() = 4096 <0.000009>
16 write() = 4096 <0.000009>
17 write() = 4096 <0.014406>
18 write() = 4096 <0.023782>
19 write() = 4096 <0.023870>
20 write() = 4096 <0.023944>
21 write() = 4096 <0.023815>
22 write() = 4096 <0.024032>
23 write() = 4096 <0.024088>


Смотрим на последний столбик, видим аномалию после 16 строки, время выполнения существенно увеличилось. Поздравляю мы нашли bottleneck (узкое место).

Теперь давай разберемся с этим узким местом. Что произошло, почему все стало тормозить?

Умножаем блок 4096 на номер строки 16, получаем = 65536. Знакомая цифра? Знакомая!

65536 это ёмкость пайпа (канала), по достижению предела пишущий процесс заблокировался, пока не было прочитано и освобождено достаточно места.

Подробнее можешь почитать в мане: man 7 pipe (раздел Pipe capacity).

Бонусом команда, которая протестирует ёмкость пайпа:

sh -c '( dd if=/dev/zero obs=1 oflag=nonblock || pkill -P $$ -x "sleep" ) | sleep 300'


Если dd сообщает о недоступности стандартного вывода, значит тест удался. У меня получилось так:

dd: writing to 'standard output': Resource temporarily unavailable
129+0 records in
65536+0 records out
65536 bytes (66 kB, 64 KiB) copied, 0.0195754 s, 3.3 MB/s
Terminated


Вот так находясь на границе между кодом приложения и кодом ядра можно увидеть тонкие моменты. Изучай!

tags: #linux #debug

🔔
Сегодня заумных простыней не будет, тем не менее следующая кишка на bash тебе пригодится.

strace -o "| grep -Eo '/home/[^\"]+' >&2" -zfe '/^open' mc


✔️ Делает она следующее

При запуске программы (в моём случае это mc), в терминал вываливается список всех файлов, которые программа открывает в домашнем каталоге.

Штука очень полезная для дебага. Когда не знаешь к каким файлам программа обращается, а очень хочется.

Эту команду можно усовершенствовать, поменяв пути и добавив например вызовы write. Тут уже от ситуации зависит.

При первом запуске mc я получил такой список:

/home/user/.config/mc/ini
/home/user/.config/mc/ini
/home/user/.config/mc/panels.ini.E4M2O2
/home/user/.config/mc/ini
/home/user/.config/mc/ini
/home/user/.config/mc/ini~
/home/user/.config/mc/ini
/home/user/.bash_history


Если в твоём сознании живёт стройный и прекрасный мир программ, и ты человек с утончённой душевной организацией, воздержись от использования этого инструмента, лучше сходи на pornhub.


Пользуйтесь!

tags: #bash #linux #debug

🔔
Про интересный факап и траблшутинг.

Обратился клиент — у нас mysql реплика не работает. Вернее работает, но отстала всего лишь на 3 месяца.

На вопрос — а хули вы 3 месяца сидели, у вас же мониторинг есть?

Очевидный ответ — да, есть, но оно молчит.

Ладно, полез разбираться. SHOW SLAVE STATUS\G;

А там ошибки брынчат, как хуи в бидоне.

Error 'Cannot delete or update a parent row: a foreign key constraint fails'


Ну это ладно, ошибка и ошибка, тут понятно что делать — НИЧЕГО.

Так как реплика используется чисто аналитиками на потыкать, игнорим эту ошибку через my.cfg. Быстрофикс.

Для продуктовой реплики такое делать - НЕЛЬЗЯ!

Самый важный вопрос — какого хера мониторинг 3 месяца молчал?

Тут уже интереснее. Реплика заведена в prometheus, экспортеры есть, все дела.

Но из графаны сервер пропал, хотя год назад я ее точно там видел.

Думаем… Думаем… Смотрю графану, мониторится поле: replica_seconds_behind

Хм, лезу обратно на реплику, а там сроду нет mysql_exporter. Что же это тогда такое?

Копаем вглубь и видим, что node_exporter мониторит папку /tmp на наличие файликов .prom.

Ага… То есть метрики с mysql реплики собирает какой-то bash скрипт по крону, генерит текстовичок и отдает в prometheus.

Типа такого:

replica_slave_io_running{host="replica"} 1
replica_seconds_behind{host="replica"} 1234567


Да, оно прекрасно работало, до момента пока не вылезла ошибка: Cannot delete or update a parent row

Соответственно текстовый файл replica.prom получился в таком формате:

replica_slave_io_running{host="replica"} 1
replica_seconds_behind{host="replica"} Null


Ну а дальше prometheus такое распарсить не смог (он хочет циферки, а не буковки) и тихонечко вывел эту ноду из графаны и вообще отовсюду. Ну и аллерты в придачу. На что им тригериться если ноды нет нигде?

Прикол в том, что во время возникновения ошибки, поле Seconds_Behind_Master в mysql принимает значение Null, а не продолжает дальше считать на сколько отстала реплика.

А вот и bash скрипт, который собирал метрики:

#!/bin/bash

MAINDIR=/tmp
METRICS=rstatus.prom
HOST="replica"

SLAVE_IO_RUNNING=$(mysql -e 'SHOW SLAVE STATUS \G' | grep 'Slave_IO_Running'| awk '{print $2}')
SLAVE_SECONDS_BEHIND=$(mysql -e 'SHOW SLAVE STATUS \G' | grep 'Seconds_Behind_Master'| awk '{print $2}')

if [[ "$SLAVE_IO_RUNNING" == "Yes" ]]; then
J=1
echo 'replica_slave_io_running{host="'$HOST'"}' $J > $MAINDIR/$METRICS
else
J=0
echo 'replica_slave_io_running{host="'$HOST'"}' $J > $MAINDIR/$METRICS
fi

echo 'replica_seconds_behind{host="'$HOST'"}' $SLAVE_SECONDS_BEHIND >> $MAINDIR/$METRICS


Работа над ошибками проведена, инцидент разобран. Ни одна жопа на ретроспективе пока не пострадала, но возможно дело времени.

Как писать подобные экспортеры я накидывал в этом посте.


И всегда помни — если изобретаешь велосипед, всегда обрабатывай эксепшены!

tags: #devops #debug #bash #monitoring

🔔
Здрасти. Еще один частый вопрос с проекта Linux Factory:

Я собрал докер имейдж, а контейнер вечно в ребуте либо вообще не запускается, чо делать и как отлаживать?


Давай симулируем ситуацию и попробуем что-то с этим сделать.

Для начала соберем имейдж, это будет простой nginx + свой конфиг, который будет копироваться с локальной машины в имейдж.

Создаем на хостовой машине пару файлов:

Dockerfile:

FROM nginx:latest
WORKDIR /etc/nginx
COPY ./nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]


nginx.conf

user  nginx;
worker_processes 1;

events {
worker_connections 1024;
}

http {
server {
listen 80;
server_name localhost;

location / {
return 200 'Hello, Docker!'
add_header Content-Type text/plain;
}
}
}


Собираем имейдж:

docker build -t my-nginx .


Ждем, на экране бежит куча всякого непотребства. Это нормально. Ждем…

Проверяем:

docker images


Ага, все ок, выплюнуло что-то вроде:

REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
my-nginx latest b844ef77daa3 33 seconds ago 188MB


Запускаем:

docker run -d -p 80:80 my-nginx


Проверяем:

docker ps


Хуй там плавал. Ничо не стартануло… ошибок нет, куда смотреть?

Если контейнер вообще не запускается, то для начала смотрим логи:

1. Узнаем состояние контейнера:

docker ps -a


Видим хуй с маслом: Exited (1) 4 minutes ago

2. Смотрим логи:

docker logs --follow <id or name>


В <id or name> подставляем айдишник либо имя контейнера:

В логах видим ошибку:

 invalid number of arguments in "return" directive in /etc/nginx/nginx.conf:15


Вот! С ней уже можно работать. Получается мы посмотрели логи, даже для незапущенного контейнера. Пиздуем в nginx конфиг и видим, что в 14й строке проебали точку с запятой.

Дополнительно можно посмотреть коды выхода:

docker inspect <id or name>


Например, если код выхода ExitCode = 137, значит не хватило ресурсов, подкинь памяти и все взлетит. Наверное…

Это основные моменты отладки.

Ну а если контейнер все же запустился, но что-то не работает, сначала повторяем все вышенаписанное. Ну и дополнительно можешь подключиться к нему в интерактивном режиме:

docker exec -it <id or name> bash/sh


Подставляешь id/name контейнера и выбираешь шелл, частенько bash и коробки не установлен, поэтому как вариант запускаешь sh.

А для визуализации слоев используем утилиту dive

Установка dive:

DIVE_VERSION=$(curl -sL "https://api.github.com/repos/wagoodman/dive/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
curl -OL https://github.com/wagoodman/dive/releases/download/v${DIVE_VERSION}/dive_${DIVE_VERSION}_linux_amd64.deb
sudo apt install ./dive_${DIVE_VERSION}_linux_amd64.deb


Открываем имейдж на анализ:

dive <id or imagename>


Подставляем id или имя — ИМЕЙДЖА (не контейнера)

Смотрим, охуеваем, закрываем.

Еще можно глянуть конкретный файл в контейнере:

docker exec -it <id or name> cat /etc/nginx/nginx.conf


Либо скопировать его себе на локальную машину:

docker cp <id or name>:/etc/nginx/nginx.conf /tmp


Поправить и скопировать обратно в контейнер:

docker cp /tmp/nginx.conf <id or name>:/etc/nginx/nginx.conf


Перезапускаем контейнер с новым конфигом:

Прикол в том, что тебе не нужно билдить новый имейдж, ты делаешь правки прям в контейнере.


docker exec <id or name> nginx -s reload


Такие дела! Если знаешь еще хаки и способы отладки контейнеров/имеджей, пиши в комменты, будет полезно!

tags: #devops #debug #docker

Богатствуйте!

И снова полезный пост! Тунеядцев прошу расслабить жопы и перейти к концу, там анекдот.

Меня часто спрашивают… Нет, всем похуй. Короче:

systemctl restart php-fpm

Unit php-fpm.service could not be found.


Хм, я точно знаю что php на сервере есть! Так какого чернослива?

За годы практики, я выработал методику поиска сервисов, которые называются совсем не очевидно.

В примере выше, php сервис называется: php8.2-fpm-fuck-you!

Ха! В жизни не догадаешься.

Первым делом пиздуем в:


history | grep php


И внимательно смотрим, если повезет, то там будет эта заветная строчка с ребутом и именем замудрёного сервиса. Возможно когда-то ты с ним имел дело, либо кто-то пытался иметь.

Если не повезло делаем так:

systemctl | grep php

php8.2-fpm-fuck-you.service
phpsessionclean.timer


Эта штука гарантированно выплюнет тебе полное название сервиса, ну а дальше ты знаешь что с ним делать.

Можно конечно воспользоваться внешними утилитами, но не рекомендую. Потому что systemctl есть всегда, а внешних утилит - нет.

➡️ Сразу привыкай работать с инструментами из коробки и будет тебе счастье.

Все!

Ну и анекдот как обещал: еслиб у бабушки был бы хуй, она была бы дедушкой.

tags: #linux #debug

🔔 ➡️
Интересный вопрос сегодня залетел:

Если функции, вынесены в файл, подключенный через source, bash каждый раз его будет открывать/перечитывать при обращении к функции? Или как-то считает в память и все?


Давай посмотрим что происходит в кишках в это время. Давненько мы с тобой в strace не смотрели.

Предположим есть bash скрипт с функциями:

functions.sh

#!/bin/bash

bashdays_function() {
echo "Hello from BashDays"
}


И основной скрипт, который сорсит файл с функциями:

test_script.sh

#!/bin/bash

source ./functions.sh

bashdays_function
bashdays_function


Не забываем сделать: chmod +x test_script.sh

Запускаем test_script.sh под контролем strace:

strace -e trace=openat ./test_script.sh


И видим:


openat(AT_FDCWD, "./test_script.sh", O_RDONLY) = 3
openat(AT_FDCWD, "./functions.sh", O_RDONLY) = 3

Hello from BashDays
Hello from BashDays


То есть в контексте скрипта test_script.sh, файл с функциями был прочитан один раз.

При втором вызове функции всё считалось из памяти.

Если бы файл functions.sh читался каждый раз, то мы увидели бы несколько строчек openat(AT_FDCWD).

Грубо говоря при каждом запуске test_script.sh, подключенный файл через source будет прочитан один раз.

Вроде очевидно, но порой заставляет задуматься.

Изучай!

tags: #bash #debug #linux

🔔 ➡️
Здрасти. Как-то я писал про strace и как применять инъекции. Если пропустил, то читай тут и тут.

Ниже скрипт который автоматически прономерует системные вызовы для последующих инъекций.

#!/usr/bin/perl

use strict;
use warnings;

my %numbs;
select STDERR;
while(<STDIN>) {
if( /^[0-9]++\s++([a-z0-9_]++(?=\())/ ) {
my $t = ++$numbs{$1};
s/\s+/ \e[31m$t\e[m /;
die $! if( keys %numbs == 1000 );
}
print;
}
exit(0);


Сохраняем это безобразие в файл num_syscalls и делаем chmod +x, ну а дальше запускаем в связке с strace:

strace -o'|./num_syscalls' -yf sh -c 'ls|cat'


Теперь получаем такой выхлоп:

456107 48 close(3</usr/) = 0
456107 52 rt_sigreturn({mask=[]})
456107 63 openat(AT_FDCWD</usr/local/sbin>)
456107 53 newfstatat(3)
456107 64 openat(AT_FDCWD</usr/local/sbin>)


Смотрим второй столбик, включаем логику и видим, что системные вызовы нумеруются.

Например, возьмем системный вызов openat, видим 63, 64. Это значит что openat был вызван 64 раза. А newfstatat 53.

Теперь берем нужный номер системного вызова и применяем инъекцию. Как это сделать и для чего, опять же показывал на примерах (ссылки в начале этого поста).

Тема крутая, не нужно ебаться и считать руками.

Весь вывод strace отправляется в stderr, чтобы иметь возможность разделять вывод трассировки и вывод исследуемой программы.

А чтобы получить только трассировку, можно сделать так:

strace -o'|./num_syscalls' -yf ls > /dev/null


Если бесит подсветка, выпили из перловского скрипта управляющий символ «\e[31m\[em».

Такие дела, изучай!

tags: #linux #debug

🔔 ➡️