diff --git a/README.md b/README.md index bd03bf7..431373b 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ **Требования:** Go 1.21+ ```bash -git clone https://gitverse.ru/magnusroot/rubric +git clone https://github.com/user/rubric cd rubric go build -o rubric . ``` @@ -32,7 +32,7 @@ go build -o rubric . Или сразу установить глобально: ```bash -go install gitverse.ru/magnusroot/rubric@latest +go install github.com/user/rubric@latest ``` --- @@ -218,4 +218,4 @@ var All = []Module{ Использует ANSI escape-коды. Работает в большинстве современных терминалов: iTerm2, Terminal.app, GNOME Terminal, Windows Terminal, tmux и других. -В средах без поддержки цвета (например, при перенаправлении вывода в файл) escape-коды будут видны как есть. При необходимости отключения цвета — установите переменную `NO_COLOR=1` перед запуском или реализуйте проверку `os.Getenv("NO_COLOR")` в `utils/display.go`. \ No newline at end of file +В средах без поддержки цвета (например, при перенаправлении вывода в файл) escape-коды будут видны как есть. При необходимости отключения цвета — установите переменную `NO_COLOR=1` перед запуском или реализуйте проверку `os.Getenv("NO_COLOR")` в `utils/display.go`. diff --git a/catalog/catalog.go b/catalog/catalog.go index 4d1c403..8608284 100644 --- a/catalog/catalog.go +++ b/catalog/catalog.go @@ -20,7 +20,7 @@ type Book struct { // All — список всех справочников var All = []Book{ GoBook, - // LinuxBook — будет добавлен позже + LinuxBook, } // Find ищет книгу по ключу или алиасу diff --git a/catalog/linuxbook.go b/catalog/linuxbook.go new file mode 100644 index 0000000..e28ccec --- /dev/null +++ b/catalog/linuxbook.go @@ -0,0 +1,115 @@ +package catalog + +import ( + "bufio" + "fmt" + "rubric/modules/linuxmodules" + "rubric/utils" + "strconv" + "strings" +) + +// LinuxBook — запись справочника Linux в главном меню +var LinuxBook = Book{ + Key: "linux", + Aliases: []string{"l", "lnx"}, + Title: "Справочник по GNU/Linux", + Description: "Основы GNU/Linux: файлы, процессы, сети, systemd, bash-скрипты и многое другое", + Run: runLinuxBook, +} + +func runLinuxBook(scanner *bufio.Scanner) { + for { + showLinuxMenu() + + input, ok := ReadLine(scanner) + if !ok { + return + } + if input == "" { + continue + } + if IsQuit(input) { + fmt.Printf("\n %s%sДо свидания!%s\n\n", + utils.ColorBold, utils.ColorCyan, utils.ColorReset) + return + } + if IsBack(input) { + return + } + + // По номеру + if n, err := strconv.Atoi(input); err == nil { + if n >= 1 && n <= len(linuxmodules.All) { + linuxmodules.All[n-1].Run() + waitLinuxBack(scanner) + continue + } + fmt.Printf("\n %s%sНомер %d вне диапазона (1–%d)%s\n", + utils.ColorBold, utils.ColorRed, n, len(linuxmodules.All), utils.ColorReset) + continue + } + + // По ключу + if m, ok := linuxmodules.Find(input); ok { + m.Run() + waitLinuxBack(scanner) + continue + } + + fmt.Printf("\n %s%sНе понял '%s'. Номер, ключ раздела, b — назад.%s\n", + utils.ColorBold, utils.ColorRed, input, utils.ColorReset) + } +} + +func showLinuxMenu() { + utils.Header("Справочник GNU/Linux") + + fmt.Printf(" %s%sРазделы:%s\n\n", + utils.ColorBold, utils.ColorWhite, utils.ColorReset) + + for i, m := range linuxmodules.All { + aliases := "" + if len(m.Aliases) > 0 { + aliases = fmt.Sprintf("%s [%s]%s", + utils.ColorDim, strings.Join(m.Aliases, ", "), utils.ColorReset) + } + fmt.Printf(" %s%s %2d.%s %s%-12s%s %s%-30s%s%s\n", + utils.ColorBold, utils.ColorCyan, i+1, utils.ColorReset, + utils.ColorYellow+utils.ColorBold, m.Key, utils.ColorReset, + utils.ColorWhite, m.Title, utils.ColorReset, + aliases, + ) + fmt.Printf(" %s%s%s\n\n", + utils.ColorDim, m.Description, utils.ColorReset) + } + + fmt.Printf(" %s%sРаздел (номер / ключ / b — главное меню / q — выход):%s ", + utils.ColorBold, utils.ColorGreen, utils.ColorReset) +} + +type linuxBackSignal struct{} + +func waitLinuxBack(scanner *bufio.Scanner) { + fmt.Printf("\n %s%s[Enter — назад в меню Linux, b — главное меню]%s ", + utils.ColorDim, utils.ColorCyan, utils.ColorReset) + if scanner.Scan() { + if IsBack(strings.TrimSpace(scanner.Text())) { + panic(linuxBackSignal{}) + } + } +} + +func init() { + orig := LinuxBook.Run + LinuxBook.Run = func(scanner *bufio.Scanner) { + defer func() { + if r := recover(); r != nil { + if _, ok := r.(linuxBackSignal); !ok { + panic(r) + } + } + }() + orig(scanner) + } +} diff --git a/main.go b/main.go index 266f0e1..270432f 100644 --- a/main.go +++ b/main.go @@ -7,11 +7,12 @@ import ( "os" "rubric/catalog" "rubric/modules/gomodules" + "rubric/modules/linuxmodules" "rubric/utils" ) func main() { - book := flag.String("book", "", "открыть справочник напрямую (например: -book go)") + book := flag.String("book", "", "открыть справочник напрямую (go, linux)") topic := flag.String("topic", "", "открыть раздел (используется вместе с -book)") list := flag.Bool("list", false, "список всех справочников и разделов") help := flag.Bool("help", false, "справка по использованию") @@ -29,7 +30,7 @@ func main() { return } - // -book go -topic basics + // -book X -topic Y if *book != "" && *topic != "" { switch *book { case "go", "g", "golang": @@ -41,6 +42,15 @@ func main() { os.Exit(1) } m.Run() + case "linux", "l", "lnx": + m, ok := linuxmodules.Find(*topic) + if !ok { + fmt.Printf("\n %s%sРаздел '%s' не найден в справочнике Linux.%s\n", + utils.ColorBold, utils.ColorRed, *topic, utils.ColorReset) + linuxmodules.ListModules() + os.Exit(1) + } + m.Run() default: fmt.Printf("\n %s%sСправочник '%s' не найден.%s\n", utils.ColorBold, utils.ColorRed, *book, utils.ColorReset) @@ -50,7 +60,7 @@ func main() { return } - // -book go + // -book X if *book != "" { b, ok := catalog.Find(*book) if !ok { diff --git a/modules/linuxmodules/linux_backup.go b/modules/linuxmodules/linux_backup.go new file mode 100644 index 0000000..8928da4 --- /dev/null +++ b/modules/linuxmodules/linux_backup.go @@ -0,0 +1,189 @@ +package linuxmodules + +import ( + "rubric/utils" +) + +var BackupModule = Module{ + Key: "backup", + Aliases: []string{"bk", "tar", "бэкап"}, + Title: "Резервное копирование", + Description: "Темы 38–40: tar, инкрементальные бэкапы, rsync, VDO", + Run: showBackup, +} + +func showBackup() { + utils.Header("Linux — Резервное копирование") + + // ─── 38. tar ────────────────────────────────────────────────── + utils.Section("38. Создание бэкапов с tar") + + utils.Println("tar — основной инструмент архивирования в Linux.") + utils.Println(utils.ColorBold + "\nОсновные флаги tar:" + utils.ColorReset) + utils.Code(`c — create (создать архив) +x — extract (извлечь) +t — list (показать содержимое) +v — verbose (подробный вывод) +f — file (имя файла архива) +z — gzip (сжатие gzip, .tar.gz / .tgz) +j — bzip2 (сжатие bzip2, .tar.bz2) +J — xz (сжатие xz, .tar.xz) +p — preserve permissions (сохранить права) +C — change directory (распаковать в указанную папку)`) + + utils.Println(utils.ColorBold + "Создание архива:" + utils.ColorReset) + utils.Code(`# Создать архив: +tar -cvf archive.tar /path/to/dir # без сжатия +tar -czvf archive.tar.gz /etc/ # с gzip +tar -cjvf archive.tar.bz2 /var/www/ # с bzip2 +tar -cJvf archive.tar.xz /home/alice/ # с xz (медленнее, лучше) + +# Создать с меткой даты: +tar -czvf backup_$(date +%Y%m%d_%H%M).tar.gz /etc/ + +# Исключить директории: +tar -czvf backup.tar.gz /home/ \ + --exclude=/home/.cache \ + --exclude='/home/*/.local' + +# Архивировать только изменённые файлы: +tar -czvf backup.tar.gz --newer "2024-01-01" /home/`) + + utils.Println(utils.ColorBold + "Извлечение архива:" + utils.ColorReset) + utils.Code(`# Извлечь в текущую директорию: +tar -xvf archive.tar +tar -xzvf archive.tar.gz + +# Извлечь в указанную директорию: +tar -xzvf archive.tar.gz -C /tmp/restore/ + +# Извлечь только конкретные файлы: +tar -xzvf archive.tar.gz etc/nginx/nginx.conf + +# Просмотр содержимого без распаковки: +tar -tzvf archive.tar.gz +tar -tzvf archive.tar.gz | grep nginx`) + + utils.Println(utils.ColorBold + "rsync — синхронизация файлов:" + utils.ColorReset) + utils.Code(`# Базовый синтаксис: rsync [опции] источник назначение + +# Опции: +-a — архивный режим (-rlptgoD: рекурсия, права, время...) +-v — verbose +-z — сжатие при передаче +-P — прогресс + продолжение +-n — dry-run (симуляция без изменений) +--delete — удалять файлы которых нет в источнике +-e ssh — использовать SSH + +# Локальная синхронизация: +rsync -av /source/ /dest/ # / после source — содержимое (без самой папки) +rsync -av /source /dest/ # без / — копирует саму папку + +# По сети через SSH: +rsync -avzP /home/alice/ user@server:/backup/alice/ +rsync -avzP user@server:/data/ /local/backup/ + +# Зеркало (с удалением лишнего): +rsync -av --delete /source/ /mirror/ + +# Бэкап с сохранением удалённых файлов: +rsync -av --backup --backup-dir=/backup/old-$(date +%Y%m%d) \ + --delete /source/ /mirror/`) + + // ─── 39. Инкрементальные бэкапы ─────────────────────────────── + utils.Section("39. Инкрементальные бэкапы с tar") + + utils.Println("Инкрементальный бэкап — сохраняет только изменения с момента последнего бэкапа.") + utils.Code(`# tar поддерживает инкрементальные бэкапы через snapshot-файл. +# Snapshot хранит список файлов и время последнего изменения. + +# Полный бэкап (level 0): +tar -czvf backup_full_$(date +%Y%m%d).tar.gz \ + --listed-incremental=/var/backup/snapshot.snar \ + /home/ + +# Инкрементальный бэкап (только изменения): +tar -czvf backup_incr_$(date +%Y%m%d_%H%M).tar.gz \ + --listed-incremental=/var/backup/snapshot.snar \ + /home/ + +# Восстановление: сначала полный, затем все инкрементальные по порядку: +tar -xzvf backup_full_20240101.tar.gz \ + --listed-incremental=/dev/null -C /restore/ +tar -xzvf backup_incr_20240102.tar.gz \ + --listed-incremental=/dev/null -C /restore/ + +# Просмотр инкрементального архива: +tar -tzvf backup_incr.tar.gz --listed-incremental=/dev/null`) + + utils.Println(utils.ColorBold + "Скрипт автоматического бэкапа:" + utils.ColorReset) + utils.Code(`#!/bin/bash +set -euo pipefail + +BACKUP_DIR="/backup" +SOURCE="/home /etc /var/www" +SNAPSHOT="/var/backup/snapshot.snar" +DATE=$(date +%Y%m%d_%H%M) +LOG="/var/log/backup.log" + +log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG"; } + +log "Начало бэкапа" + +# Полный бэкап по воскресеньям, инкрементальный остальные дни: +if [ "$(date +%u)" -eq 7 ]; then + cp "$SNAPSHOT" "${SNAPSHOT}.prev" 2>/dev/null || true + ARCHIVE="$BACKUP_DIR/full_$DATE.tar.gz" + tar -czvf "$ARCHIVE" --listed-incremental="$SNAPSHOT" $SOURCE + log "Полный бэкап: $ARCHIVE" +else + ARCHIVE="$BACKUP_DIR/incr_$DATE.tar.gz" + tar -czvf "$ARCHIVE" --listed-incremental="$SNAPSHOT" $SOURCE + log "Инкрементальный бэкап: $ARCHIVE" +fi + +# Удалить старые бэкапы (оставить за 30 дней): +find "$BACKUP_DIR" -name "*.tar.gz" -mtime +30 -delete +log "Старые бэкапы очищены. Готово."`) + + // ─── 40. VDO ────────────────────────────────────────────────── + utils.Section("40. Дедупликация с VDO (Virtual Data Optimizer)") + + utils.Println("VDO — технология RHEL для дедупликации и сжатия данных на блочном уровне.") + utils.Println("Уменьшает занимаемое место на диске без изменения работы приложений.") + utils.Code(`# VDO доступен в RHEL/CentOS. Установка: +dnf install vdo kmod-kvdo + +# Создать VDO-устройство поверх блочного (/dev/sdb): +vdo create --name=vdo_data \ + --device=/dev/sdb \ + --vdoLogicalSize=100G # виртуальный размер (больше физического) + +# Посмотреть VDO-устройства: +vdo list +vdo status --name=vdo_data + +# Создать ФС на VDO: +mkfs.ext4 -E nodiscard /dev/mapper/vdo_data +mount /dev/mapper/vdo_data /mnt/data + +# Статистика экономии: +vdostats --human-readable +# Показывает: физический размер / использовано / коэффициент сжатия + +# VDO в /etc/fstab: +/dev/mapper/vdo_data /mnt/data ext4 defaults,x-systemd.requires=vdo.service 0 2 + +# Запустить/остановить: +vdo start --name=vdo_data +vdo stop --name=vdo_data + +# Удалить VDO: +vdo remove --name=vdo_data --force`) + + utils.Note("VDO хорошо работает для виртуализации, контейнеров и бэкапов — там много одинаковых данных.") + utils.Note("LVM 2.3+ поддерживает VDO напрямую через lvcreate --type vdo.") + + utils.Footer() +} diff --git a/modules/linuxmodules/linux_bash.go b/modules/linuxmodules/linux_bash.go new file mode 100644 index 0000000..30be653 --- /dev/null +++ b/modules/linuxmodules/linux_bash.go @@ -0,0 +1,238 @@ +package linuxmodules + +import ( + "fmt" + "rubric/utils" +) + +var BashModule = Module{ + Key: "bash", + Aliases: []string{"sh", "shell", "баш"}, + Title: "Bash: основы и переменные", + Description: "Темы 12–13: bash-completion, alias, type, переменные окружения", + Run: showBash, +} + +func showBash() { + utils.Header("Linux — Bash: основы и переменные") + + // ─── 12. Bash #1 ────────────────────────────────────────────── + utils.Section("12. Bash #1: bash-completion, alias, type") + + utils.Println(utils.ColorBold + "bash-completion — автодополнение Tab:" + utils.ColorReset) + utils.Code(`Tab — дополнить команду / путь / аргумент +Tab Tab — показать все варианты + +# Примеры: +git che → git checkout +ls /etc/sy → ls /etc/systemd/ +ssh us → ssh user@hostname (из ~/.ssh/config) +systemctl st → systemctl start/status/stop + +# Установить расширенный bash-completion: +# Debian/Ubuntu: apt install bash-completion +# RHEL/Fedora: dnf install bash-completion +# Активировать в ~/.bashrc: +[ -f /etc/bash_completion ] && . /etc/bash_completion`) + + utils.Println(utils.ColorBold + "alias — псевдонимы команд:" + utils.ColorReset) + utils.Code(`# Посмотреть все алиасы: +alias + +# Создать алиас (действует до конца сессии): +alias ll='ls -la' +alias la='ls -la' +alias ..='cd ..' +alias ...='cd ../..' +alias grep='grep --color=auto' +alias rm='rm -i' # защита от случайного удаления +alias df='df -h' +alias free='free -h' +alias update='sudo apt update && sudo apt upgrade' + +# Использование алиаса: +ll /etc + +# Удалить алиас: +unalias ll + +# Посмотреть что делает алиас: +alias ll`) + + utils.Println(utils.ColorBold + "Постоянные алиасы — добавить в ~/.bashrc:" + utils.ColorReset) + utils.Code(`# ~/.bashrc +alias ll='ls -la --color=auto' +alias la='ls -la' +alias l='ls -CF' +alias ..='cd ..' +alias grep='grep --color=auto' +alias h='history' +alias c='clear' + +# Применить без перезапуска терминала: +source ~/.bashrc +# или: +. ~/.bashrc`) + + utils.Println(utils.ColorBold + "type — определить тип команды:" + utils.ColorReset) + utils.Code(`type ls +# ls is aliased to 'ls --color=auto' + +type cd +# cd is a shell builtin + +type python3 +# python3 is /usr/bin/python3 + +type ll +# ll is aliased to 'ls -la' + +type if +# if is a shell keyword + +# Опции: +type -a ls # все варианты (алиас + файл) +type -t ls # только тип: alias/builtin/file/keyword`) + + utils.Println(utils.ColorBold + "which и whereis:" + utils.ColorReset) + utils.Command("which python3", "полный путь к исполняемому файлу") + utils.Command("which -a python", "все версии python в PATH") + utils.Command("whereis nginx", "бинарник, исходники, man-страница") + utils.Command("command -v git", "путь или алиас (POSIX-совместимо)") + fmt.Println() + utils.Println(utils.ColorBold + "Работа с историей команд:" + utils.ColorReset) + utils.Command("history", "полная история") + utils.Command("history 20", "последние 20 команд") + utils.Command("!42", "выполнить команду №42") + utils.Command("!!", "повторить последнюю команду") + utils.Command("!ls", "последняя команда начинающаяся с ls") + utils.Command("Ctrl+R", "интерактивный поиск по истории") + utils.Command("history -c", "очистить историю") + fmt.Println() + utils.Code(`# Файл истории: ~/.bash_history +# Управление историей через переменные в ~/.bashrc: +HISTSIZE=10000 # размер в памяти +HISTFILESIZE=20000 # размер файла +HISTCONTROL=ignoredups # не сохранять дубли +HISTCONTROL=ignorespace # команды с пробелом впереди не сохраняются +# Временные метки в истории: +HISTTIMEFORMAT="%F %T "`) + + // ─── 13. Bash #2: переменные ────────────────────────────────── + utils.Section("13. Bash #2: переменные") + + utils.Println(utils.ColorBold + "Переменные оболочки:" + utils.ColorReset) + utils.Code(`# Создать переменную: +name="Alice" # без пробелов вокруг = +count=42 +PATH_BACKUP=$PATH # использовать значение другой переменной + +# Использовать переменную ($ перед именем): +echo $name # Alice +echo "Привет, $name!" # Привет, Alice! +echo "Привет, ${name}!" # фигурные скобки — явное обозначение + +# Удалить переменную: +unset name`) + + utils.Println(utils.ColorBold + "Переменные окружения (Environment Variables):" + utils.ColorReset) + utils.Code(`# Переменные оболочки vs переменные окружения: +# - переменная оболочки видна только в текущем shell +# - переменная окружения (export) передаётся дочерним процессам + +# Экспортировать: +export name="Alice" +export PATH="$PATH:/opt/myapp/bin" + +# Или сразу: +export count=42 + +# Посмотреть все переменные окружения: +env +printenv +printenv PATH # конкретная переменная +echo $PATH # то же`) + + utils.Println(utils.ColorBold + "Важные системные переменные:" + utils.ColorReset) + utils.Code(`PATH — список директорий для поиска команд (: разделитель) + /usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin +HOME — домашняя директория (~) /home/alice +USER — имя пользователя alice +LOGNAME — логин пользователя alice +SHELL — оболочка пользователя /bin/bash +TERM — тип терминала xterm-256color +LANG — язык/локаль en_US.UTF-8 +LC_ALL — переопределить все локали +PWD — текущая директория /home/alice/docs +OLDPWD — предыдущая директория +PS1 — приглашение командной строки +PS2 — вторичное приглашение (>) +EDITOR — редактор по умолчанию vim +VISUAL — визуальный редактор vim +PAGER — пагинатор less +HISTSIZE — размер истории в памяти +RANDOM — случайное число 0-32767`) + + utils.Println(utils.ColorBold + "Специальные переменные bash:" + utils.ColorReset) + utils.Code(`$0 — имя скрипта / оболочки +$1..$9 — позиционные параметры (аргументы скрипта) +$@ — все аргументы как отдельные строки +$* — все аргументы как одна строка +$# — количество аргументов +$? — код возврата последней команды (0 = успех) +$$ — PID текущего процесса +$! — PID последнего фонового процесса +$_ — последний аргумент предыдущей команды`) + + utils.Code(`# Примеры: +echo $? # 0 если последняя команда успешна +ls /nonexistent +echo $? # 2 (или другой ненулевой) — ошибка + +echo $$ # PID bash +echo $RANDOM # случайное число`) + + utils.Println(utils.ColorBold + "Работа со строками переменных:" + utils.ColorReset) + utils.Code(`name="alice" + +${name} → alice +${name^} → Alice (первая буква заглавная) +${name^^} → ALICE (все заглавные) +${name,,} → alice (все строчные) + +str="hello world" +${#str} → 11 (длина строки) +${str:0:5} → hello (подстрока с 0, длиной 5) +${str:6} → world (с позиции 6 до конца) + +path="/home/user/file.txt" +${path##*/} → file.txt (удалить до последнего /) +${path%/*} → /home/user (удалить от последнего /) +${path%.*} → /home/user/file (удалить расширение) +${path##*.} → txt (только расширение) + +# Значения по умолчанию: +${var:-default} → default если var не задана или пустая +${var:=default} → присвоить и вернуть default если пустая +${var:?ошибка} → вывести ошибку если пустая`) + + utils.Println(utils.ColorBold + "Настройка ~/.bashrc и ~/.bash_profile:" + utils.ColorReset) + utils.Code(`~/.bashrc — выполняется при каждом запуске интерактивного bash +~/.bash_profile — выполняется при входе в систему (login shell) +~/.profile — POSIX-совместимый аналог .bash_profile +~/.bash_logout — выполняется при выходе + +# Типичный ~/.bashrc: +export PATH="$HOME/.local/bin:$PATH" +export EDITOR=vim +alias ll='ls -la' +alias ..='cd ..' + +# ~/.bash_profile обычно вызывает ~/.bashrc: +[[ -f ~/.bashrc ]] && . ~/.bashrc + +# Применить изменения без перезапуска: +source ~/.bashrc`) + + utils.Footer() +} diff --git a/modules/linuxmodules/linux_boot.go b/modules/linuxmodules/linux_boot.go new file mode 100644 index 0000000..887ce72 --- /dev/null +++ b/modules/linuxmodules/linux_boot.go @@ -0,0 +1,223 @@ +package linuxmodules + +import ( + "fmt" + "rubric/utils" +) + +var BootModule = Module{ + Key: "boot", + Aliases: []string{"bo", "systemd", "grub", "загрузка"}, + Title: "Загрузка системы и systemd", + Description: "Темы 33–35, 41: GRUB, systemd, юниты, управление сервисами", + Run: showBoot, +} + +func showBoot() { + utils.Header("Linux — Загрузка системы и systemd") + + // ─── 33. GRUB ───────────────────────────────────────────────── + utils.Section("33. Загрузчик GRUB") + + utils.Println("Процесс загрузки Linux:") + utils.Code(`BIOS/UEFI → MBR/GPT → GRUB → Ядро (vmlinuz) → initrd/initramfs → /sbin/init (systemd) → Сервисы → Пользователь + +BIOS/UEFI — инициализация железа, поиск загрузочного устройства +MBR/GPT — первый сектор диска, указывает где GRUB +GRUB — загрузчик, выбор ядра/ОС +vmlinuz — сжатое ядро Linux +initramfs — временная корневая ФС в памяти (для монтирования /) +systemd — PID 1, запускает все сервисы`) + + utils.Println(utils.ColorBold + "GRUB — конфигурация:" + utils.ColorReset) + utils.Code(`# Основные файлы: +/boot/grub/grub.cfg — итоговая конфигурация (не редактировать!) +/etc/grub.d/ — скрипты генерации конфига +/etc/default/grub — настройки + +# Редактировать настройки: +sudo nano /etc/default/grub + +# Ключевые параметры /etc/default/grub: +GRUB_DEFAULT=0 # пункт меню по умолчанию (0 = первый) +GRUB_TIMEOUT=5 # таймаут выбора (сек) +GRUB_CMDLINE_LINUX="" # параметры ядра для всех записей +GRUB_CMDLINE_LINUX_DEFAULT="quiet splash" # для обычной загрузки + +# Применить изменения: +sudo update-grub # Debian/Ubuntu +sudo grub2-mkconfig -o /boot/grub2/grub.cfg # RHEL/Fedora`) + + utils.Println(utils.ColorBold + "GRUB — установка и восстановление:" + utils.ColorReset) + utils.Code(`# Установить GRUB на диск: +sudo grub-install /dev/sda # Debian/Ubuntu +sudo grub2-install /dev/sda # RHEL/Fedora + +# Восстановление GRUB через LiveCD: +mount /dev/sda2 /mnt # корневой раздел +mount /dev/sda1 /mnt/boot/efi # EFI раздел (UEFI) +mount --bind /dev /mnt/dev +mount --bind /proc /mnt/proc +mount --bind /sys /mnt/sys +chroot /mnt +grub-install /dev/sda +update-grub +exit; reboot`) + + utils.Println(utils.ColorBold + "Параметры ядра при загрузке:" + utils.ColorReset) + utils.Code(`# Нажать 'e' в меню GRUB для редактирования записи. +# Найти строку linux/linuxefi и добавить параметры в конец: + +ro quiet splash — стандартная загрузка +rw single — однопользовательский режим (recovery) +init=/bin/bash — минимальный shell (без systemd) +nomodeset — без KMS (проблемы с видео) +rd.break — остановить в initramfs (RHEL) +systemd.unit=rescue.target — аварийный режим`) + + // ─── 34. systemd ────────────────────────────────────────────── + utils.Section("34. Система инициализации — systemd") + + utils.Println("systemd — PID 1. Управляет всеми сервисами, монтированием, логами.") + fmt.Println() + utils.Println(utils.ColorBold + "Юниты (Units):" + utils.ColorReset) + utils.Code(`Юнит — объект управления systemd. +Типы юнитов: +.service — сервис (nginx.service, sshd.service) +.socket — сокет (активация по запросу) +.target — группа юнитов (graphical.target = GUI) +.timer — планировщик (альтернатива cron) +.mount — точка монтирования +.path — отслеживание файлов/директорий +.slice — группа процессов (управление ресурсами) + +# Расположение юнитов: +/lib/systemd/system/ — системные (из пакетов) +/etc/systemd/system/ — пользовательские (переопределение) +/run/systemd/system/ — временные (runtime)`) + + // ─── 35. Управление сервисами ───────────────────────────────── + utils.Section("35. Системный менеджер systemd: управление сервисами") + + utils.Println(utils.ColorBold + "systemctl — основные команды:" + utils.ColorReset) + utils.Command("systemctl status nginx", "статус сервиса") + utils.Command("systemctl start nginx", "запустить") + utils.Command("systemctl stop nginx", "остановить") + utils.Command("systemctl restart nginx", "перезапустить") + utils.Command("systemctl reload nginx", "перечитать конфигурацию") + utils.Command("systemctl enable nginx", "включить автозапуск") + utils.Command("systemctl disable nginx", "выключить автозапуск") + utils.Command("systemctl enable --now nginx", "включить и сразу запустить") + utils.Command("systemctl disable --now nginx", "выключить и остановить") + utils.Command("systemctl is-active nginx", "активен? (active/inactive)") + utils.Command("systemctl is-enabled nginx", "в автозапуске? (enabled/disabled)") + utils.Command("systemctl is-failed nginx", "завершился с ошибкой?") + fmt.Println() + utils.Command("systemctl list-units", "список всех активных юнитов") + utils.Command("systemctl list-units --type=service", "только сервисы") + utils.Command("systemctl list-units --failed", "упавшие юниты") + utils.Command("systemctl list-unit-files", "все юниты и их состояние") + utils.Command("systemctl daemon-reload", "перечитать файлы юнитов (после изменений)") + fmt.Println() + utils.Println(utils.ColorBold + "Таргеты (targets) — уровни запуска:" + utils.ColorReset) + utils.Code(`poweroff.target — выключение (runlevel 0) +rescue.target — однопользовательский (runlevel 1) +multi-user.target — многопользовательский без GUI (runlevel 3) +graphical.target — с GUI (runlevel 5) +reboot.target — перезагрузка (runlevel 6) + +# Текущий таргет: +systemctl get-default + +# Изменить таргет по умолчанию: +systemctl set-default multi-user.target + +# Переключиться немедленно: +systemctl isolate multi-user.target + +# Выключение и перезагрузка: +systemctl poweroff +systemctl reboot +systemctl suspend +systemctl hibernate`) + + utils.Println(utils.ColorBold + "journalctl — просмотр логов systemd:" + utils.ColorReset) + utils.Command("journalctl", "все логи") + utils.Command("journalctl -u nginx", "логи конкретного сервиса") + utils.Command("journalctl -f", "следить в реальном времени") + utils.Command("journalctl -f -u nginx", "следить за nginx") + utils.Command("journalctl -n 50", "последние 50 строк") + utils.Command("journalctl --since '2024-01-15 10:00'", "с определённого времени") + utils.Command("journalctl --since '1 hour ago'", "за последний час") + utils.Command("journalctl -p err", "только ошибки (emerg alert crit err warning notice info debug)") + utils.Command("journalctl -b", "с момента последней загрузки") + utils.Command("journalctl -b -1", "предыдущая загрузка") + utils.Command("journalctl --disk-usage", "объём логов на диске") + utils.Command("journalctl --vacuum-size=100M", "оставить только 100МБ логов") + + // ─── 41. Systemd юниты ──────────────────────────────────────── + utils.Section("41. Создание systemd юнитов") + + utils.Println(utils.ColorBold + "Структура .service файла:" + utils.ColorReset) + utils.Code(`# /etc/systemd/system/myapp.service +[Unit] +Description=My Application +Documentation=https://example.com +After=network.target # запустить после сети +Requires=postgresql.service # обязательная зависимость +Wants=redis.service # желательная зависимость + +[Service] +Type=simple # forking, oneshot, notify, idle +User=myapp # от какого пользователя +Group=myapp +WorkingDirectory=/opt/myapp +ExecStart=/opt/myapp/bin/myapp --config /etc/myapp.conf +ExecReload=/bin/kill -HUP $MAINPID +Restart=on-failure # always, on-failure, on-abnormal +RestartSec=5 +StandardOutput=journal +StandardError=journal +Environment=NODE_ENV=production +EnvironmentFile=/etc/myapp/env + +# Ограничения: +MemoryMax=512M +CPUQuota=50% +LimitNOFILE=65536 + +[Install] +WantedBy=multi-user.target`) + + utils.Code(`# Применить новый юнит: +sudo systemctl daemon-reload +sudo systemctl enable --now myapp + +# Переопределить параметры (без редактирования оригинала): +sudo systemctl edit nginx # создаёт /etc/systemd/system/nginx.service.d/override.conf`) + + utils.Println(utils.ColorBold + "Timer юнит (альтернатива cron):" + utils.ColorReset) + utils.Code(`# /etc/systemd/system/backup.timer +[Unit] +Description=Ежедневный бэкап + +[Timer] +OnCalendar=*-*-* 02:00:00 # каждый день в 02:00 +OnCalendar=Mon *-*-* 03:00 # каждый понедельник в 03:00 +OnBootSec=15min # через 15 мин после загрузки +OnUnitActiveSec=1h # каждый час после последнего запуска +Persistent=true # запустить если пропустили время + +[Install] +WantedBy=timers.target + +# /etc/systemd/system/backup.service +[Unit] +Description=Скрипт бэкапа + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/backup.sh`) + + utils.Footer() +} diff --git a/modules/linuxmodules/linux_disks.go b/modules/linuxmodules/linux_disks.go new file mode 100644 index 0000000..604e67e --- /dev/null +++ b/modules/linuxmodules/linux_disks.go @@ -0,0 +1,211 @@ +package linuxmodules + +import ( + "fmt" + "rubric/utils" +) + +var DisksModule = Module{ + Key: "disks", + Aliases: []string{"d", "lvm", "raid", "диски"}, + Title: "Диски, файловые системы, LVM и RAID", + Description: "Темы 22–26: разделы, mount, LVM, программный RAID", + Run: showDisks, +} + +func showDisks() { + utils.Header("Linux — Диски, файловые системы, LVM и RAID") + + // ─── 22. Работа с дисками ───────────────────────────────────── + utils.Section("22. Работа с дисками и разделами") + + utils.Println(utils.ColorBold + "Именование устройств:" + utils.ColorReset) + utils.Code(`/dev/sda — первый SATA/SCSI диск +/dev/sdb — второй диск +/dev/sda1 — первый раздел первого диска +/dev/sda2 — второй раздел первого диска +/dev/nvme0n1 — первый NVMe диск +/dev/nvme0n1p1 — первый раздел NVMe диска +/dev/vda — виртуальный диск (KVM/QEMU) +/dev/xvda — диск Xen +/dev/loop0 — loop-устройство (ISO-образ)`) + + utils.Println(utils.ColorBold + "Просмотр дисков и разделов:" + utils.ColorReset) + utils.Command("lsblk", "дерево блочных устройств") + utils.Command("lsblk -f", "с типом ФС и UUID") + utils.Command("lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,FSTYPE", "выбрать столбцы") + utils.Command("fdisk -l", "все диски и разделы (root)") + utils.Command("fdisk -l /dev/sda", "разделы диска sda") + utils.Command("parted -l", "таблицы разделов (GPT и MBR)") + utils.Command("blkid", "UUID и типы ФС всех устройств") + utils.Command("blkid /dev/sda1", "UUID конкретного раздела") + fmt.Println() + utils.Println(utils.ColorBold + "Разбивка диска (fdisk):" + utils.ColorReset) + utils.Code(`sudo fdisk /dev/sdb # интерактивная работа с разделами + +Команды fdisk: + p — показать таблицу разделов + n — новый раздел + d — удалить раздел + t — изменить тип раздела + l — список типов разделов + w — записать изменения (опасно!) + q — выйти без сохранения + +# Для GPT-дисков и дисков > 2ТБ — используйте parted или gdisk`) + + utils.Println(utils.ColorBold + "Создание файловой системы (mkfs):" + utils.ColorReset) + utils.Command("mkfs.ext4 /dev/sdb1", "создать ext4") + utils.Command("mkfs.xfs /dev/sdb1", "создать xfs") + utils.Command("mkfs.ext4 -L data /dev/sdb1", "с меткой 'data'") + utils.Command("mkswap /dev/sdb2", "создать swap") + utils.Command("swapon /dev/sdb2", "активировать swap") + utils.Command("swapon -s", "показать активные swap") + utils.Command("swapoff /dev/sdb2", "отключить swap") + fmt.Println() + utils.Println(utils.ColorBold + "Проверка и восстановление ФС:" + utils.ColorReset) + utils.Command("fsck /dev/sdb1", "проверить ФС (только при размонтированной!)") + utils.Command("fsck -n /dev/sdb1", "только проверить, не исправлять") + utils.Command("e2fsck -f /dev/sdb1", "принудительная проверка ext2/3/4") + utils.Command("xfs_repair /dev/sdb1", "восстановление XFS") + + utils.Println(utils.ColorBold + "Использование диска:" + utils.ColorReset) + utils.Command("df -h", "занятое и свободное место на ФС") + utils.Command("df -hT", "с типом ФС") + utils.Command("du -sh /var/log", "размер директории") + utils.Command("du -sh /*", "размер каждой директории в корне") + utils.Command("du -sh * | sort -h", "отсортировать по размеру") + utils.Command("ncdu /var", "интерактивный анализ (нужно установить)") + + // ─── 23–24. Файловые системы и монтирование ─────────────────── + utils.Section("23–24. Файловые системы и монтирование") + + utils.Println(utils.ColorBold + "mount — монтирование:" + utils.ColorReset) + utils.Command("mount", "список всех смонтированных ФС") + utils.Command("mount /dev/sdb1 /mnt/data", "монтировать раздел") + utils.Command("mount -t ext4 /dev/sdb1 /mnt", "указать тип ФС") + utils.Command("mount -o ro /dev/sdb1 /mnt", "только чтение") + utils.Command("mount -o remount,rw /", "перемонтировать с правами записи") + utils.Command("mount UUID=abc123 /mnt/data", "монтировать по UUID") + utils.Command("mount -a", "смонтировать всё из /etc/fstab") + utils.Command("umount /mnt/data", "размонтировать") + utils.Command("umount -l /mnt/data", "ленивое размонтирование (когда занято)") + utils.Command("lsof /mnt/data", "кто использует раздел (если umount отказывает)") + fmt.Println() + utils.Println(utils.ColorBold + "/etc/fstab — автомонтирование при старте:" + utils.ColorReset) + utils.Code(`# Формат: устройство точка_монтирования тип опции dump fsck +UUID=abc123 /mnt/data ext4 defaults 0 2 +/dev/sdb1 /mnt/data xfs defaults 0 0 +//server/share /mnt/smb cifs credentials=/etc/samba.creds 0 0 +tmpfs /tmp tmpfs defaults,size=2G 0 0 + +# Опции монтирования: +defaults — rw, suid, exec, auto, nouser, async +ro — только чтение +rw — чтение и запись +noexec — запрет запуска файлов +nosuid — игнорировать SUID/SGID биты +noatime — не обновлять atime (быстрее) +auto — монтировать при mount -a +noauto — не монтировать автоматически + +# Столбцы dump и fsck: +# dump: 0 = не бэкапить, 1 = бэкапить +# fsck: 0 = не проверять, 1 = / (первый), 2 = остальные`) + + utils.Note("Всегда используйте UUID вместо /dev/sdb1 в fstab — имена устройств могут меняться после перезагрузки.") + + // ─── 25. LVM ────────────────────────────────────────────────── + utils.Section("25. Управление логическими томами — LVM") + + utils.Println("LVM позволяет гибко управлять дисковым пространством:") + utils.Println("объединять несколько дисков, изменять размер томов без перезагрузки.") + fmt.Println() + utils.Code(`Структура LVM: +PV (Physical Volume) — физический диск или раздел (/dev/sdb) +VG (Volume Group) — группа PV, единый пул пространства +LV (Logical Volume) — логический том из VG (аналог раздела) + +PV: /dev/sdb /dev/sdc + ↓ ↓ + VG: vg_data (объединённое пространство) + ↓ + LV: /dev/vg_data/lv_web /dev/vg_data/lv_db`) + + utils.Println(utils.ColorBold + "Создание LVM:" + utils.ColorReset) + utils.Code(`# 1. Создать Physical Volume: +pvcreate /dev/sdb /dev/sdc +pvs # показать PV +pvdisplay # подробно + +# 2. Создать Volume Group: +vgcreate vg_data /dev/sdb /dev/sdc +vgs # показать VG +vgdisplay vg_data + +# 3. Создать Logical Volume: +lvcreate -L 20G -n lv_web vg_data # 20 ГБ +lvcreate -l 100%FREE -n lv_db vg_data # всё свободное +lvs # показать LV +lvdisplay /dev/vg_data/lv_web + +# 4. Создать ФС и смонтировать: +mkfs.ext4 /dev/vg_data/lv_web +mount /dev/vg_data/lv_web /var/www`) + + utils.Println(utils.ColorBold + "Расширение LV:" + utils.ColorReset) + utils.Code(`# Расширить LV на 10 ГБ: +lvextend -L +10G /dev/vg_data/lv_web + +# Расширить ФС (ext4): +resize2fs /dev/vg_data/lv_web + +# Одной командой (ext4): +lvextend -L +10G -r /dev/vg_data/lv_web # -r = resize ФС + +# Для XFS (только увеличение): +xfs_growfs /var/www`) + + utils.Println(utils.ColorBold + "Добавить диск в VG:" + utils.ColorReset) + utils.Code(`pvcreate /dev/sdd +vgextend vg_data /dev/sdd`) + + // ─── 26. Программный RAID ───────────────────────────────────── + utils.Section("26. Программный RAID — MD (mdadm)") + + utils.Println("RAID — избыточный массив для надёжности и/или производительности.") + fmt.Println() + utils.Code(`Уровни RAID: +RAID 0 — страйпинг (производительность), без избыточности +RAID 1 — зеркало (надёжность), нужно 2 диска, использует 50% +RAID 5 — страйп + чётность, нужно 3+ дисков, теряем 1 диск +RAID 6 — двойная чётность, нужно 4+ дисков, теряем 2 диска +RAID 10 — зеркало + страйп, нужно 4 диска, теряем до N/2`) + + utils.Println(utils.ColorBold + "mdadm — управление программным RAID:" + utils.ColorReset) + utils.Code(`# Создать RAID 1 из двух дисков: +mdadm --create /dev/md0 --level=1 --raid-devices=2 /dev/sdb /dev/sdc + +# Создать RAID 5: +mdadm --create /dev/md0 --level=5 --raid-devices=3 \ + /dev/sdb /dev/sdc /dev/sdd + +# Состояние массива: +cat /proc/mdstat # текущее состояние +mdadm --detail /dev/md0 # подробная информация + +# Сохранить конфигурацию: +mdadm --detail --scan >> /etc/mdadm/mdadm.conf + +# Добавить запасной диск: +mdadm /dev/md0 --add /dev/sde + +# Удалить диск из массива: +mdadm /dev/md0 --fail /dev/sdb +mdadm /dev/md0 --remove /dev/sdb + +# Остановить массив: +mdadm --stop /dev/md0`) + + utils.Footer() +} diff --git a/modules/linuxmodules/linux_files.go b/modules/linuxmodules/linux_files.go new file mode 100644 index 0000000..71652ed --- /dev/null +++ b/modules/linuxmodules/linux_files.go @@ -0,0 +1,266 @@ +package linuxmodules + +import ( + "fmt" + "rubric/utils" +) + +var FilesModule = Module{ + Key: "files", + Aliases: []string{"f", "dirs", "файлы"}, + Title: "Файлы и директории", + Description: "Темы 06–10: пути, cp/mv/rm, ссылки, чтение файлов, nano и vi", + Run: showFiles, +} + +func showFiles() { + utils.Header("Linux — Файлы и директории") + + // ─── 06. Пути и директории ──────────────────────────────────── + utils.Section("06. Пути и директории") + + utils.Println(utils.ColorBold + "Абсолютный и относительный пути:" + utils.ColorReset) + utils.Code(`Абсолютный: начинается с / + /home/user/documents/file.txt + +Относительный: относительно текущей директории + documents/file.txt (из /home/user) + ../другой/файл (.. — родительская директория) + ./скрипт.sh (. — текущая директория)`) + + utils.Println(utils.ColorBold + "Специальные обозначения:" + utils.ColorReset) + utils.Code(`. — текущая директория +.. — родительская директория +~ — домашняя директория текущего пользователя +~/ — то же самое, используется в путях: ~/docs +- — предыдущая директория (cd -)`) + + utils.Println(utils.ColorBold + "Навигация:" + utils.ColorReset) + utils.Command("pwd", "показать текущую директорию (Print Working Directory)") + utils.Command("cd /etc", "перейти в /etc (абсолютный путь)") + utils.Command("cd docs", "перейти в docs (относительный)") + utils.Command("cd ..", "перейти в родительскую директорию") + utils.Command("cd ~", "перейти домой") + utils.Command("cd -", "вернуться в предыдущую директорию") + utils.Command("cd", "то же что cd ~") + fmt.Println() + utils.Println(utils.ColorBold + "Просмотр содержимого:" + utils.ColorReset) + utils.Command("ls", "список файлов текущей директории") + utils.Command("ls -l", "длинный формат (права, владелец, размер, дата)") + utils.Command("ls -a", "все файлы включая скрытые (начинаются с .)") + utils.Command("ls -la", "длинный формат + скрытые") + utils.Command("ls -lh", "размер в читаемом виде (K, M, G)") + utils.Command("ls -lt", "сортировка по времени (новые сверху)") + utils.Command("ls -ltr", "по времени в обратном порядке") + utils.Command("ls -R", "рекурсивно (все вложенные)") + utils.Command("ls /etc/*.conf", "glob-паттерн: все .conf в /etc") + fmt.Println() + utils.Code(`# Пример вывода ls -l: +drwxr-xr-x 2 alice users 4096 Jan 15 10:30 docs +-rw-r--r-- 1 alice users 512 Jan 14 09:00 file.txt +lrwxrwxrwx 1 alice users 7 Jan 13 12:00 link -> file.txt +│ │ │ │ │ │ │ +│ │ │ │ │ │ └ имя файла +│ │ │ │ │ └ дата изменения +│ │ │ │ └ размер (байты) +│ │ │ └ группа +│ │ └ владелец +│ └ количество жёстких ссылок +└ тип и права доступа`) + + utils.Println(utils.ColorBold + "Создание директорий:" + utils.ColorReset) + utils.Command("mkdir mydir", "создать директорию") + utils.Command("mkdir -p a/b/c", "создать вложенные директории") + utils.Command("mkdir -p project/{src,docs,tests}", "создать несколько сразу") + utils.Command("rmdir mydir", "удалить пустую директорию") + + // ─── 07. Создание и копирование файлов ─────────────────────── + utils.Section("07. Создание и копирование файлов") + + utils.Println(utils.ColorBold + "Создание файлов:" + utils.ColorReset) + utils.Command("touch file.txt", "создать пустой файл / обновить время доступа") + utils.Command("touch file{1..5}.txt", "создать file1.txt … file5.txt") + utils.Command("> file.txt", "создать пустой файл / очистить существующий") + utils.Command("echo 'текст' > file.txt", "записать текст в файл") + utils.Command("echo 'текст' >> file.txt", "добавить текст в конец файла") + fmt.Println() + utils.Println(utils.ColorBold + "Копирование (cp):" + utils.ColorReset) + utils.Command("cp src dst", "скопировать файл") + utils.Command("cp -r src/ dst/", "скопировать директорию рекурсивно") + utils.Command("cp -v src dst", "показать что копируется (-v = verbose)") + utils.Command("cp -i src dst", "спросить при перезаписи (-i = interactive)") + utils.Command("cp -p src dst", "сохранить права/метаданные (-p = preserve)") + utils.Command("cp -a src/ dst/", "архивный режим: -r + -p + символические ссылки") + utils.Command("cp *.txt /tmp/", "копировать все .txt в /tmp") + fmt.Println() + utils.Note("cp -r не сохраняет права и время по умолчанию. Для резервного копирования используйте cp -a.") + + // ─── 08. Перемещение, удаление, ссылки ─────────────────────── + utils.Section("08. Перемещение, переименование, удаление. Ссылки") + + utils.Println(utils.ColorBold + "Перемещение и переименование (mv):" + utils.ColorReset) + utils.Command("mv old.txt new.txt", "переименовать файл") + utils.Command("mv file.txt /tmp/", "переместить в /tmp") + utils.Command("mv -v src dst", "подробный вывод") + utils.Command("mv -i src dst", "спросить при перезаписи") + utils.Command("mv -n src dst", "не перезаписывать существующий") + fmt.Println() + utils.Println(utils.ColorBold + "Удаление (rm):" + utils.ColorReset) + utils.Command("rm file.txt", "удалить файл") + utils.Command("rm -r dir/", "удалить директорию рекурсивно") + utils.Command("rm -rf dir/", "принудительно, без подтверждений") + utils.Command("rm -i file.txt", "спросить перед удалением") + utils.Command("rm -v file.txt", "показать что удаляется") + fmt.Println() + utils.Note("rm -rf удаляет безвозвратно. Нет корзины. Будьте внимательны!") + utils.Code(`# Защита: никогда не делайте: +rm -rf / # удалит всю систему +rm -rf ./ # удалит текущую директорию + +# Безопаснее: перенести в /tmp, потом удалить +mv dangerous_dir /tmp/ && rm -rf /tmp/dangerous_dir`) + + utils.Println(utils.ColorBold + "Жёсткие ссылки (hard links):" + utils.ColorReset) + utils.Code(`Жёсткая ссылка — ещё одно имя для того же inode. + +ln file.txt hardlink.txt # создать жёсткую ссылку + +Особенности: +- указывает на те же данные на диске +- не отличить от оригинала командой ls +- удаление одного имени не удаляет данные + (данные удаляются когда счётчик ссылок = 0) +- нельзя создать на директорию +- нельзя создать на другой раздел/диске`) + + utils.Println(utils.ColorBold + "Символические ссылки (soft links / symlinks):" + utils.ColorReset) + utils.Code(`Символическая ссылка — файл, содержащий путь к цели. + +ln -s /etc/nginx/nginx.conf nginx.conf # создать симлинк +ln -s /path/to/dir mylink # симлинк на директорию +ls -la nginx.conf +# lrwxrwxrwx 1 user group 20 Jan nginx.conf -> /etc/nginx/nginx.conf + +Особенности: +- показывается как l в ls -la +- может указывать на директории +- может быть "битым" (цель удалена) +- можно создать между разными разделами +- readlink nginx.conf — показать куда указывает`) + + utils.Command("stat file.txt", "показать подробную информацию о файле (inode, ссылки)") + utils.Command("ls -i file.txt", "показать номер inode") + + // ─── 09. Чтение текстовых файлов ───────────────────────────── + utils.Section("09. Чтение текстовых файлов") + + utils.Command("cat file.txt", "вывести весь файл") + utils.Command("cat -n file.txt", "с номерами строк") + utils.Command("cat -A file.txt", "показать спецсимволы ($ в конце строк)") + utils.Command("cat f1 f2 > merged", "объединить файлы") + fmt.Println() + utils.Command("less file.txt", "постраничный просмотр (рекомендуется для больших файлов)") + utils.Command("more file.txt", "постраничный просмотр (только вперёд)") + fmt.Println() + utils.Code(`Навигация в less: + Space / PgDn — следующая страница + b / PgUp — предыдущая страница + g / G — начало / конец файла + /паттерн — поиск вперёд + ?паттерн — поиск назад + n / N — следующее / предыдущее совпадение + q — выход`) + + utils.Command("head file.txt", "первые 10 строк") + utils.Command("head -n 20 file.txt", "первые 20 строк") + utils.Command("head -c 100 file.txt", "первые 100 байт") + utils.Command("tail file.txt", "последние 10 строк") + utils.Command("tail -n 30 file.txt", "последние 30 строк") + utils.Command("tail -f /var/log/syslog", "следить за файлом в реальном времени") + utils.Command("tail -F /var/log/nginx/access.log", "следить, даже если файл пересоздаётся") + fmt.Println() + utils.Command("grep 'текст' file.txt", "поиск строк содержащих 'текст'") + utils.Command("grep -i 'TEXT' file.txt", "без учёта регистра") + utils.Command("grep -r 'текст' /etc/", "рекурсивный поиск в директории") + utils.Command("grep -n 'текст' file.txt", "с номерами строк") + utils.Command("grep -v 'текст' file.txt", "строки НЕ содержащие 'текст'") + utils.Command("grep -c 'текст' file.txt", "количество совпадений") + utils.Command("grep -l 'текст' *.conf", "только имена файлов с совпадениями") + fmt.Println() + utils.Command("wc file.txt", "количество строк, слов, байт") + utils.Command("wc -l file.txt", "только строки") + utils.Command("wc -w file.txt", "только слова") + utils.Command("sort file.txt", "сортировать строки") + utils.Command("sort -r file.txt", "в обратном порядке") + utils.Command("sort -n file.txt", "числовая сортировка") + utils.Command("sort -u file.txt", "убрать дубли (unique)") + utils.Command("uniq file.txt", "убрать соседние одинаковые строки") + utils.Command("cut -d: -f1 /etc/passwd", "вырезать первое поле (разделитель :)") + utils.Command("cut -d, -f2,4 data.csv", "поля 2 и 4 из CSV") + utils.Command("tr 'a-z' 'A-Z' < file.txt", "заменить символы (нижний → верхний регистр)") + utils.Command("diff file1 file2", "сравнить два файла") + utils.Command("diff -u file1 file2", "unified-формат (как git diff)") + + // ─── 10. Текстовые редакторы ────────────────────────────────── + utils.Section("10. Текстовые редакторы: nano и vi/vim") + + utils.Println(utils.ColorBold + "nano — простой редактор:" + utils.ColorReset) + utils.Command("nano file.txt", "открыть файл в nano") + utils.Code(`Основные сочетания клавиш в nano: + Ctrl+O — сохранить (Write Out) + Ctrl+X — выйти + Ctrl+K — вырезать строку + Ctrl+U — вставить + Ctrl+W — поиск + Ctrl+\ — замена + Ctrl+G — справка + Alt+U — отменить (undo)`) + + utils.Println(utils.ColorBold + "vi / vim — мощный редактор:" + utils.ColorReset) + utils.Command("vi file.txt", "открыть в vi") + utils.Command("vim file.txt", "открыть в vim (улучшенный vi)") + fmt.Println() + utils.Code(`Режимы vim: + Нормальный (Normal) — навигация, команды. По умолчанию. + Вставки (Insert) — ввод текста. Нажать i. + Командный (Command) — команды (:). Нажать : + Визуальный (Visual) — выделение. Нажать v. + +Переключение: + i — режим вставки перед курсором + a — режим вставки после курсора + o — новая строка ниже, режим вставки + O — новая строка выше, режим вставки + Esc — вернуться в нормальный режим`) + + utils.Code(`Навигация (нормальный режим): + h j k l — ← ↓ ↑ → + w / b — следующее / предыдущее слово + 0 / $ — начало / конец строки + gg / G — начало / конец файла + :n — перейти на строку n + Ctrl+F/B — вперёд / назад на страницу + +Редактирование: + dd — удалить строку + yy — скопировать строку (yank) + p — вставить после курсора + P — вставить перед курсором + u — отменить (undo) + Ctrl+R — повторить (redo) + /текст — поиск вперёд + n / N — следующее / предыдущее совпадение + :%s/old/new/g — заменить все вхождения + +Сохранение и выход: + :w — сохранить + :q — выйти + :wq или ZZ — сохранить и выйти + :q! — выйти без сохранения + :wq! — принудительно сохранить и выйти`) + + utils.Note("Если застряли в vi — нажмите Esc несколько раз, затем :q! для выхода без сохранения.") + utils.Note("vimtutor — встроенный интерактивный учебник по vim (30 мин). Запустите в терминале.") + + utils.Footer() +} diff --git a/modules/linuxmodules/linux_intro.go b/modules/linuxmodules/linux_intro.go new file mode 100644 index 0000000..78832f0 --- /dev/null +++ b/modules/linuxmodules/linux_intro.go @@ -0,0 +1,161 @@ +package linuxmodules + +import ( + "fmt" + "rubric/utils" +) + +var IntroModule = Module{ + Key: "intro", + Aliases: []string{"i", "os", "начало"}, + Title: "Введение. ОС и GNU/Linux", + Description: "Темы 01, 04, 05: операционные системы, файловые системы, терминал", + Run: showIntro, +} + +func showIntro() { + utils.Header("Linux — Введение. ОС и GNU/Linux") + + // ─── 01. Операционные системы и GNU/Linux ───────────────────── + utils.Section("01. Операционные системы и GNU/Linux") + + utils.Println("Операционная система (ОС) — программа, управляющая аппаратурой и") + utils.Println("предоставляющая среду для работы прикладных программ.") + fmt.Println() + utils.Println(utils.ColorBold + "Ключевые понятия:" + utils.ColorReset) + utils.Code(`Ядро (kernel) — центральная часть ОС, управляет памятью, + процессами, устройствами. +Userspace — пространство пользователя, где работают + обычные программы. +Дистрибутив — ядро Linux + набор программ + система управления + пакетами (Debian, Ubuntu, RHEL, Fedora, Arch...).`) + + utils.Println(utils.ColorBold + "История:" + utils.ColorReset) + utils.Code(`1969 — AT&T Bell Labs: UNIX (Ричи, Томпсон) +1983 — Ричард Столлман: проект GNU (свободное ПО) +1991 — Линус Торвальдс: ядро Linux (v0.01) + = GNU/Linux: ядро Linux + утилиты GNU +POSIX — стандарт совместимости UNIX-подобных систем`) + + utils.Println(utils.ColorBold + "GNU/Linux vs другие ОС:" + utils.ColorReset) + utils.Code(`Linux Windows macOS +───────────────────────────────────────────── +Открытый код Закрытый Частично открытый +Бесплатно Платный Платный (только на Mac) +Пакетный менеджер Магазин/exe App Store/Homebrew +Множество дистро Одна система Одна система +Сильный CLI GUI-ориентирован CLI через zsh/bash`) + + utils.Note("Серверы: >90% работают на Linux. Android — ядро Linux. Суперкомпьютеры: 100% Linux.") + utils.Note("RHEL (Red Hat Enterprise Linux) — коммерческий дистрибутив; RHCSA — его сертификация.") + + // ─── 04. О файловых системах ────────────────────────────────── + utils.Section("04. О файловых системах") + + utils.Println("Файловая система (ФС) — способ организации хранения данных на диске.") + fmt.Println() + utils.Println(utils.ColorBold + "Популярные файловые системы Linux:" + utils.ColorReset) + utils.Code(`ext4 — стандарт для большинства дистрибутивов, + журналирование, поддержка файлов до 16 ТБ +xfs — высокая производительность, RHEL по умолчанию, + хорошо для больших файлов +btrfs — Copy-on-Write, снапшоты, сжатие +vfat — совместимость с Windows (флешки, EFI-раздел) +ntfs — чтение/запись Windows-разделов (ntfs-3g) +tmpfs — виртуальная ФС в оперативной памяти (/tmp, /run) +proc — виртуальная ФС, информация о процессах (/proc) +sysfs — виртуальная ФС, информация об устройствах (/sys)`) + + utils.Println(utils.ColorBold + "Структура файловой системы Linux (FHS):" + utils.ColorReset) + utils.Code(`/ — корень, начало всего дерева +├── bin/ — основные бинарные файлы (ls, cp, mv...) +├── sbin/ — системные бинарники (root: fdisk, mount...) +├── etc/ — конфигурационные файлы +├── home/ — домашние директории пользователей +├── root/ — домашняя директория root +├── var/ — изменяемые данные (логи, кэш, БД) +├── tmp/ — временные файлы (очищается при перезагрузке) +├── usr/ — пользовательские программы и данные +│ ├── bin/ — программы пользователя +│ ├── lib/ — библиотеки +│ └── share/ — разделяемые данные +├── lib/ — системные библиотеки +├── dev/ — файлы устройств (sda, tty, null...) +├── proc/ — виртуальная ФС: инфо о процессах и ядре +├── sys/ — виртуальная ФС: инфо об устройствах +├── run/ — данные запущенных процессов (PID-файлы) +├── boot/ — загрузчик, ядро (vmlinuz, initrd) +├── mnt/ — точки монтирования (временные) +└── media/ — автомонтирование съёмных носителей`) + + utils.Note("В Linux всё — файл: устройства, сокеты, каналы, процессы.") + utils.Note("Нет буквы диска (C:, D:). Всё монтируется в единое дерево с корнем /") + + utils.Println(utils.ColorBold + "Типы файлов:" + utils.ColorReset) + utils.Code(`- обычный файл (ls показывает -) +d директория (ls показывает d) +l символическая ссылка (ls показывает l) +b блочное устройство (/dev/sda) +c символьное устройство (/dev/tty) +p именованный канал (FIFO) +s сокет`) + + // ─── 05. Текстовый интерфейс пользователя ──────────────────── + utils.Section("05. Текстовый интерфейс пользователя (CLI)") + + utils.Println("Shell (оболочка) — интерпретатор команд между пользователем и ядром.") + fmt.Println() + utils.Println(utils.ColorBold + "Оболочки:" + utils.ColorReset) + utils.Code(`bash — Bourne Again Shell, стандарт в большинстве дистро +zsh — расширенный bash, Oh My Zsh, популярен у разработчиков +sh — POSIX sh (минималистичный, для скриптов) +fish — дружелюбный, автодополнение из коробки`) + + utils.Println(utils.ColorBold + "Приглашение командной строки (prompt):" + utils.ColorReset) + utils.Code(`user@hostname:~$ — обычный пользователь +root@hostname:~# — суперпользователь (root) + +user — имя пользователя +hostname — имя машины +~ — текущая директория (~ = домашняя) +$ — не root; # — root`) + + utils.Println(utils.ColorBold + "Базовые горячие клавиши:" + utils.ColorReset) + utils.Code(`Tab — автодополнение команд и путей +Tab Tab — показать все варианты +↑ / ↓ — история команд +Ctrl+C — прервать текущую команду (SIGINT) +Ctrl+Z — приостановить процесс (SIGTSTP) +Ctrl+D — закрыть сессию / конец ввода (EOF) +Ctrl+L — очистить экран (= clear) +Ctrl+A — в начало строки +Ctrl+E — в конец строки +Ctrl+R — поиск по истории команд +Ctrl+U — удалить строку до курсора +Ctrl+W — удалить слово влево`) + + utils.Println(utils.ColorBold + "Полезные команды общего назначения:" + utils.ColorReset) + utils.Command("man команда", "страница руководства (q — выход, /текст — поиск)") + utils.Command("info команда", "расширенная документация GNU") + utils.Command("команда --help", "краткая справка") + utils.Command("type команда", "что такое команда (alias/builtin/файл)") + utils.Command("which команда", "полный путь к исполняемому файлу") + utils.Command("whereis команда", "бинарник, исходник и man-страница") + utils.Command("history", "история команд") + utils.Command("history 20", "последние 20 команд") + utils.Command("!42", "выполнить команду №42 из истории") + utils.Command("!!", "повторить последнюю команду") + utils.Command("clear", "очистить экран") + utils.Command("exit", "выйти из сессии") + utils.Command("echo $SHELL", "какая оболочка используется") + fmt.Println() + utils.Code(`# Запуск нескольких команд: +cmd1 ; cmd2 — выполнить последовательно (всегда) +cmd1 && cmd2 — cmd2 только если cmd1 успешна +cmd1 || cmd2 — cmd2 только если cmd1 неуспешна +cmd1 | cmd2 — передать вывод cmd1 на вход cmd2 (pipe)`) + + utils.Note("Виртуальные консоли: Alt+F1..F6 в Linux. В X11 — Ctrl+Alt+F1..F6. Вернуться: Ctrl+Alt+F7.") + + utils.Footer() +} diff --git a/modules/linuxmodules/linux_kernel.go b/modules/linuxmodules/linux_kernel.go new file mode 100644 index 0000000..b072b60 --- /dev/null +++ b/modules/linuxmodules/linux_kernel.go @@ -0,0 +1,109 @@ +package linuxmodules + +import ( + "rubric/utils" +) + +var KernelModule = Module{ + Key: "kernel", + Aliases: []string{"k", "ядро"}, + Title: "Ядро Linux", + Description: "Тема 21: ядро, модули, параметры, uname, dmesg", + Run: showKernel, +} + +func showKernel() { + utils.Header("Linux — Ядро (Kernel)") + + utils.Section("21. Ядро Linux") + + utils.Println("Ядро (kernel) — центральная часть ОС. Управляет:") + utils.Println("• процессами и планировщиком CPU") + utils.Println("• памятью (виртуальная память, swap)") + utils.Println("• устройствами (через драйверы)") + utils.Println("• файловыми системами") + utils.Println("• сетью") + utils.Println("• системными вызовами (syscalls)") + + utils.Println(utils.ColorBold + "\nИнформация о ядре:" + utils.ColorReset) + utils.Command("uname -r", "версия ядра") + utils.Command("uname -a", "полная информация (ядро, архитектура, дата)") + utils.Command("uname -m", "архитектура (x86_64, aarch64...)") + utils.Command("cat /proc/version", "подробная версия (компилятор, дата)") + utils.Command("cat /proc/sys/kernel/osrelease", "версия через /proc") + utils.Code(`# Пример uname -a: +Linux server01 5.15.0-91-generic #101-Ubuntu SMP Tue Nov 14 13:30:08 UTC 2023 +x86_64 x86_64 x86_64 GNU/Linux +│ │ │ └ платформа +│ │ └── архитектура процессора +│ └── имя хоста +└── имя ядра + +# Версия ядра: 5.15.0-91-generic +# 5.15 — основная версия +# 0 — патч-уровень +# 91 — номер пакета дистрибутива`) + + utils.Println(utils.ColorBold + "dmesg — буфер сообщений ядра:" + utils.ColorReset) + utils.Command("dmesg", "все сообщения ядра") + utils.Command("dmesg | tail -20", "последние 20 сообщений") + utils.Command("dmesg -T", "с человекочитаемыми временными метками") + utils.Command("dmesg | grep -i error", "только ошибки") + utils.Command("dmesg | grep -i usb", "сообщения о USB-устройствах") + utils.Command("dmesg | grep -i sda", "сообщения о диске sda") + utils.Command("dmesg -w", "следить за новыми сообщениями (как tail -f)") + utils.Command("dmesg -l err,crit", "только критические ошибки") + + utils.Println(utils.ColorBold + "\nМодули ядра:" + utils.ColorReset) + utils.Println("Модуль — расширение ядра, загружаемое динамически (драйверы, ФС...).") + utils.Code(`# Управление модулями: +lsmod # список загруженных модулей +lsmod | grep ext4 # есть ли модуль ext4? +modinfo ext4 # информация о модуле +modprobe ext4 # загрузить модуль (с зависимостями) +modprobe -r ext4 # выгрузить модуль +insmod /path/to/mod.ko # загрузить .ko файл напрямую +rmmod ext4 # выгрузить модуль + +# Автоматическая загрузка при старте: +# /etc/modules (Debian/Ubuntu) +# /etc/modules-load.d/*.conf +echo "br_netfilter" > /etc/modules-load.d/k8s.conf + +# Параметры модулей: +# /etc/modprobe.d/*.conf +echo "options kvm_intel nested=1" > /etc/modprobe.d/kvm.conf`) + + utils.Println(utils.ColorBold + "Параметры ядра (sysctl):" + utils.ColorReset) + utils.Code(`# Просмотр параметров: +sysctl -a # все параметры +sysctl net.ipv4.ip_forward # конкретный параметр +cat /proc/sys/net/ipv4/ip_forward # то же через /proc/sys + +# Изменить параметр (временно): +sysctl -w net.ipv4.ip_forward=1 + +# Постоянно — в /etc/sysctl.conf или /etc/sysctl.d/: +echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.d/99-custom.conf +sysctl -p /etc/sysctl.d/99-custom.conf # применить + +# Полезные параметры: +net.ipv4.ip_forward = 1 # маршрутизация (для Docker/Kubernetes) +net.ipv4.tcp_syncookies = 1 # защита от SYN flood +vm.swappiness = 10 # предпочитать RAM над swap +fs.file-max = 2097152 # максимум открытых файлов +kernel.dmesg_restrict = 0 # dmesg без root`) + + utils.Println(utils.ColorBold + "Аппаратная информация:" + utils.ColorReset) + utils.Command("lscpu", "информация о процессоре") + utils.Command("lsmem", "информация о памяти") + utils.Command("lspci", "устройства на шине PCI") + utils.Command("lspci -v", "подробно") + utils.Command("lsusb", "USB-устройства") + utils.Command("lsblk", "блочные устройства (диски)") + utils.Command("lshw", "полная информация об оборудовании (нужен root)") + utils.Command("dmidecode", "данные BIOS/UEFI (тип памяти, серийный номер...)") + utils.Command("inxi -Fz", "обзор системы (нужно установить)") + + utils.Footer() +} diff --git a/modules/linuxmodules/linux_logs.go b/modules/linuxmodules/linux_logs.go new file mode 100644 index 0000000..01130fe --- /dev/null +++ b/modules/linuxmodules/linux_logs.go @@ -0,0 +1,175 @@ +package linuxmodules + +import ( + "rubric/utils" +) + +var LogsModule = Module{ + Key: "logs", + Aliases: []string{"l", "cron", "логи"}, + Title: "Логирование и планировщики", + Description: "Темы 36–37: rsyslog, journald, cron, at", + Run: showLogs, +} + +func showLogs() { + utils.Header("Linux — Логирование и планировщики задач") + + // ─── 36. Логирование ────────────────────────────────────────── + utils.Section("36. Логирование") + + utils.Println("В современных системах логирование — двухуровневое:") + utils.Println("journald (systemd) + rsyslog/syslog (традиционный)") + + utils.Println(utils.ColorBold + "\nОсновные лог-файлы в /var/log/:" + utils.ColorReset) + utils.Code(`/var/log/syslog — общий системный лог (Debian/Ubuntu) +/var/log/messages — общий системный лог (RHEL/Fedora) +/var/log/auth.log — аутентификация, sudo, ssh (Debian) +/var/log/secure — аутентификация (RHEL) +/var/log/kern.log — сообщения ядра +/var/log/dmesg — сообщения при загрузке +/var/log/boot.log — процесс загрузки +/var/log/cron — задания cron +/var/log/mail.log — почтовый сервер +/var/log/nginx/ — access.log, error.log +/var/log/apache2/ — access.log, error.log +/var/log/mysql/ — error.log +/var/log/dpkg.log — установка пакетов (Debian) +/var/log/dnf.log — установка пакетов (RHEL) +/var/log/wtmp — история входов (last для чтения) +/var/log/btmp — неудачные попытки входа (lastb) +/var/log/lastlog — последний вход каждого пользователя`) + + utils.Println(utils.ColorBold + "Работа с логами:" + utils.ColorReset) + utils.Command("tail -f /var/log/syslog", "следить за системным логом") + utils.Command("tail -n 100 /var/log/auth.log", "последние 100 строк лога входов") + utils.Command("grep 'ERROR' /var/log/nginx/error.log", "ошибки nginx") + utils.Command("grep -i 'failed' /var/log/auth.log", "неудачные входы") + utils.Command("zcat /var/log/syslog.1.gz", "читать сжатый архивный лог") + utils.Command("zgrep 'error' /var/log/syslog.*.gz", "поиск в архивных логах") + utils.Command("last", "история входов в систему") + utils.Command("lastb", "неудачные попытки входа (root)") + utils.Command("lastlog", "последний вход каждого пользователя") + + utils.Println(utils.ColorBold + "\nrsyslog — конфигурация:" + utils.ColorReset) + utils.Code(`# Конфиг: /etc/rsyslog.conf и /etc/rsyslog.d/*.conf +# Формат правил: facility.priority назначение + +# Facility (источник): +auth, authpriv — аутентификация +cron — планировщик +daemon — системные демоны +kern — ядро +mail — почта +user — пользовательские программы +local0..local7 — зарезервированы для своего использования +* — все + +# Priority (уровень, по возрастанию важности): +debug, info, notice, warning, err, crit, alert, emerg + +# Примеры правил: +*.info;mail.none;authpriv.none /var/log/messages # всё кроме mail и auth +authpriv.* /var/log/secure # всё от authpriv +mail.* /var/log/maillog # почта +cron.* /var/log/cron # cron +*.emerg :omusrmsg:* # критичное — всем пользователям +local1.* /var/log/myapp.log # своё приложение + +# Перезапустить rsyslog: +sudo systemctl restart rsyslog`) + + utils.Println(utils.ColorBold + "logrotate — ротация логов:" + utils.ColorReset) + utils.Code(`# Конфиг: /etc/logrotate.conf и /etc/logrotate.d/* +# Пример /etc/logrotate.d/nginx: +/var/log/nginx/*.log { + daily # каждый день + missingok # не ошибаться если файл отсутствует + rotate 14 # хранить 14 архивов + compress # сжимать gzip + delaycompress # не сжимать текущий архив + notifempty # не ротировать пустые файлы + create 0640 nginx adm # создать новый файл с правами + sharedscripts + postrotate + nginx -s reopen # сообщить nginx открыть новый файл + endscript +} + +# Ручная ротация (тест): +sudo logrotate -d /etc/logrotate.d/nginx # -d = dry run`) + + // ─── 37. Планировщики ───────────────────────────────────────── + utils.Section("37. Планировщики задач: cron и at") + + utils.Println(utils.ColorBold + "cron — периодические задачи:" + utils.ColorReset) + utils.Code(`# Редактировать crontab текущего пользователя: +crontab -e + +# Посмотреть: +crontab -l + +# Удалить все задачи: +crontab -r + +# Для root: +sudo crontab -e + +# Формат строки crontab: +# мин час день_месяца месяц день_недели команда +# 0-59 0-23 1-31 1-12 0-7(0,7=воскресенье) + +# Примеры: +* * * * * /script.sh # каждую минуту +0 * * * * /script.sh # каждый час в 0 минут +0 2 * * * /backup.sh # каждый день в 02:00 +0 2 * * 0 /weekly.sh # каждое воскресенье в 02:00 +0 2 1 * * /monthly.sh # 1-го числа каждого месяца +*/5 * * * * /check.sh # каждые 5 минут +0 9-17 * * 1-5 /work.sh # по будням с 9 до 17 +0 2 * * * root /root/backup.sh # в /etc/crontab с указанием пользователя + +# Специальные строки: +@reboot /script.sh # при каждой загрузке +@daily /script.sh # раз в день (= 0 0 * * *) +@weekly /script.sh # раз в неделю +@monthly /script.sh # раз в месяц +@yearly /script.sh # раз в год`) + + utils.Println(utils.ColorBold + "Системные cron-директории:" + utils.ColorReset) + utils.Code(`/etc/crontab — системный crontab (с полем user) +/etc/cron.d/ — отдельные файлы crontab +/etc/cron.hourly/ — скрипты, запускаемые каждый час +/etc/cron.daily/ — каждый день +/etc/cron.weekly/ — каждую неделю +/etc/cron.monthly/ — каждый месяц + +# Поместить скрипт в /etc/cron.daily/: +sudo cp backup.sh /etc/cron.daily/ +sudo chmod +x /etc/cron.daily/backup.sh`) + + utils.Println(utils.ColorBold + "at — однократные задачи:" + utils.ColorReset) + utils.Code(`# Выполнить команду однократно в указанное время: +at 14:30 # в 14:30 сегодня +at 14:30 tomorrow # завтра в 14:30 +at 14:30 July 15 # 15 июля +at now + 1 hour # через час +at now + 30 minutes # через 30 минут + +# Ввод команд (Ctrl+D для завершения): +at 02:00 +> /usr/local/bin/backup.sh +> Ctrl+D + +# Список задач: +atq +at -l + +# Удалить задачу: +atrm 5 # удалить задачу №5 + +# Посмотреть содержимое задачи: +at -c 5`) + + utils.Footer() +} diff --git a/modules/linuxmodules/linux_netfs.go b/modules/linuxmodules/linux_netfs.go new file mode 100644 index 0000000..3598def --- /dev/null +++ b/modules/linuxmodules/linux_netfs.go @@ -0,0 +1,346 @@ +package linuxmodules + +import ( + "fmt" + "rubric/utils" +) + +var NetfsModule = Module{ + Key: "netfs", + Aliases: []string{"nfs", "smb", "samba", "autofs", "сетевые-фс"}, + Title: "Сетевые файловые системы", + Description: "Темы 55–59: IPv6, передача файлов, NFS, SMB/Samba, autofs", + Run: showNetfs, +} + +func showNetfs() { + utils.Header("Linux — Сетевые файловые системы") + + // ─── 55. IPv6 ───────────────────────────────────────────────── + utils.Section("55. Работа с IPv6") + + utils.Println("IPv6 — протокол интернета следующего поколения (128-битные адреса).") + fmt.Println() + utils.Println(utils.ColorBold + "Формат IPv6 адресов:" + utils.ColorReset) + utils.Code(`Формат: 8 групп по 4 hex-цифры, разделённых : +2001:0db8:85a3:0000:0000:8a2e:0370:7334 + +Сокращения: +- Ведущие нули в группе можно опустить: 0db8 → db8 +- Одну последовательность групп из нулей → :: +2001:db8::1 (полный: 2001:0db8:0000:0000:0000:0000:0000:0001) +::1 — loopback (аналог 127.0.0.1) +fe80::/10 — link-local (автоконфигурация в подсети) +fd00::/8 — уникальные локальные (аналог 192.168.x.x) +2000::/3 — глобальные unicast (публичные) + +Длина префикса: 2001:db8::/32 (аналог маски подсети)`) + + utils.Println(utils.ColorBold + "Настройка IPv6 через nmcli:" + utils.ColorReset) + utils.Code(`# Статический IPv6: +nmcli con mod eth0 ipv6.addresses "2001:db8::10/64" +nmcli con mod eth0 ipv6.gateway "2001:db8::1" +nmcli con mod eth0 ipv6.method manual +nmcli con up eth0 + +# SLAAC (автоконфигурация): +nmcli con mod eth0 ipv6.method auto + +# DHCPv6: +nmcli con mod eth0 ipv6.method dhcp + +# Отключить IPv6 для интерфейса: +nmcli con mod eth0 ipv6.method disabled`) + + utils.Println(utils.ColorBold + "IPv6 команды:" + utils.ColorReset) + utils.Command("ip -6 addr", "IPv6 адреса интерфейсов") + utils.Command("ip -6 route", "IPv6 таблица маршрутов") + utils.Command("ping6 ::1", "ping loopback IPv6") + utils.Command("ping6 fe80::1%eth0", "ping link-local с указанием интерфейса") + utils.Command("traceroute6 2001:4860:4860::8888", "traceroute IPv6") + utils.Command("ss -6 -tuln", "IPv6 порты") + utils.Command("dig AAAA google.com", "DNS AAAA запись (IPv6)") + + // ─── 56. Передача файлов по сети ───────────────────────────── + utils.Section("56. Передача файлов по сети") + + utils.Println(utils.ColorBold + "SCP — копирование через SSH:" + utils.ColorReset) + utils.Code(`# Скопировать локальный файл на сервер: +scp file.txt user@server:/path/to/dest/ + +# Скопировать с сервера на локальную машину: +scp user@server:/path/file.txt /local/path/ + +# Директорию рекурсивно: +scp -r mydir/ user@server:/tmp/ + +# Нестандартный порт: +scp -P 2222 file.txt user@server:/tmp/ + +# С указанием ключа: +scp -i ~/.ssh/mykey file.txt user@server:/tmp/ + +# Между двумя серверами: +scp user1@server1:/path/file.txt user2@server2:/path/`) + + utils.Println(utils.ColorBold + "SFTP — интерактивная передача файлов:" + utils.ColorReset) + utils.Code(`# Подключиться: +sftp user@server +sftp -P 2222 user@server + +# Команды в интерактивном режиме: +ls — список файлов на сервере +lls — список файлов локально +pwd — директория на сервере +lpwd — локальная директория +cd /remote/path — перейти на сервере +lcd /local/path — перейти локально +get file.txt — скачать файл +get -r dir/ — скачать директорию +put file.txt — загрузить файл +put -r dir/ — загрузить директорию +rm file.txt — удалить на сервере +mkdir newdir — создать директорию на сервере +exit / quit — выйти`) + + utils.Println(utils.ColorBold + "rsync — эффективная синхронизация:" + utils.ColorReset) + utils.Code(`# rsync передаёт только изменения — быстрее scp для больших объёмов. + +# Синхронизировать локально: +rsync -av /source/ /dest/ + +# Синхронизировать на удалённый сервер: +rsync -avz /local/data/ user@server:/remote/data/ + +# С сервера локально: +rsync -avz user@server:/remote/data/ /local/data/ + +# Ключи: +# -a — архивный режим (сохраняет права, время, симлинки) +# -v — verbose +# -z — сжатие при передаче +# -P — прогресс + продолжение прерванной передачи +# --delete — удалять файлы которых нет в источнике +# --exclude='*.log' — исключить паттерн +# -n / --dry-run — симуляция (что будет скопировано) +# -e "ssh -p 2222" — нестандартный порт SSH + +# Зеркалирование с исключениями: +rsync -avz --delete \ + --exclude='.git/' \ + --exclude='node_modules/' \ + /project/ user@server:/var/www/project/`) + + // ─── 57. NFS ────────────────────────────────────────────────── + utils.Section("57. Сетевые файловые системы — NFS") + + utils.Println("NFS (Network File System) — монтирование директорий с удалённых серверов.") + utils.Println("Прозрачно для приложений: работает как обычная локальная ФС.") + fmt.Println() + utils.Println(utils.ColorBold + "Сервер NFS — настройка экспорта:" + utils.ColorReset) + utils.Code(`# Установка: +dnf install nfs-utils # RHEL/Fedora +apt install nfs-kernel-server # Debian/Ubuntu + +# Включить и запустить: +systemctl enable --now nfs-server # RHEL +systemctl enable --now nfs-kernel-server # Ubuntu + +# Настройка экспортов /etc/exports: +# директория клиент(опции) +/shared 192.168.1.0/24(rw,sync,no_root_squash) +/data *(ro,sync) # всем только чтение +/home/alice server2(rw,sync,no_subtree_check) + +# Опции: +# rw — чтение и запись +# ro — только чтение +# sync — синхронная запись (безопасно) +# async — асинхронная (быстрее, риск потери) +# no_root_squash — root клиента = root сервера +# root_squash — root клиента → nobody (безопаснее, по умолчанию) +# no_subtree_check — не проверять поддерево (производительность) + +# Применить изменения: +exportfs -r # перечитать /etc/exports +exportfs -v # показать активные экспорты +exportfs -a # экспортировать всё из /etc/exports`) + + utils.Println(utils.ColorBold + "Firewall для NFS:" + utils.ColorReset) + utils.Code(`firewall-cmd --permanent --add-service=nfs +firewall-cmd --permanent --add-service=rpc-bind +firewall-cmd --permanent --add-service=mountd +firewall-cmd --reload`) + + utils.Println(utils.ColorBold + "Клиент NFS — монтирование:" + utils.ColorReset) + utils.Code(`# Установка клиента: +dnf install nfs-utils +apt install nfs-common + +# Посмотреть экспорты сервера: +showmount -e 192.168.1.10 + +# Смонтировать: +mount -t nfs 192.168.1.10:/shared /mnt/shared +mount -t nfs4 192.168.1.10:/data /mnt/data # NFSv4 + +# Параметры монтирования: +mount -t nfs -o rw,sync,hard,intr 192.168.1.10:/shared /mnt + +# В /etc/fstab (постоянно): +192.168.1.10:/shared /mnt/shared nfs defaults,_netdev 0 0 +# _netdev — монтировать только после настройки сети + +# Размонтировать: +umount /mnt/shared`) + + // ─── 58. SMB/Samba ──────────────────────────────────────────── + utils.Section("58. Сетевые файловые системы — SMB/Samba") + + utils.Println("SMB (Server Message Block) / CIFS — протокол файлового обмена Windows.") + utils.Println("Samba — реализация SMB на Linux. Позволяет обмениваться файлами с Windows.") + fmt.Println() + utils.Println(utils.ColorBold + "Сервер Samba — установка и настройка:" + utils.ColorReset) + utils.Code(`# Установка: +dnf install samba samba-client # RHEL +apt install samba # Ubuntu + +# Включить и запустить: +systemctl enable --now smb nmb # RHEL +systemctl enable --now smbd nmbd # Ubuntu`) + + utils.Println(utils.ColorBold + "Конфигурация /etc/samba/smb.conf:" + utils.ColorReset) + utils.Code(`[global] + workgroup = WORKGROUP # рабочая группа Windows + server string = Samba Server + security = user # аутентификация по пользователю + passdb backend = tdbsam # база паролей + +# Публичная шара (без пароля): +[public] + path = /srv/samba/public + browseable = yes + writable = yes + guest ok = yes + create mask = 0664 + directory mask = 0775 + +# Приватная шара (с паролем): +[private] + path = /srv/samba/private + valid users = alice bob + writable = yes + browseable = no + create mask = 0660`) + + utils.Println(utils.ColorBold + "Управление пользователями Samba:" + utils.ColorReset) + utils.Code(`# Пользователь Samba должен существовать в Linux: +useradd -s /sbin/nologin alice + +# Добавить пользователя в Samba (отдельный пароль!): +smbpasswd -a alice +smbpasswd -e alice # включить +smbpasswd -d alice # отключить +smbpasswd -x alice # удалить + +# Список пользователей Samba: +pdbedit -L`) + + utils.Println(utils.ColorBold + "SELinux + Samba:" + utils.ColorReset) + utils.Code(`# Разрешить Samba доступ к домашним директориям: +setsebool -P samba_enable_home_dirs on + +# Разрешить Samba читать/писать общие директории: +chcon -t samba_share_t /srv/samba/public +semanage fcontext -a -t samba_share_t '/srv/samba(/.*)?' +restorecon -Rv /srv/samba/`) + + utils.Println(utils.ColorBold + "Firewall для Samba:" + utils.ColorReset) + utils.Code(`firewall-cmd --permanent --add-service=samba +firewall-cmd --reload`) + + utils.Println(utils.ColorBold + "Клиент SMB — монтирование Windows-шары:" + utils.ColorReset) + utils.Code(`# Установка: +dnf install cifs-utils samba-client +apt install cifs-utils smbclient + +# Просмотр шар на сервере: +smbclient -L //192.168.1.20 -U alice + +# Интерактивный клиент: +smbclient //192.168.1.20/shared -U alice + +# Монтирование: +mount -t cifs //192.168.1.20/shared /mnt/windows \ + -o username=alice,password=secret + +# С файлом учётных данных (безопаснее): +cat > /etc/samba/creds << 'EOF' +username=alice +password=secret +domain=WORKGROUP +EOF +chmod 600 /etc/samba/creds + +mount -t cifs //192.168.1.20/shared /mnt/windows \ + -o credentials=/etc/samba/creds + +# В /etc/fstab: +//server/shared /mnt/windows cifs credentials=/etc/samba/creds,_netdev 0 0`) + + // ─── 59. Autofs ─────────────────────────────────────────────── + utils.Section("59. Автоматическое монтирование — Autofs") + + utils.Println("Autofs — демон автоматического монтирования сетевых ФС по запросу.") + utils.Println("Монтирует при обращении к директории, размонтирует при простое.") + fmt.Println() + utils.Println(utils.ColorBold + "Установка и запуск:" + utils.ColorReset) + utils.Code(`dnf install autofs # RHEL +apt install autofs # Ubuntu + +systemctl enable --now autofs`) + + utils.Println(utils.ColorBold + "Конфигурация autofs:" + utils.ColorReset) + utils.Code(`# Главный файл /etc/auto.master: +# точка_монтирования файл_карты [опции] +/mnt/nfs /etc/auto.nfs --timeout=60 +/home /etc/auto.home --timeout=300 +/- /etc/auto.direct + +# /etc/auto.nfs — монтирование NFS: +# ключ опции сервер:путь +shared -rw,sync 192.168.1.10:/shared +data -ro 192.168.1.10:/data +# Обращение: ls /mnt/nfs/shared → автоматически монтируется + +# /etc/auto.home — домашние директории через NFS: +* -rw,sync 192.168.1.10:/home/& +# & → подставляется ключ (* = любой пользователь) +# /home/alice → монтируется 192.168.1.10:/home/alice + +# /etc/auto.direct — прямые точки монтирования: +/srv/data -rw,sync 192.168.1.10:/data + +# Применить изменения: +systemctl reload autofs +# или: +automount -v`) + + utils.Println(utils.ColorBold + "Использование с FreeIPA/LDAP:" + utils.ColorReset) + utils.Code(`# FreeIPA хранит карты autofs в LDAP. +# После настройки sssd + ipa-client autofs +# получает карты автоматически. + +# Подключить autofs к SSSD: +# В /etc/sssd/sssd.conf: +[domain/ipa.example.com] +autofs_provider = ipa + +# Перезапустить: +systemctl restart sssd autofs`) + + utils.Note("Autofs удобен для сотен пользователей: их домашние директории монтируются автоматически при входе.") + utils.Note("--timeout=60 означает размонтировать после 60 секунд бездействия.") + + utils.Footer() +} diff --git a/modules/linuxmodules/linux_network.go b/modules/linuxmodules/linux_network.go new file mode 100644 index 0000000..c0464e1 --- /dev/null +++ b/modules/linuxmodules/linux_network.go @@ -0,0 +1,238 @@ +package linuxmodules + +import ( + "fmt" + "rubric/utils" +) + +var NetworkModule = Module{ + Key: "network", + Aliases: []string{"net", "ssh", "сеть"}, + Title: "Сети и SSH", + Description: "Темы 42–44: основы сетей, настройка, SSH", + Run: showNetwork, +} + +func showNetwork() { + utils.Header("Linux — Сети и SSH") + + // ─── 42. Основы сетей ───────────────────────────────────────── + utils.Section("42. Основы сетей") + + utils.Println(utils.ColorBold + "Ключевые понятия:" + utils.ColorReset) + utils.Code(`IP-адрес — уникальный адрес устройства в сети + IPv4: 192.168.1.10 (4 байта, 0-255) + IPv6: 2001:db8::1 (16 байт, hex) +Маска сети — определяет границу сети и хостов + /24 = 255.255.255.0 (256 адресов, 254 хоста) + /16 = 255.255.0.0 (65536 адресов) +Шлюз — маршрутизатор для выхода за пределы сети +DNS — перевод имён в IP (8.8.8.8 = Google DNS) +MAC-адрес — физический адрес сетевого интерфейса +DHCP — автоматическое получение IP от сервера + +Приватные сети (RFC 1918): + 10.0.0.0/8 (10.x.x.x) + 172.16.0.0/12 (172.16-31.x.x) + 192.168.0.0/16 (192.168.x.x) + +Localhost: + 127.0.0.1 — loopback IPv4 (lo) + ::1 — loopback IPv6`) + + utils.Println(utils.ColorBold + "Информация о сетевых интерфейсах:" + utils.ColorReset) + utils.Command("ip addr", "IP-адреса всех интерфейсов") + utils.Command("ip addr show eth0", "конкретный интерфейс") + utils.Command("ip link", "состояние интерфейсов (UP/DOWN)") + utils.Command("ip route", "таблица маршрутизации") + utils.Command("ip route show default", "шлюз по умолчанию") + utils.Command("ip neigh", "ARP-таблица (MAC → IP)") + fmt.Println() + utils.Code(`# Старые команды (net-tools, устаревшие): +ifconfig # → ip addr +route -n # → ip route +netstat -rn # → ip route +arp -n # → ip neigh`) + + utils.Println(utils.ColorBold + "Диагностика сети:" + utils.ColorReset) + utils.Command("ping 8.8.8.8", "проверить доступность хоста") + utils.Command("ping -c 4 google.com", "4 пакета") + utils.Command("ping6 ::1", "ping для IPv6") + utils.Command("traceroute google.com", "маршрут до хоста") + utils.Command("tracepath google.com", "маршрут (без root)") + utils.Command("mtr google.com", "ping + traceroute в реальном времени") + utils.Command("nslookup google.com", "DNS-запрос") + utils.Command("dig google.com", "подробный DNS-запрос") + utils.Command("dig @8.8.8.8 google.com", "DNS через конкретный сервер") + utils.Command("host google.com", "быстрый DNS-запрос") + utils.Command("whois 192.168.1.1", "информация об IP/домене") + fmt.Println() + utils.Println(utils.ColorBold + "Сетевые соединения и порты:" + utils.ColorReset) + utils.Command("ss -tuln", "прослушиваемые порты (t=tcp u=udp l=listen n=numeric)") + utils.Command("ss -tulnp", "с именами процессов (root)") + utils.Command("ss -s", "статистика соединений") + utils.Command("ss -tn state established", "активные TCP-соединения") + utils.Command("netstat -tuln", "аналог ss (устаревший)") + utils.Command("lsof -i :80", "что слушает порт 80") + utils.Command("lsof -i :22", "что слушает порт 22") + utils.Command("nmap -sS 192.168.1.0/24", "сканирование сети (нужно установить)") + utils.Command("nmap -p 22,80,443 server", "проверить конкретные порты") + + // ─── 43. Работа с сетью ─────────────────────────────────────── + utils.Section("43. Настройка сети") + + utils.Println(utils.ColorBold + "Временная настройка (без сохранения):" + utils.ColorReset) + utils.Code(`# Добавить IP: +ip addr add 192.168.1.10/24 dev eth0 + +# Удалить IP: +ip addr del 192.168.1.10/24 dev eth0 + +# Включить/выключить интерфейс: +ip link set eth0 up +ip link set eth0 down + +# Добавить маршрут: +ip route add 10.0.0.0/8 via 192.168.1.1 +ip route add default via 192.168.1.1 + +# Удалить маршрут: +ip route del default`) + + utils.Println(utils.ColorBold + "NetworkManager — постоянная настройка:" + utils.ColorReset) + utils.Code(`# nmcli — командная строка NetworkManager +nmcli device status # список устройств +nmcli connection show # все соединения +nmcli connection show eth0 # параметры соединения + +# Статический IP: +nmcli con mod eth0 ipv4.addresses 192.168.1.10/24 +nmcli con mod eth0 ipv4.gateway 192.168.1.1 +nmcli con mod eth0 ipv4.dns "8.8.8.8 8.8.4.4" +nmcli con mod eth0 ipv4.method manual # static (не DHCP) +nmcli con up eth0 # применить + +# DHCP: +nmcli con mod eth0 ipv4.method auto +nmcli con up eth0 + +# Создать соединение: +nmcli con add type ethernet con-name myconn ifname eth1 \ + ipv4.addresses 10.0.0.5/24 ipv4.gateway 10.0.0.1 \ + ipv4.method manual + +# nmtui — псевдографический интерфейс: +nmtui`) + + utils.Println(utils.ColorBold + "DNS-настройка:" + utils.ColorReset) + utils.Code(`# /etc/resolv.conf — DNS-серверы: +nameserver 8.8.8.8 +nameserver 8.8.4.4 +search mydomain.local # домен для коротких имён + +# /etc/hosts — локальное разрешение имён: +127.0.0.1 localhost +192.168.1.10 server01.local server01 + +# Порядок разрешения (/etc/nsswitch.conf): +hosts: files dns myhostname # сначала /etc/hosts, потом DNS`) + + utils.Println(utils.ColorBold + "curl и wget — HTTP-запросы:" + utils.ColorReset) + utils.Command("curl https://example.com", "GET запрос") + utils.Command("curl -I https://example.com", "только заголовки") + utils.Command("curl -o file.txt https://example.com/file", "сохранить в файл") + utils.Command("curl -L https://example.com", "следовать перенаправлениям") + utils.Command("curl -X POST -d 'data' https://api.example.com", "POST запрос") + utils.Command("curl -H 'Authorization: Bearer token' https://api.example.com", "с заголовком") + utils.Command("wget https://example.com/file.tar.gz", "скачать файл") + utils.Command("wget -r -np https://example.com/docs/", "рекурсивно скачать") + + // ─── 44. SSH ────────────────────────────────────────────────── + utils.Section("44. Удалённый доступ — SSH") + + utils.Println("SSH (Secure Shell) — зашифрованный протокол удалённого доступа.") + fmt.Println() + utils.Println(utils.ColorBold + "Подключение:" + utils.ColorReset) + utils.Command("ssh user@server", "подключиться к серверу") + utils.Command("ssh user@192.168.1.10", "по IP") + utils.Command("ssh -p 2222 user@server", "нестандартный порт") + utils.Command("ssh -i ~/.ssh/mykey user@server", "с конкретным ключом") + utils.Command("ssh -v user@server", "подробный вывод (отладка)") + utils.Command("ssh -A user@server", "пробросить SSH-агент") + fmt.Println() + utils.Println(utils.ColorBold + "SSH-ключи — аутентификация без пароля:" + utils.ColorReset) + utils.Code(`# Генерация пары ключей: +ssh-keygen -t ed25519 -C "alice@example.com" # (рекомендуется) +ssh-keygen -t rsa -b 4096 -C "alice@example.com" # RSA 4096 + +# Файлы: +~/.ssh/id_ed25519 — приватный ключ (НИКОМУ не передавать!) +~/.ssh/id_ed25519.pub — публичный ключ + +# Скопировать публичный ключ на сервер: +ssh-copy-id user@server # автоматически +ssh-copy-id -i ~/.ssh/mykey.pub user@server + +# Вручную (добавить в ~/.ssh/authorized_keys на сервере): +cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys +chmod 600 ~/.ssh/authorized_keys +chmod 700 ~/.ssh/`) + + utils.Println(utils.ColorBold + "~/.ssh/config — настройка подключений:" + utils.ColorReset) + utils.Code(`# ~/.ssh/config +Host myserver + HostName 192.168.1.10 + User alice + Port 22 + IdentityFile ~/.ssh/id_ed25519 + ServerAliveInterval 60 + +Host bastion + HostName bastion.example.com + User admin + ForwardAgent yes + +Host internal + HostName 10.0.0.5 + User root + ProxyJump bastion # подключиться через bastion + +# Использование: +ssh myserver # вместо ssh alice@192.168.1.10 -i ~/.ssh/id_ed25519`) + + utils.Println(utils.ColorBold + "Передача файлов:" + utils.ColorReset) + utils.Command("scp file.txt user@server:/path/", "скопировать на сервер") + utils.Command("scp user@server:/path/file.txt .", "скопировать с сервера") + utils.Command("scp -r dir/ user@server:/path/", "директорию рекурсивно") + utils.Command("rsync -avzP dir/ user@server:/path/", "синхронизация (лучше scp)") + fmt.Println() + utils.Println(utils.ColorBold + "Конфигурация сервера (/etc/ssh/sshd_config):" + utils.ColorReset) + utils.Code(`Port 22 # порт (лучше изменить) +PermitRootLogin no # запретить вход root (рекомендуется) +PasswordAuthentication no # только ключи +PubkeyAuthentication yes # ключи разрешены +AuthorizedKeysFile .ssh/authorized_keys +AllowUsers alice bob # только эти пользователи +MaxAuthTries 3 # попытки аутентификации + +# Применить изменения: +sudo systemctl reload sshd + +# Проверить конфигурацию: +sudo sshd -t`) + + utils.Println(utils.ColorBold + "Туннели SSH (Port Forwarding):" + utils.ColorReset) + utils.Code(`# Локальный туннель (доступ к удалённому сервису через localhost): +ssh -L 8080:localhost:80 user@server +# Теперь http://localhost:8080 = http://server:80 + +# Удалённый туннель (открыть порт на удалённом сервере): +ssh -R 9090:localhost:3000 user@server +# Теперь server:9090 → localhost:3000 + +# SOCKS-прокси (динамический туннель): +ssh -D 1080 user@server +# Настроить браузер на SOCKS5 proxy localhost:1080`) + + utils.Footer() +} diff --git a/modules/linuxmodules/linux_packages.go b/modules/linuxmodules/linux_packages.go new file mode 100644 index 0000000..f0b9123 --- /dev/null +++ b/modules/linuxmodules/linux_packages.go @@ -0,0 +1,191 @@ +package linuxmodules + +import ( + "fmt" + "rubric/utils" +) + +var PackagesModule = Module{ + Key: "packages", + Aliases: []string{"pkg", "dnf", "apt", "пакеты"}, + Title: "Пакетный менеджер", + Description: "Тема 47: dnf (RHEL/Fedora) и apt (Debian/Ubuntu)", + Run: showPackages, +} + +func showPackages() { + utils.Header("Linux — Пакетный менеджер") + + utils.Section("47. Пакетные менеджеры: dnf и apt") + + utils.Println("Пакетный менеджер — инструмент установки, обновления и удаления ПО.") + utils.Println("Решает зависимости автоматически, загружает из репозиториев.") + fmt.Println() + utils.Println(utils.ColorBold + "Семейства дистрибутивов и их менеджеры:" + utils.ColorReset) + utils.Code(`RHEL / CentOS / Fedora / Rocky / AlmaLinux: + dnf (современный) / yum (устаревший) + Формат пакетов: .rpm + Репозитории: /etc/yum.repos.d/*.repo + +Debian / Ubuntu / Linux Mint: + apt (фронтенд) / dpkg (низкий уровень) + Формат пакетов: .deb + Репозитории: /etc/apt/sources.list, /etc/apt/sources.list.d/ + +Arch Linux: + pacman + +Alpine Linux: + apk`) + + // ─── dnf ────────────────────────────────────────────────────── + utils.Section("dnf — RHEL / Fedora / CentOS") + + utils.Println(utils.ColorBold + "Основные операции:" + utils.ColorReset) + utils.Command("dnf search nginx", "поиск пакета") + utils.Command("dnf info nginx", "информация о пакете") + utils.Command("dnf install nginx", "установить") + utils.Command("dnf install nginx -y", "без подтверждения") + utils.Command("dnf remove nginx", "удалить") + utils.Command("dnf update", "обновить все пакеты") + utils.Command("dnf update nginx", "обновить конкретный") + utils.Command("dnf upgrade --refresh", "обновить с принудительным обновлением метаданных") + utils.Command("dnf check-update", "показать доступные обновления") + fmt.Println() + utils.Println(utils.ColorBold + "Запросы и история:" + utils.ColorReset) + utils.Command("dnf list installed", "установленные пакеты") + utils.Command("dnf list available", "доступные пакеты") + utils.Command("dnf list | grep nginx", "найти в списке") + utils.Command("dnf provides /usr/bin/python3", "какой пакет предоставляет файл") + utils.Command("dnf provides '*/Makefile'", "поиск по glob") + utils.Command("rpm -ql nginx", "файлы установленного пакета") + utils.Command("rpm -qf /etc/nginx/nginx.conf", "какому пакету принадлежит файл") + utils.Command("rpm -qi nginx", "информация об установленном пакете") + utils.Command("dnf history", "история операций") + utils.Command("dnf history undo 5", "отменить операцию №5") + fmt.Println() + utils.Println(utils.ColorBold + "Группы пакетов:" + utils.ColorReset) + utils.Command("dnf group list", "список групп") + utils.Command("dnf group info 'Development Tools'", "информация о группе") + utils.Command("dnf group install 'Development Tools'", "установить группу") + utils.Command("dnf group remove 'Development Tools'", "удалить группу") + fmt.Println() + utils.Println(utils.ColorBold + "Репозитории:" + utils.ColorReset) + utils.Code(`# Список репозиториев: +dnf repolist +dnf repolist all # включая отключённые + +# Включить/выключить репозиторий: +dnf config-manager --enable epel +dnf config-manager --disable crb + +# Добавить репозиторий: +dnf install epel-release # EPEL (Extra Packages for Enterprise Linux) +dnf config-manager --add-repo https://rpm.example.com/example.repo + +# Установить из конкретного репозитория: +dnf install nginx --repo=epel + +# Файл репозитория (/etc/yum.repos.d/myrepo.repo): +[myrepo] +name=My Repository +baseurl=https://repo.example.com/rhel/$releasever/$basearch/ +enabled=1 +gpgcheck=1 +gpgkey=https://repo.example.com/RPM-GPG-KEY-myrepo`) + + utils.Println(utils.ColorBold + "Кэш и модули:" + utils.ColorReset) + utils.Command("dnf clean all", "очистить кэш") + utils.Command("dnf makecache", "обновить кэш метаданных") + utils.Command("dnf autoremove", "удалить ненужные зависимости") + utils.Command("dnf module list", "список модулей (AppStream)") + utils.Command("dnf module install nodejs:18", "установить модуль nodejs версии 18") + utils.Command("dnf module enable postgresql:15", "включить модуль") + + // ─── apt ────────────────────────────────────────────────────── + utils.Section("apt — Debian / Ubuntu") + + utils.Println(utils.ColorBold + "Основные операции:" + utils.ColorReset) + utils.Command("apt search nginx", "поиск пакета") + utils.Command("apt show nginx", "информация о пакете") + utils.Command("apt install nginx", "установить") + utils.Command("apt install nginx -y", "без подтверждения") + utils.Command("apt remove nginx", "удалить (конфиги остаются)") + utils.Command("apt purge nginx", "удалить с конфигами") + utils.Command("apt update", "обновить индекс репозиториев (метаданные)") + utils.Command("apt upgrade", "обновить установленные пакеты") + utils.Command("apt full-upgrade", "обновить, может удалять и устанавливать новые") + utils.Command("apt dist-upgrade", "аналог full-upgrade") + utils.Command("apt autoremove", "удалить ненужные зависимости") + utils.Command("apt clean", "очистить кэш скачанных пакетов") + utils.Command("apt autoclean", "очистить устаревший кэш") + fmt.Println() + utils.Println(utils.ColorBold + "Запросы:" + utils.ColorReset) + utils.Command("apt list --installed", "установленные пакеты") + utils.Command("apt list --upgradable", "пакеты с доступными обновлениями") + utils.Command("dpkg -l nginx", "статус установленного пакета") + utils.Command("dpkg -L nginx", "файлы установленного пакета") + utils.Command("dpkg -S /etc/nginx/nginx.conf", "какому пакету принадлежит файл") + utils.Command("dpkg -s nginx", "информация об установленном пакете") + fmt.Println() + utils.Println(utils.ColorBold + "Репозитории (Debian/Ubuntu):" + utils.ColorReset) + utils.Code(`# Конфиг: /etc/apt/sources.list +# Ubuntu 22.04: +deb http://ru.archive.ubuntu.com/ubuntu jammy main restricted +deb http://ru.archive.ubuntu.com/ubuntu jammy-updates main restricted +deb http://security.ubuntu.com/ubuntu jammy-security main restricted + +# Добавить PPA (Ubuntu): +add-apt-repository ppa:ondrej/php +apt update +apt install php8.3 + +# Добавить сторонний репозиторий (пример nginx): +# 1. Импортировать GPG-ключ: +curl -fsSL https://nginx.org/keys/nginx_signing.key | gpg --dearmor \ + -o /etc/apt/keyrings/nginx.gpg +# 2. Добавить репозиторий: +echo "deb [signed-by=/etc/apt/keyrings/nginx.gpg] \ + http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" \ + > /etc/apt/sources.list.d/nginx.list +# 3. Обновить и установить: +apt update && apt install nginx + +# Файл в /etc/apt/sources.list.d/: формат .list или .sources (deb822)`) + + utils.Println(utils.ColorBold + "Низкоуровневые операции (dpkg):" + utils.ColorReset) + utils.Code(`# Установить .deb файл: +dpkg -i package.deb +apt install -f # исправить зависимости после dpkg + +# Удалить: +dpkg -r package # без конфигов +dpkg -P package # с конфигами (purge) + +# Reconfigure (перенастроить): +dpkg-reconfigure tzdata +dpkg-reconfigure locales`) + + utils.Println(utils.ColorBold + "Общие инструменты управления ПО:" + utils.ColorReset) + utils.Code(`# Snap (Ubuntu, кросс-дистрибутивный): +snap install code --classic +snap list +snap remove code +snap refresh + +# Flatpak (кросс-дистрибутивный): +flatpak install flathub org.gimp.GIMP +flatpak run org.gimp.GIMP +flatpak list + +# pip (Python): +pip install requests +pip install -r requirements.txt +pip list + +# npm (Node.js): +npm install -g pm2 +npm list -g`) + + utils.Footer() +} diff --git a/modules/linuxmodules/linux_perfomance.go b/modules/linuxmodules/linux_perfomance.go new file mode 100644 index 0000000..9d9350e --- /dev/null +++ b/modules/linuxmodules/linux_perfomance.go @@ -0,0 +1,264 @@ +package linuxmodules + +import ( + "fmt" + "rubric/utils" +) + +var PerformanceModule = Module{ + Key: "performance", + Aliases: []string{"perf", "swap", "tuned", "производительность"}, + Title: "Производительность системы", + Description: "Темы 49–52: виртуальная память, планировщик CPU, tuned, Stratis", + Run: showPerformance, +} + +func showPerformance() { + utils.Header("Linux — Производительность системы") + + // ─── 49. Виртуальная память, swap ──────────────────────────── + utils.Section("49. Виртуальная память и swap") + + utils.Println("Виртуальная память — механизм ядра, позволяющий процессам иметь") + utils.Println("больше памяти, чем физически установлено, за счёт использования диска.") + fmt.Println() + utils.Println(utils.ColorBold + "Swap — раздел/файл подкачки:" + utils.ColorReset) + utils.Code(`Когда физической RAM не хватает, ядро перемещает +редко используемые страницы памяти на swap. +Это медленнее RAM в сотни раз, но лучше OOM-killer. + +Типы swap: +- раздел swap (swap partition) — отдельный раздел диска +- файл swap (swapfile) — обычный файл на любой ФС`) + + utils.Println(utils.ColorBold + "Просмотр swap:" + utils.ColorReset) + utils.Command("free -h", "RAM и swap (human-readable)") + utils.Command("swapon --show", "активные swap-устройства") + utils.Command("cat /proc/swaps", "то же через /proc") + utils.Command("vmstat -s", "статистика памяти и swap") + fmt.Println() + utils.Println(utils.ColorBold + "Создание swapfile:" + utils.ColorReset) + utils.Code(`# 1. Создать файл нужного размера: +sudo dd if=/dev/zero of=/swapfile bs=1M count=2048 # 2 ГБ +# или быстрее: +sudo fallocate -l 2G /swapfile + +# 2. Установить права (только root): +sudo chmod 600 /swapfile + +# 3. Форматировать как swap: +sudo mkswap /swapfile + +# 4. Активировать: +sudo swapon /swapfile + +# 5. Добавить в /etc/fstab для автоматической активации: +echo '/swapfile none swap defaults 0 0' | sudo tee -a /etc/fstab`) + + utils.Println(utils.ColorBold + "Управление swap:" + utils.ColorReset) + utils.Command("swapon /dev/sdb2", "активировать swap-раздел") + utils.Command("swapoff /swapfile", "деактивировать") + utils.Command("swapoff -a", "деактивировать все swap") + utils.Command("swapon -a", "активировать все из /etc/fstab") + fmt.Println() + utils.Println(utils.ColorBold + "vm.swappiness — настройка агрессивности swap:" + utils.ColorReset) + utils.Code(`# swappiness: 0–100 +# 0 — использовать swap только при нехватке RAM +# 60 — по умолчанию +# 100 — активно перемещать страницы в swap + +# Посмотреть: +cat /proc/sys/vm/swappiness +sysctl vm.swappiness + +# Изменить временно: +sudo sysctl -w vm.swappiness=10 + +# Постоянно в /etc/sysctl.d/99-swap.conf: +vm.swappiness = 10 +vm.vfs_cache_pressure = 50 # агрессивность освобождения кэша inode`) + + utils.Println(utils.ColorBold + "OOM-killer (Out Of Memory):" + utils.ColorReset) + utils.Code(`Когда память (RAM + swap) исчерпана, ядро убивает процессы. + +# Посмотреть OOM-события в логах: +dmesg | grep -i "oom\|killed process" +journalctl -k | grep -i oom + +# oom_score — чем выше, тем вероятнее убийство: +cat /proc/PID/oom_score + +# Защитить процесс от OOM (от -17 до 15): +echo -1000 > /proc/PID/oom_score_adj # максимальная защита +# или через systemd в юните: +OOMScoreAdjust=-1000`) + + // ─── 50. Планировщик процессов ─────────────────────────────── + utils.Section("50. Планировщик процессов") + + utils.Println("Планировщик CPU распределяет процессорное время между процессами.") + fmt.Println() + utils.Println(utils.ColorBold + "Политики планирования:" + utils.ColorReset) + utils.Code(`SCHED_OTHER — обычные процессы (CFS — Completely Fair Scheduler) +SCHED_FIFO — реального времени, без вытеснения +SCHED_RR — реального времени, с квантованием +SCHED_BATCH — фоновые задачи (CPU-bound) +SCHED_IDLE — минимальный приоритет (ниже nice 19) +SCHED_DEADLINE — задачи с дедлайном`) + + utils.Println(utils.ColorBold + "nice и renice — управление приоритетом:" + utils.ColorReset) + utils.Code(`# Nice: -20 (высший приоритет) → 19 (низший) +# По умолчанию: 0 +# Только root может установить отрицательные значения + +# Запустить с пониженным приоритетом: +nice -n 15 make -j8 # фоновая сборка + +# Запустить с повышенным (root): +sudo nice -n -10 realtime_app + +# Изменить приоритет запущенного процесса: +renice -n 5 -p 1234 # по PID +renice -n 10 -u alice # всем процессам пользователя +sudo renice -n -5 -p 1234 # повысить (нужен root)`) + + utils.Println(utils.ColorBold + "chrt — управление политикой планирования:" + utils.ColorReset) + utils.Command("chrt -p 1234", "показать политику процесса") + utils.Command("chrt -f -p 50 1234", "установить FIFO с приоритетом 50") + utils.Command("chrt -r 1234", "установить Round-Robin") + utils.Command("chrt -o -p 0 1234", "обычная политика (SCHED_OTHER)") + utils.Command("chrt -f 50 ./myapp", "запустить с FIFO приоритетом 50") + fmt.Println() + utils.Println(utils.ColorBold + "Просмотр загрузки CPU:" + utils.ColorReset) + utils.Command("mpstat 1 5", "загрузка каждого CPU (пакет sysstat)") + utils.Command("mpstat -P ALL 1", "все ядра каждую секунду") + utils.Command("iostat -x 1", "статистика I/O дисков") + utils.Command("sar -u 1 10", "средняя загрузка CPU 10 раз по 1 сек") + utils.Command("perf top", "top по использованию CPU (нужен perf)") + utils.Code(`# cpupower — управление частотой CPU: +cpupower frequency-info # текущий режим +cpupower frequency-set -g performance # режим производительности +# governors: performance, powersave, ondemand, conservative`) + + // ─── 51. tuned ──────────────────────────────────────────────── + utils.Section("51. Оптимизация производительности — tuned") + + utils.Println("tuned — демон автоматической оптимизации системы по профилям.") + utils.Println("Настраивает CPU, диски, сеть под конкретные сценарии использования.") + fmt.Println() + utils.Println(utils.ColorBold + "Управление tuned:" + utils.ColorReset) + utils.Command("systemctl status tuned", "статус демона") + utils.Command("tuned-adm active", "текущий профиль") + utils.Command("tuned-adm list", "список доступных профилей") + utils.Command("tuned-adm profile throughput-performance", "применить профиль") + utils.Command("tuned-adm recommend", "рекомендованный профиль для этой системы") + utils.Command("tuned-adm off", "отключить tuned") + fmt.Println() + utils.Println(utils.ColorBold + "Встроенные профили:" + utils.ColorReset) + utils.Code(`balanced — баланс производительности и энергопотребления +powersave — минимальное энергопотребление +throughput-performance — максимальная пропускная способность (серверы) +latency-performance — минимальная задержка (без энергосбережения) +network-latency — минимальная сетевая задержка +network-throughput — максимальная сетевая пропускная способность +virtual-guest — оптимизация для виртуальных машин +virtual-host — оптимизация для хоста виртуализации +oracle — для Oracle DB +mssql — для MS SQL Server +desktop — для рабочих станций`) + + utils.Println(utils.ColorBold + "Создание собственного профиля:" + utils.ColorReset) + utils.Code(`# Профили хранятся в /usr/lib/tuned/ (системные) +# и /etc/tuned/ (пользовательские) + +# Создать профиль на основе существующего: +mkdir /etc/tuned/myprofile +cat > /etc/tuned/myprofile/tuned.conf << 'EOF' +[main] +summary=Мой профиль +include=throughput-performance + +[cpu] +governor=performance +energy_perf_bias=performance + +[disk] +readahead=>4096 + +[sysctl] +vm.swappiness=10 +net.core.somaxconn=65535 +EOF + +tuned-adm profile myprofile`) + + // ─── 52. Stratis ────────────────────────────────────────────── + utils.Section("52. Управление многоуровневым хранилищем — Stratis") + + utils.Println("Stratis — менеджер хранилища от Red Hat (RHEL 8+).") + utils.Println("Упрощает создание пулов, снапшотов и тонкого выделения места.") + utils.Println("Работает поверх LVM и XFS.") + fmt.Println() + utils.Code(`Архитектура Stratis: +Physical Device (/dev/sdb, /dev/sdc) + ↓ + Pool (пул хранилища) + ↓ + Filesystem (XFS файловая система) + +Особенности: +- Тонкое выделение (thin provisioning) +- Снапшоты (моментальные снимки) +- Кэширование (SSD как кэш для HDD) +- Автоматическое управление XFS`) + + utils.Println(utils.ColorBold + "Установка и запуск:" + utils.ColorReset) + utils.Code(`# RHEL/Fedora: +dnf install stratisd stratis-cli +systemctl enable --now stratisd`) + + utils.Println(utils.ColorBold + "Работа с пулами:" + utils.ColorReset) + utils.Code(`# Создать пул: +stratis pool create mypool /dev/sdb +stratis pool create mypool /dev/sdb /dev/sdc # из нескольких дисков + +# Добавить диск в существующий пул: +stratis pool add-data mypool /dev/sdd + +# Добавить кэш (SSD): +stratis pool add-cache mypool /dev/nvme0n1 + +# Список пулов: +stratis pool list + +# Детали пула: +stratis pool info mypool`) + + utils.Println(utils.ColorBold + "Работа с файловыми системами:" + utils.ColorReset) + utils.Code(`# Создать ФС в пуле: +stratis filesystem create mypool myfs + +# Список ФС: +stratis filesystem list +stratis fs + +# Монтирование: +mount /stratis/mypool/myfs /mnt/data + +# В /etc/fstab (с x-systemd.requires): +/stratis/mypool/myfs /mnt/data xfs defaults,x-systemd.requires=stratisd.service 0 0 + +# Создать снапшот: +stratis filesystem snapshot mypool myfs myfs-snapshot + +# Удалить ФС: +stratis filesystem destroy mypool myfs + +# Удалить пул (сначала удалить все ФС): +stratis pool destroy mypool`) + + utils.Note("Stratis автоматически форматирует дискипод XFS. Не используйте mkfs вручную.") + utils.Note("Снапшоты — это отдельные ФС. Можно смонтировать для восстановления файлов.") + + utils.Footer() +} diff --git a/modules/linuxmodules/linux_processes.go b/modules/linuxmodules/linux_processes.go new file mode 100644 index 0000000..e389d9d --- /dev/null +++ b/modules/linuxmodules/linux_processes.go @@ -0,0 +1,207 @@ +package linuxmodules + +import ( + "fmt" + "rubric/utils" +) + +var ProcessesModule = Module{ + Key: "processes", + Aliases: []string{"proc", "ps", "процессы"}, + Title: "Процессы", + Description: "Темы 14–16: информация о процессах, сигналы, управление процессами", + Run: showProcesses, +} + +func showProcesses() { + utils.Header("Linux — Процессы") + + // ─── 14. Процессы №1: информация ───────────────────────────── + utils.Section("14. Процессы №1: информация о процессах") + + utils.Println("Процесс — выполняющаяся программа. Каждый процесс имеет уникальный PID.") + fmt.Println() + utils.Println(utils.ColorBold + "ps — информация о процессах:" + utils.ColorReset) + utils.Command("ps", "процессы текущего терминала") + utils.Command("ps aux", "все процессы всех пользователей (BSD стиль)") + utils.Command("ps -ef", "все процессы (UNIX стиль)") + utils.Command("ps aux | grep nginx", "найти процессы nginx") + utils.Command("ps -u alice", "процессы пользователя alice") + utils.Command("ps --forest", "дерево процессов (родитель → потомок)") + fmt.Println() + utils.Code(`# Вывод ps aux: +USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND +root 1 0.0 0.1 168384 13312 ? Ss Jan01 0:05 /sbin/init +alice 1234 2.1 1.5 567890 61234 pts/0 Sl 10:30 0:12 firefox + +Поля: +USER — владелец процесса +PID — Process ID (уникальный номер) +PPID — Parent PID (родительский процесс) +%CPU — использование процессора +%MEM — использование памяти +VSZ — виртуальная память (КБ) +RSS — реальная память (КБ) +TTY — терминал (? = нет терминала, демон) +STAT — состояние процесса +START — время запуска +TIME — суммарное CPU-время +COMMAND — команда + +Коды состояния (STAT): +R — Running (работает) +S — Sleeping (ожидает, прерываемый) +D — Sleeping (ожидает, непрерываемый, I/O) +Z — Zombie (завершён, ждёт родителя) +T — Stopped (остановлен сигналом) +s — лидер сессии ++ — процесс переднего плана +l — многопоточный`) + + utils.Println(utils.ColorBold + "pstree — дерево процессов:" + utils.ColorReset) + utils.Command("pstree", "дерево всех процессов") + utils.Command("pstree -p", "с PID") + utils.Command("pstree alice", "только процессы пользователя alice") + fmt.Println() + utils.Println(utils.ColorBold + "/proc — виртуальная файловая система:" + utils.ColorReset) + utils.Code(`/proc — информация о процессах и ядре +/proc/PID/ — директория конкретного процесса +/proc/PID/cmdline — командная строка запуска +/proc/PID/status — статус процесса (память, UID...) +/proc/PID/fd/ — открытые файловые дескрипторы +/proc/PID/maps — карта памяти процесса +/proc/cpuinfo — информация о CPU +/proc/meminfo — информация о памяти +/proc/loadavg — средняя загрузка + +# Примеры: +cat /proc/1/cmdline # команда процесса PID=1 +cat /proc/cpuinfo | grep "model name" +cat /proc/meminfo | grep MemAvail`) + + // ─── 15. Процессы №2: информация ───────────────────────────── + utils.Section("15. Процессы №2: мониторинг в реальном времени") + + utils.Println(utils.ColorBold + "top — динамический мониторинг:" + utils.ColorReset) + utils.Command("top", "интерактивный мониторинг (обновляется каждые 3 сек)") + utils.Command("top -u alice", "только процессы пользователя alice") + utils.Command("top -p 1234,5678", "только указанные PID") + utils.Command("top -b -n 1", "пакетный режим (для скриптов/логирования)") + fmt.Println() + utils.Code(`Клавиши в top: + q — выйти + h — справка + k — убить процесс (ввести PID) + r — изменить nice (приоритет) + M — сортировать по памяти + P — сортировать по CPU + T — сортировать по времени + 1 — показать каждый CPU отдельно + f — настройка столбцов + u — фильтр по пользователю`) + + utils.Println(utils.ColorBold + "htop — улучшенный top (нужно установить):" + utils.ColorReset) + utils.Command("htop", "цветной интерактивный мониторинг") + utils.Code(`# Установка: +apt install htop # Debian/Ubuntu +dnf install htop # RHEL/Fedora`) + + utils.Println(utils.ColorBold + "Мониторинг ресурсов:" + utils.ColorReset) + utils.Command("free -h", "использование памяти (human-readable)") + utils.Command("free -m", "в мегабайтах") + utils.Command("vmstat 2 5", "статистика памяти, CPU каждые 2 сек, 5 раз") + utils.Command("uptime", "время работы системы и средняя загрузка") + utils.Command("w", "кто залогинен и что делает") + utils.Command("who", "список залогиненных пользователей") + utils.Command("last", "история входов в систему") + fmt.Println() + utils.Code(`# Средняя загрузка (load average): +uptime +# 10:30:00 up 5 days, 2:15, 2 users, load average: 0.52, 0.41, 0.35 +# 1min 5min 15min + +# Значение = количество процессов ждущих CPU +# На однопроцессорной системе: +# < 1.0 — нормально +# = 1.0 — 100% загрузка +# > 1.0 — перегрузка (очередь) +# На N ядрах перегрузка начинается при load > N`) + + utils.Println(utils.ColorBold + "lsof — открытые файлы и соединения:" + utils.ColorReset) + utils.Command("lsof", "все открытые файлы (очень много)") + utils.Command("lsof -p 1234", "открытые файлы процесса 1234") + utils.Command("lsof -u alice", "файлы пользователя alice") + utils.Command("lsof -i :80", "что использует порт 80") + utils.Command("lsof -i TCP", "все TCP соединения") + utils.Command("lsof /var/log/syslog", "какие процессы используют этот файл") + + // ─── 16. Процессы №3: управление ───────────────────────────── + utils.Section("16. Процессы №3: управление процессами") + + utils.Println(utils.ColorBold + "Сигналы:" + utils.ColorReset) + utils.Code(`Сигнал — асинхронное уведомление процессу. + +Номер Имя Действие по умолчанию +────────────────────────────────────────────────────── +1 SIGHUP Завершить (или перечитать конфиг для демонов) +2 SIGINT Прервать (Ctrl+C) +3 SIGQUIT Завершить с core dump (Ctrl+\) +9 SIGKILL Убить немедленно (нельзя перехватить/игнорировать) +15 SIGTERM Завершить корректно (по умолчанию для kill) +17 SIGCHLD Дочерний процесс изменил состояние +18 SIGCONT Продолжить остановленный процесс +19 SIGSTOP Остановить (нельзя перехватить/игнорировать) +20 SIGTSTP Остановить (Ctrl+Z, можно перехватить)`) + + utils.Println(utils.ColorBold + "kill — отправить сигнал процессу:" + utils.ColorReset) + utils.Command("kill 1234", "SIGTERM (15) процессу 1234 — корректное завершение") + utils.Command("kill -9 1234", "SIGKILL — принудительное убийство") + utils.Command("kill -15 1234", "SIGTERM явно") + utils.Command("kill -HUP 1234", "SIGHUP (перечитать конфиг)") + utils.Command("kill -l", "список всех сигналов") + utils.Command("killall nginx", "SIGTERM всем процессам с именем nginx") + utils.Command("killall -9 nginx", "SIGKILL всем nginx") + utils.Command("pkill nginx", "SIGTERM по имени (поддерживает regex)") + utils.Command("pkill -u alice", "завершить все процессы пользователя alice") + fmt.Println() + utils.Note("Сначала используйте kill (SIGTERM) — даёт процессу завершиться корректно. SIGKILL только если SIGTERM не помог.") + + utils.Println(utils.ColorBold + "Приоритет процессов (nice):" + utils.ColorReset) + utils.Code(`Nice значение: от -20 (максимальный приоритет) до 19 (минимальный) +По умолчанию: 0 + +# Запустить с пониженным приоритетом: +nice -n 10 make -j4 + +# Изменить приоритет запущенного процесса: +renice -n 5 -p 1234 # PID +renice -n 5 -u alice # для пользователя +# renice на отрицательное значение требует root`) + + utils.Println(utils.ColorBold + "Фоновые процессы и задания (job control):" + utils.ColorReset) + utils.Code(`# Запустить в фоне: +command & # & в конце +long_task.sh & + +# Управление заданиями: +jobs # список фоновых заданий текущего терминала +jobs -l # с PID +fg # вернуть последнее задание на передний план +fg %2 # вернуть задание №2 +bg # продолжить остановленное в фоне +bg %1 # продолжить задание №1 в фоне + +# Ctrl+Z — приостановить текущий процесс (SIGTSTP) +# Затем bg — продолжить в фоне + +# Процесс продолжит работу после выхода из терминала: +nohup command & # игнорировать SIGHUP при выходе +disown %1 # отвязать задание от терминала`) + + utils.Println(utils.ColorBold + "watch — периодически выполнять команду:" + utils.ColorReset) + utils.Command("watch -n 2 'ps aux | grep nginx'", "каждые 2 сек смотреть процессы nginx") + utils.Command("watch -d free -h", "следить за памятью, выделять изменения") + utils.Command("watch -n 1 uptime", "загрузка каждую секунду") + + utils.Footer() +} diff --git a/modules/linuxmodules/linux_registry.go b/modules/linuxmodules/linux_registry.go new file mode 100644 index 0000000..a393ed9 --- /dev/null +++ b/modules/linuxmodules/linux_registry.go @@ -0,0 +1,69 @@ +package linuxmodules + +import ( + "fmt" + "rubric/utils" + "strings" +) + +// Module описывает один раздел справочника Linux +type Module struct { + Key string + Aliases []string + Title string + Description string + Run func() +} + +// All — список всех модулей в порядке меню +var All = []Module{ + IntroModule, + FilesModule, + StreamsModule, + BashModule, + ProcessesModule, + UsersModule, + KernelModule, + DisksModule, + ScriptsModule, + BootModule, + LogsModule, + BackupModule, + NetworkModule, + SecurityModule, + PackagesModule, + PerformanceModule, + SysconfigModule, + NetfsModule, + ToolsModule, +} + +// Find ищет модуль по ключу или алиасу +func Find(key string) (Module, bool) { + key = strings.ToLower(strings.TrimSpace(key)) + for _, m := range All { + if m.Key == key { + return m, true + } + for _, a := range m.Aliases { + if a == key { + return m, true + } + } + } + return Module{}, false +} + +// ListModules выводит краткий список модулей +func ListModules() { + fmt.Printf("\n%s%sРазделы справочника Linux:%s\n\n", + utils.ColorBold, utils.ColorCyan, utils.ColorReset) + for i, m := range All { + fmt.Printf(" %s%d.%s %-12s — %s\n", + utils.ColorDim, i+1, utils.ColorReset, + utils.ColorYellow+utils.ColorBold+m.Key+utils.ColorReset, + m.Title, + ) + } + fmt.Println() +} diff --git a/modules/linuxmodules/linux_scripts.go b/modules/linuxmodules/linux_scripts.go new file mode 100644 index 0000000..d7d78e7 --- /dev/null +++ b/modules/linuxmodules/linux_scripts.go @@ -0,0 +1,318 @@ +package linuxmodules + +import ( + "fmt" + "rubric/utils" +) + +var ScriptsModule = Module{ + Key: "scripts", + Aliases: []string{"sc", "scripting", "скрипты"}, + Title: "Bash-скрипты", + Description: "Темы 27–32: скрипты, условия, циклы, функции, массивы", + Run: showScripts, +} + +func showScripts() { + utils.Header("Linux — Bash-скрипты") + + // ─── 27. Bash скрипты №1 ────────────────────────────────────── + utils.Section("27. Основы скриптов. Условия") + + utils.Println(utils.ColorBold + "Структура скрипта:" + utils.ColorReset) + utils.Code(`#!/bin/bash +# Shebang — первая строка указывает интерпретатор +# Комментарий + +echo "Привет, мир!" + +# Запуск скрипта: +chmod +x script.sh # сделать исполняемым +./script.sh # запустить +bash script.sh # запустить через bash (без chmod)`) + + utils.Println(utils.ColorBold + "Переменные в скриптах:" + utils.ColorReset) + utils.Code(`#!/bin/bash +name="Alice" +count=5 + +echo "Имя: $name" +echo "Счёт: $count" + +# Ввод от пользователя: +read -p "Введите имя: " username +echo "Привет, $username!" + +# Ввод без отображения (пароль): +read -s -p "Пароль: " password`) + + utils.Println(utils.ColorBold + "Условный оператор if:" + utils.ColorReset) + utils.Code(`#!/bin/bash +# Базовая форма: +if [ условие ]; then + команды +elif [ другое_условие ]; then + команды +else + команды +fi + +# Примеры условий: +# Сравнение строк: +if [ "$name" = "Alice" ]; then echo "Привет, Alice"; fi +if [ "$name" != "Bob" ]; then echo "Не Боб"; fi +if [ -z "$name" ]; then echo "Пустая строка"; fi # -z = пусто +if [ -n "$name" ]; then echo "Не пустая"; fi # -n = не пусто + +# Сравнение чисел: +if [ "$count" -eq 5 ]; then ... # equal +if [ "$count" -ne 5 ]; then ... # not equal +if [ "$count" -gt 3 ]; then ... # greater than +if [ "$count" -lt 10 ]; then ... # less than +if [ "$count" -ge 5 ]; then ... # greater or equal +if [ "$count" -le 5 ]; then ... # less or equal + +# Файлы и директории: +if [ -f /etc/passwd ]; then echo "файл существует"; fi +if [ -d /tmp ]; then echo "директория существует"; fi +if [ -e /dev/sda ]; then echo "путь существует"; fi +if [ -r file ]; then echo "доступен для чтения"; fi +if [ -w file ]; then echo "доступен для записи"; fi +if [ -x script.sh ]; then echo "исполняемый"; fi +if [ -s file ]; then echo "файл не пустой"; fi +if [ file1 -nt file2 ]; then echo "file1 новее"; fi + +# Логика: +if [ cond1 ] && [ cond2 ]; then ... # И +if [ cond1 ] || [ cond2 ]; then ... # ИЛИ +if ! [ cond ]; then ... # НЕ + +# [[ ]] — расширенные условия bash: +if [[ "$str" == *"подстрока"* ]]; then ... # glob +if [[ "$str" =~ ^[0-9]+$ ]]; then ... # regex`) + + // ─── 28–29. Bash скрипты №2–3 ───────────────────────────────── + utils.Section("28–29. Циклы") + + utils.Println(utils.ColorBold + "Цикл for:" + utils.ColorReset) + utils.Code(`# По списку: +for item in один два три; do + echo "$item" +done + +# По числовому диапазону: +for i in {1..5}; do + echo "Шаг $i" +done + +# С шагом: +for i in {0..20..5}; do echo "$i"; done # 0 5 10 15 20 + +# C-стиль: +for ((i=0; i<5; i++)); do + echo "$i" +done + +# По файлам: +for file in /etc/*.conf; do + echo "Обрабатываю: $file" +done + +# По строкам вывода команды: +for user in $(cat /etc/passwd | cut -d: -f1); do + echo "Пользователь: $user" +done`) + + utils.Println(utils.ColorBold + "Цикл while:" + utils.ColorReset) + utils.Code(`# Пока условие истинно: +count=0 +while [ $count -lt 5 ]; do + echo "count = $count" + ((count++)) +done + +# Чтение файла построчно: +while IFS= read -r line; do + echo "Строка: $line" +done < /etc/hosts + +# Бесконечный цикл: +while true; do + echo "Работаю..." + sleep 1 +done`) + + utils.Println(utils.ColorBold + "Цикл until и управление циклами:" + utils.ColorReset) + utils.Code(`# Пока условие ложно: +until [ -f /tmp/ready ]; do + echo "Жду файл..." + sleep 1 +done + +# break — выйти из цикла: +for i in {1..10}; do + if [ $i -eq 5 ]; then break; fi + echo $i +done + +# continue — перейти к следующей итерации: +for i in {1..10}; do + if [ $((i % 2)) -eq 0 ]; then continue; fi + echo "Нечётное: $i" +done`) + + // ─── 30–31. Bash скрипты №4–5 ───────────────────────────────── + utils.Section("30–31. Функции и обработка ошибок") + + utils.Println(utils.ColorBold + "Функции:" + utils.ColorReset) + utils.Code(`#!/bin/bash +# Объявление функции: +greet() { + local name=$1 # local — локальная переменная + echo "Привет, $name!" +} + +# Или: +function greet { + echo "Привет, $1!" +} + +# Вызов: +greet "Alice" +greet "Bob" + +# Возвращаемое значение: +# Функции возвращают только числа (код возврата 0-255) +is_root() { + [ "$(id -u)" -eq 0 ] +} + +if is_root; then + echo "Запущен как root" +fi + +# Для передачи строк — echo + подстановка команд: +get_hostname() { + echo "$(hostname)" +} +host=$(get_hostname)`) + + utils.Println(utils.ColorBold + "Обработка ошибок:" + utils.ColorReset) + utils.Code(`#!/bin/bash +# Остановить при ошибке: +set -e # выйти при любой ошибке (exit on error) +set -u # ошибка при неопределённой переменной +set -o pipefail # учитывать ошибки в pipe +set -euo pipefail # всё вместе (рекомендуется) + +# Проверка кода возврата: +if ! mkdir /tmp/mydir 2>/dev/null; then + echo "Ошибка создания директории" >&2 + exit 1 +fi + +# Функция для вывода ошибок: +error() { + echo "ОШИБКА: $*" >&2 + exit 1 +} + +[ -f "$1" ] || error "Файл $1 не найден" + +# Trap — обработка сигналов и выхода: +cleanup() { + rm -f /tmp/tempfile + echo "Очищено" +} +trap cleanup EXIT # при любом выходе +trap cleanup INT TERM # при Ctrl+C или kill`) + + // ─── 32. Bash скрипты №6 ────────────────────────────────────── + utils.Section("32. Массивы, строки и аргументы скрипта") + + utils.Println(utils.ColorBold + "Массивы:" + utils.ColorReset) + utils.Code(`# Объявление: +fruits=("яблоко" "банан" "апельсин") +declare -a numbers=(1 2 3 4 5) + +# Доступ: +echo "${fruits[0]}" # яблоко (индекс с 0) +echo "${fruits[@]}" # все элементы +echo "${#fruits[@]}" # количество элементов +echo "${fruits[@]:1:2}" # срез: с индекса 1, 2 элемента + +# Добавить элемент: +fruits+=("манго") + +# Перебор: +for fruit in "${fruits[@]}"; do + echo "$fruit" +done + +# Перебор с индексом: +for i in "${!fruits[@]}"; do + echo "$i: ${fruits[$i]}" +done + +# Ассоциативный массив (словарь): +declare -A user +user[name]="Alice" +user[age]=30 +echo "${user[name]}" +echo "${!user[@]}" # ключи +echo "${user[@]}" # значения`) + + utils.Println(utils.ColorBold + "Аргументы скрипта:" + utils.ColorReset) + utils.Code(`#!/bin/bash +# Позиционные параметры: +echo "Скрипт: $0" +echo "Первый аргумент: $1" +echo "Второй аргумент: $2" +echo "Все аргументы: $@" +echo "Количество аргументов: $#" + +# Проверка аргументов: +if [ $# -lt 2 ]; then + echo "Использование: $0 <имя> <возраст>" >&2 + exit 1 +fi + +# Обработка опций (getopts): +while getopts "hv:n:" opt; do + case $opt in + h) echo "Справка"; exit 0 ;; + v) verbose=true ;; + n) name="$OPTARG" ;; + ?) echo "Неизвестный ключ"; exit 1 ;; + esac +done + +# shift — сдвинуть аргументы: +shift $((OPTIND - 1)) # убрать опции, остались обычные аргументы`) + + utils.Println(utils.ColorBold + "Полезные приёмы:" + utils.ColorReset) + utils.Code(`# Цвета в терминале: +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' # No Color +echo -e "${RED}Ошибка${NC}" +echo -e "${GREEN}Успех${NC}" + +# Прогресс-бар простой: +for i in {1..10}; do + echo -ne "\rПрогресс: $((i*10))%" + sleep 0.1 +done; echo + +# Логирование: +LOG=/var/log/myscript.log +log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG"; } +log "Скрипт запущен" + +# Ожидание с таймаутом: +timeout 30 ./long_command.sh || echo "Таймаут!"`) + fmt.Println() + utils.Note("Проверяйте скрипты на ошибки: bash -n script.sh (синтаксис) и bash -x script.sh (трассировка).") + + utils.Footer() +} diff --git a/modules/linuxmodules/linux_security.go b/modules/linuxmodules/linux_security.go new file mode 100644 index 0000000..39c9dd3 --- /dev/null +++ b/modules/linuxmodules/linux_security.go @@ -0,0 +1,276 @@ +package linuxmodules + +import ( + "fmt" + "rubric/utils" +) + +var SecurityModule = Module{ + Key: "security", + Aliases: []string{"sec", "selinux", "firewall", "безопасность"}, + Title: "Безопасность: SELinux и Firewall", + Description: "Темы 45–46, 48: SELinux, firewalld, восстановление доступа", + Run: showSecurity, +} + +func showSecurity() { + utils.Header("Linux — Безопасность: SELinux и Firewall") + + // ─── 45. SELinux ────────────────────────────────────────────── + utils.Section("45. Принудительный контроль доступа — SELinux") + + utils.Println("SELinux (Security-Enhanced Linux) — система принудительного контроля доступа.") + utils.Println("Работает поверх обычных прав Unix: даже root ограничен политикой SELinux.") + fmt.Println() + utils.Println(utils.ColorBold + "Режимы SELinux:" + utils.ColorReset) + utils.Code(`Enforcing — SELinux активен, запрещённые действия блокируются + и логируются (производственный режим) +Permissive — SELinux активен, нарушения только логируются + (не блокируются). Для отладки. +Disabled — SELinux полностью отключён (требует перезагрузки) + +# Текущий режим: +getenforce +sestatus # подробная информация + +# Временно изменить режим (до перезагрузки): +setenforce 0 # Enforcing → Permissive +setenforce 1 # Permissive → Enforcing +setenforce Permissive # то же самое + +# Постоянно — /etc/selinux/config: +SELINUX=enforcing # enforcing / permissive / disabled +SELINUXTYPE=targeted # политика + +# После изменения с/на disabled — нужна перезагрузка. +# При включении SELinux после disabled — нужна переметка файлов: +touch /.autorelabel && reboot`) + + utils.Println(utils.ColorBold + "Контексты SELinux:" + utils.ColorReset) + utils.Code(`Каждый файл, процесс и порт имеет SELinux-контекст: +user:role:type:level + ↓ ↓ ↓ ↓ +system_u:object_r:httpd_sys_content_t:s0 + +Самое важное — type (тип): httpd_sys_content_t, etc_t... + +# Просмотр контекстов файлов: +ls -Z /var/www/html/ +ls -lZ /etc/nginx/ + +# Просмотр контекста процессов: +ps auxZ | grep nginx + +# Просмотр контекста портов: +semanage port -l | grep http`) + + utils.Println(utils.ColorBold + "Управление контекстами:" + utils.ColorReset) + utils.Code(`# Изменить контекст файла: +chcon -t httpd_sys_content_t /var/www/mysite/ +chcon -R -t httpd_sys_content_t /var/www/mysite/ # рекурсивно + +# Проблема: chcon не постоянен, restorecon сбросит его. +# Правильно: использовать semanage fcontext: + +# Добавить постоянное правило для контекста: +semanage fcontext -a -t httpd_sys_content_t '/srv/web(/.*)?' +# Применить правила к файлам: +restorecon -Rv /srv/web/ + +# Восстановить контекст по умолчанию: +restorecon -Rv /var/www/html/ + +# Проверить ожидаемый контекст: +matchpathcon /var/www/html/index.html`) + + utils.Println(utils.ColorBold + "Булевые переменные SELinux (Booleans):" + utils.ColorReset) + utils.Code(`# Booleans — включают/выключают определённые возможности: + +# Просмотр всех: +getsebool -a +getsebool -a | grep httpd + +# Включить/выключить (временно): +setsebool httpd_can_network_connect on +setsebool httpd_can_network_connect off + +# Постоянно (после перезагрузки): +setsebool -P httpd_can_network_connect on +setsebool -P httpd_enable_homedirs on + +# Полезные booleans: +httpd_can_network_connect # nginx/apache → внешняя сеть +httpd_can_network_connect_db # nginx/apache → БД +httpd_enable_homedirs # доступ к /home +samba_enable_home_dirs # Samba к /home +ssh_sysadm_login # SSH-вход для sysadmin`) + + utils.Println(utils.ColorBold + "Порты и SELinux:" + utils.ColorReset) + utils.Code(`# Посмотреть разрешённые порты: +semanage port -l +semanage port -l | grep http + +# Разрешить nginx слушать нестандартный порт 8888: +semanage port -a -t http_port_t -p tcp 8888 + +# Удалить правило порта: +semanage port -d -t http_port_t -p tcp 8888 + +# Изменить существующее правило: +semanage port -m -t http_port_t -p tcp 8888`) + + utils.Println(utils.ColorBold + "Диагностика проблем SELinux:" + utils.ColorReset) + utils.Code(`# Логи SELinux: +/var/log/audit/audit.log # основной лог + +# Поиск запретов: +ausearch -m avc -ts recent # последние запреты AVC +grep 'denied' /var/log/audit/audit.log | tail -20 + +# audit2why — объяснить запрет: +ausearch -m avc -ts recent | audit2why + +# audit2allow — создать модуль для разрешения: +ausearch -m avc -ts recent | audit2allow -m mymodule > mymodule.te +checkmodule -M -m -o mymodule.mod mymodule.te +semodule_package -o mymodule.pp -m mymodule.mod +semodule -i mymodule.pp + +# sealert — графическая диагностика (если установлен setroubleshoot): +sealert -a /var/log/audit/audit.log`) + + // ─── 46. firewalld ──────────────────────────────────────────── + utils.Section("46. Межсетевой экран — firewalld") + + utils.Println("firewalld — динамический менеджер firewall в RHEL/Fedora/CentOS.") + utils.Println("Работает поверх nftables (или iptables).") + fmt.Println() + utils.Println(utils.ColorBold + "Зоны (Zones) — основное понятие firewalld:" + utils.ColorReset) + utils.Code(`Зона определяет уровень доверия к трафику интерфейса. + +drop — всё входящее молча отбрасывается +block — входящее отклоняется с сообщением об ошибке +public — публичные сети, только явно разрешённое (по умолчанию) +external — внешние сети с маскарадингом +internal — внутренние сети, больше доверие +home — домашние сети +work — рабочие сети +dmz — демилитаризованная зона +trusted — весь трафик разрешён`) + + utils.Println(utils.ColorBold + "Основные команды firewall-cmd:" + utils.ColorReset) + utils.Command("firewall-cmd --state", "работает ли firewalld") + utils.Command("systemctl status firewalld", "статус сервиса") + utils.Command("firewall-cmd --get-active-zones", "активные зоны и интерфейсы") + utils.Command("firewall-cmd --get-default-zone", "зона по умолчанию") + utils.Command("firewall-cmd --list-all", "все правила активной зоны") + utils.Command("firewall-cmd --list-all --zone=public", "правила зоны public") + fmt.Println() + utils.Println(utils.ColorBold + "Управление сервисами и портами:" + utils.ColorReset) + utils.Code(`# Разрешить сервис (временно, до перезагрузки): +firewall-cmd --add-service=http +firewall-cmd --add-service=https +firewall-cmd --add-service=ssh + +# Постоянно (--permanent): +firewall-cmd --permanent --add-service=http +firewall-cmd --permanent --add-service=https +firewall-cmd --reload # применить permanent-правила + +# Удалить сервис: +firewall-cmd --permanent --remove-service=http + +# Список доступных сервисов: +firewall-cmd --get-services + +# Разрешить порт напрямую: +firewall-cmd --permanent --add-port=8080/tcp +firewall-cmd --permanent --add-port=5000-5100/tcp +firewall-cmd --permanent --remove-port=8080/tcp`) + + utils.Println(utils.ColorBold + "Rich rules — сложные правила:" + utils.ColorReset) + utils.Code(`# Разрешить SSH только с конкретного IP: +firewall-cmd --permanent --add-rich-rule=' + rule family="ipv4" + source address="192.168.1.0/24" + service name="ssh" accept' + +# Заблокировать IP: +firewall-cmd --permanent --add-rich-rule=' + rule family="ipv4" + source address="10.10.10.5" + drop' + +# Ограничить количество соединений (rate limiting): +firewall-cmd --permanent --add-rich-rule=' + rule service name="ssh" + limit value="5/m" accept'`) + + utils.Println(utils.ColorBold + "Маскарадинг (NAT):" + utils.ColorReset) + utils.Code(`# Включить маскарадинг (нужно для роутера): +firewall-cmd --permanent --zone=external --add-masquerade + +# Пробросить порт: +firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=8080 +# Внешний 80 → внутренний 8080`) + + // ─── 48. Восстановление доступа ─────────────────────────────── + utils.Section("48. Восстановление доступа") + + utils.Println("Что делать если потеряли пароль root или доступ к системе.") + fmt.Println() + utils.Println(utils.ColorBold + "Сброс пароля root (RHEL/CentOS):" + utils.ColorReset) + utils.Code(`1. Перезагрузить систему. +2. В меню GRUB нажать 'e' на нужной записи. +3. Найти строку начинающуюся с linux или linuxefi. +4. В конце строки добавить: rd.break +5. Нажать Ctrl+X для загрузки. + +# В initramfs shell: +mount -o remount,rw /sysroot # перемонтировать с правами записи +chroot /sysroot # перейти в систему +passwd root # задать новый пароль root +# Если SELinux включён: +touch /.autorelabel # переметить файлы SELinux +exit +reboot`) + + utils.Println(utils.ColorBold + "Сброс пароля root (Ubuntu/Debian):" + utils.ColorReset) + utils.Code(`1. В GRUB выбрать "Advanced options". +2. Выбрать строку "(recovery mode)". +3. В меню recovery выбрать "root". + +# Или: в GRUB нажать 'e', найти строку linux, +# заменить ro на rw, добавить в конец: init=/bin/bash + +# В shell: +passwd root +# Если файловая система только для чтения: +mount -o remount,rw / +passwd root +sync +reboot -f`) + + utils.Println(utils.ColorBold + "Восстановление из LiveCD:" + utils.ColorReset) + utils.Code(`# Загрузиться с LiveCD/LiveUSB + +# Найти системный раздел: +lsblk + +# Смонтировать: +mount /dev/sda2 /mnt +mount /dev/sda1 /mnt/boot # boot раздел + +# Для UEFI: +mount /dev/sda1 /mnt/boot/efi + +# Chroot: +mount --bind /dev /mnt/dev +mount --bind /proc /mnt/proc +mount --bind /sys /mnt/sys +chroot /mnt + +# Теперь можно: passwd root, grub-install, etc.`) + + utils.Footer() +} diff --git a/modules/linuxmodules/linux_streams.go b/modules/linuxmodules/linux_streams.go new file mode 100644 index 0000000..ca96025 --- /dev/null +++ b/modules/linuxmodules/linux_streams.go @@ -0,0 +1,135 @@ +package linuxmodules + +import ( + "fmt" + "rubric/utils" +) + +var StreamsModule = Module{ + Key: "streams", + Aliases: []string{"st", "io", "потоки"}, + Title: "Стандартные потоки и перенаправление", + Description: "Тема 11: stdin, stdout, stderr, перенаправление, pipe", + Run: showStreams, +} + +func showStreams() { + utils.Header("Linux — Стандартные потоки и перенаправление") + + // ─── 11. Стандартные потоки ─────────────────────────────────── + utils.Section("11. Стандартные потоки (Standard Streams)") + + utils.Println("Каждый процесс в Linux имеет три стандартных потока ввода-вывода:") + fmt.Println() + utils.Code(`Дескриптор Имя Поток По умолчанию +────────────────────────────────────────────────────── +0 stdin ввод клавиатура +1 stdout вывод терминал +2 stderr вывод ошибок терминал + +Программа читает из stdin, пишет результат в stdout, +ошибки — в stderr.`) + + utils.Println(utils.ColorBold + "Перенаправление вывода (stdout):" + utils.ColorReset) + utils.Code(`> — перенаправить stdout в файл (перезаписать) +>> — перенаправить stdout в файл (дописать в конец) + +ls /etc > list.txt # список файлов → файл +echo "строка" >> log.txt # дописать в конец +date > /dev/null # выбросить вывод в никуда`) + + utils.Println(utils.ColorBold + "Перенаправление ошибок (stderr):" + utils.ColorReset) + utils.Code(`2> — перенаправить stderr в файл +2>> — дописать stderr в файл +2>&1 — направить stderr туда же куда stdout + +ls /nonexistent 2> errors.txt # ошибки → файл +ls /etc 1> out.txt 2> err.txt # каждый поток отдельно +ls /etc /nonexistent > all.txt 2>&1 # всё в один файл +ls /etc /nonexistent &> all.txt # краткая форма bash +ls /etc /nonexistent 2>/dev/null # подавить ошибки`) + + utils.Println(utils.ColorBold + "Перенаправление ввода (stdin):" + utils.ColorReset) + utils.Code(`< — читать stdin из файла + +sort < unsorted.txt # отсортировать содержимое файла +wc -l < file.txt # считать строки из файла + +# Here-document — передать несколько строк: +cat << EOF +строка 1 +строка 2 +EOF + +# Here-string — передать строку: +grep 'pattern' <<< "одна строка для поиска"`) + + utils.Println(utils.ColorBold + "Конвейер (pipe) |:" + utils.ColorReset) + utils.Println("Pipe передаёт stdout одной команды в stdin следующей.") + utils.Code(`ls -la | grep '.conf' # только .conf файлы +cat /etc/passwd | sort # отсортировать passwd +ps aux | grep nginx # найти процессы nginx +cat file.txt | wc -l # посчитать строки +ls /etc | head -10 # первые 10 строк +history | tail -20 | grep git # цепочка из трёх команд`) + + utils.Println(utils.ColorBold + "tee — записать и передать дальше:" + utils.ColorReset) + utils.Code(`# tee читает stdin, пишет в файл И в stdout: +ls -la | tee listing.txt | grep '.conf' + +# -a — дописать в файл (append): +echo "строка" | tee -a log.txt`) + + utils.Println(utils.ColorBold + "xargs — передать строки как аргументы:" + utils.ColorReset) + utils.Code(`# find возвращает список файлов, xargs передаёт их rm: +find /tmp -name '*.tmp' | xargs rm -f + +# -I{} — подстановка каждой строки в {}: +cat hosts.txt | xargs -I{} ping -c1 {} + +# -P4 — параллельно (4 процесса): +cat urls.txt | xargs -P4 -I{} curl -O {}`) + + utils.Println(utils.ColorBold + "/dev/null и /dev/zero:" + utils.ColorReset) + utils.Code(`/dev/null — "чёрная дыра": запись выбрасывается, чтение → EOF +/dev/zero — бесконечный источник нулевых байт +/dev/random — случайные байты (медленно, использует энтропию) +/dev/urandom — псевдослучайные байты (быстро) + +# Типичные применения: +command > /dev/null 2>&1 # подавить весь вывод +dd if=/dev/zero of=file bs=1M count=100 # создать 100МБ файл +cat /dev/urandom | head -c 16 | base64 # случайный токен`) + + utils.Println(utils.ColorBold + "Подстановка команд (command substitution):" + utils.ColorReset) + utils.Code(`# Результат команды используется как аргумент: +echo "Сегодня: $(date)" +ls -la $(which python3) +mkdir backup_$(date +%Y%m%d) + +# Старый стиль (обратные кавычки): +echo "Версия: $(uname -r)" # backtick-форма устарела, используйте $()`) + + utils.Println(utils.ColorBold + "Полезные фильтры для pipe:" + utils.ColorReset) + utils.Command("grep", "фильтр строк по паттерну") + utils.Command("sed 's/old/new/g'", "замена текста в потоке") + utils.Command("awk '{print $1}'", "обработка/вывод полей") + utils.Command("sort", "сортировка строк") + utils.Command("uniq", "удаление дубликатов (после sort)") + utils.Command("head -n N", "первые N строк") + utils.Command("tail -n N", "последние N строк") + utils.Command("wc -l", "подсчёт строк") + utils.Command("tr 'a-z' 'A-Z'", "замена символов") + utils.Command("cut -d: -f1", "вырезать поле") + fmt.Println() + utils.Code(`# Практический пример — топ-5 процессов по памяти: +ps aux --sort=-%mem | head -6 + +# Все уникальные IP из лога nginx: +cat /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -20 + +# Подсчёт файлов по расширению: +find . -type f | sed 's/.*\.//' | sort | uniq -c | sort -rn`) + + utils.Footer() +} diff --git a/modules/linuxmodules/linux_sysconfig.go b/modules/linuxmodules/linux_sysconfig.go new file mode 100644 index 0000000..f928e6c --- /dev/null +++ b/modules/linuxmodules/linux_sysconfig.go @@ -0,0 +1,191 @@ +package linuxmodules + +import ( + "fmt" + "rubric/utils" +) + +var SysconfigModule = Module{ + Key: "sysconfig", + Aliases: []string{"cfg", "time", "ntp", "chrony", "настройка"}, + Title: "Конфигурация системы", + Description: "Темы 53–54: установка RHEL, настройка времени, NTP, chronyd", + Run: showSysconfig, +} + +func showSysconfig() { + utils.Header("Linux — Конфигурация системы") + + // ─── 53. Установка RHEL ─────────────────────────────────────── + utils.Section("53. Установка RHEL и первоначальная настройка") + + utils.Println("RHEL (Red Hat Enterprise Linux) — коммерческий дистрибутив.") + utils.Println("Бесплатные альтернативы: AlmaLinux, Rocky Linux (1:1 совместимы с RHEL).") + fmt.Println() + utils.Println(utils.ColorBold + "Получение RHEL:" + utils.ColorReset) + utils.Code(`# Бесплатная подписка для разработчиков (до 16 машин): +# https://developers.redhat.com/articles/faqs-no-cost-red-hat-enterprise-linux + +# Скачать ISO: +# https://access.redhat.com/downloads + +# Альтернативы без подписки: +# AlmaLinux: https://almalinux.org +# Rocky Linux: https://rockylinux.org +# CentOS Stream: https://www.centos.org/centos-stream/`) + + utils.Println(utils.ColorBold + "Первоначальная настройка после установки:" + utils.ColorReset) + utils.Code(`# Обновить систему: +dnf update -y + +# Настроить hostname: +hostnamectl set-hostname server01.example.com +hostnamectl status + +# Настроить часовой пояс: +timedatectl set-timezone Europe/Moscow + +# Включить автоматическую синхронизацию времени: +timedatectl set-ntp true + +# Добавить репозиторий EPEL (Extra Packages): +dnf install epel-release -y +# или для RHEL: +subscription-manager repos --enable codeready-builder-for-rhel-9-x86_64-rpms + +# Включить CRB (CodeReady Builder) — нужен для некоторых пакетов EPEL: +dnf config-manager --set-enabled crb # RHEL 9 +dnf config-manager --set-enabled powertools # RHEL 8`) + + utils.Println(utils.ColorBold + "subscription-manager — управление подпиской RHEL:" + utils.ColorReset) + utils.Code(`# Зарегистрировать систему: +subscription-manager register --username=myuser --password=mypass + +# Присоединить подписку: +subscription-manager attach --auto + +# Список доступных репозиториев: +subscription-manager repos --list + +# Включить репозиторий: +subscription-manager repos --enable rhel-9-for-x86_64-baseos-rpms +subscription-manager repos --enable rhel-9-for-x86_64-appstream-rpms + +# Отключить регистрацию: +subscription-manager unregister`) + + utils.Println(utils.ColorBold + "hostnamectl — управление именем хоста:" + utils.ColorReset) + utils.Command("hostnamectl", "показать всю информацию о хосте") + utils.Command("hostnamectl set-hostname myserver", "установить hostname") + utils.Command("hostnamectl set-hostname 'My Server' --pretty", "красивое имя") + utils.Command("hostname", "показать текущий hostname") + utils.Command("cat /etc/hostname", "hostname из файла") + fmt.Println() + utils.Println(utils.ColorBold + "localectl — настройка локали и раскладки:" + utils.ColorReset) + utils.Command("localectl", "показать текущую локаль") + utils.Command("localectl list-locales | grep ru", "русские локали") + utils.Command("localectl set-locale LANG=ru_RU.UTF-8", "установить русскую локаль") + utils.Command("localectl set-keymap ru", "русская раскладка для консоли") + utils.Command("localectl list-keymaps | grep ru", "доступные раскладки") + + // ─── 54. Настройка времени ──────────────────────────────────── + utils.Section("54. Настройка времени. NTP и chronyd") + + utils.Println(utils.ColorBold + "Типы часов в Linux:" + utils.ColorReset) + utils.Code(`RTC (Hardware Clock) — аппаратные часы (BIOS/UEFI), работают без питания +System Clock — системные часы ядра, синхронизируются от RTC при загрузке + +UTC vs LOCAL: +RTC рекомендуется хранить в UTC, чтобы избежать проблем с летним временем. +Отображение в локальном времени — задача ОС.`) + + utils.Println(utils.ColorBold + "timedatectl — управление временем:" + utils.ColorReset) + utils.Command("timedatectl", "показать время, часовой пояс, NTP") + utils.Command("timedatectl status", "то же самое") + utils.Command("timedatectl list-timezones", "список часовых поясов") + utils.Command("timedatectl list-timezones | grep Moscow", "найти московский пояс") + utils.Command("timedatectl set-timezone Europe/Moscow", "установить часовой пояс") + utils.Command("timedatectl set-time '2024-01-15 14:30:00'", "установить время вручную") + utils.Command("timedatectl set-ntp true", "включить синхронизацию по NTP") + utils.Command("timedatectl set-ntp false", "отключить NTP") + utils.Command("timedatectl set-local-rtc 0", "хранить RTC в UTC") + fmt.Println() + utils.Println(utils.ColorBold + "hwclock — работа с аппаратными часами:" + utils.ColorReset) + utils.Command("hwclock", "показать время RTC") + utils.Command("hwclock --systohc", "записать системное время в RTC") + utils.Command("hwclock --hctosys", "установить системное время из RTC") + utils.Command("hwclock --utc", "RTC в UTC") + fmt.Println() + utils.Println(utils.ColorBold + "NTP — Network Time Protocol:" + utils.ColorReset) + utils.Code(`NTP — протокол синхронизации времени по сети. +Иерархия серверов (stratum): + Stratum 0 — атомные часы, GPS + Stratum 1 — серверы напрямую подключённые к stratum 0 + Stratum 2 — синхронизируются от stratum 1 + ... + Stratum 16 — несинхронизированы + +Популярные публичные NTP-серверы: + pool.ntp.org — пул серверов (рекомендуется) + time.google.com — Google + time.cloudflare.com — Cloudflare + ntp1.vniiftri.ru — Россия (ВНИИФТРИ) + ntp2.vniiftri.ru — Россия`) + + utils.Println(utils.ColorBold + "chronyd — рекомендуемый NTP-клиент в RHEL:" + utils.ColorReset) + utils.Code(`# Установка (обычно предустановлен): +dnf install chrony # RHEL/Fedora +apt install chrony # Debian/Ubuntu + +# Управление: +systemctl enable --now chronyd +systemctl status chronyd`) + + utils.Command("chronyc tracking", "статус синхронизации") + utils.Command("chronyc sources", "список NTP-источников") + utils.Command("chronyc sources -v", "подробно") + utils.Command("chronyc sourcestats", "статистика источников") + utils.Command("chronyc makestep", "принудительно синхронизировать (мгновенный шаг)") + utils.Command("chronyc ntpdata", "NTP-данные каждого источника") + fmt.Println() + utils.Println(utils.ColorBold + "Конфигурация chronyd (/etc/chrony.conf):" + utils.ColorReset) + utils.Code(`# Серверы синхронизации: +server pool.ntp.org iburst +server ntp1.vniiftri.ru iburst +server ntp2.vniiftri.ru iburst +pool 2.rhel.pool.ntp.org iburst + +# iburst — отправлять несколько пакетов при первом контакте (быстрее) + +# Разрешить синхронизацию для подсети (NTP-сервер): +allow 192.168.1.0/24 + +# Синхронизировать RTC с системными часами: +rtcsync + +# Сохранять данные о дрейфе: +driftfile /var/lib/chrony/drift + +# Принять шаг > 1 сек только при старте: +makestep 1.0 3 + +# Применить изменения: +systemctl restart chronyd`) + + utils.Println(utils.ColorBold + "Настройка chronyd как NTP-сервера для локальной сети:" + utils.ColorReset) + utils.Code(`# /etc/chrony.conf на сервере: +server pool.ntp.org iburst +allow 192.168.1.0/24 # разрешить клиентам из этой подсети + +# На клиентах /etc/chrony.conf: +server 192.168.1.10 iburst # указать IP локального NTP-сервера + +# Открыть порт на файрволе сервера: +firewall-cmd --permanent --add-service=ntp +firewall-cmd --reload + +# Проверить что клиент синхронизирован: +chronyc sources`) + + utils.Footer() +} diff --git a/modules/linuxmodules/linux_tools.go b/modules/linuxmodules/linux_tools.go new file mode 100644 index 0000000..bfef1fd --- /dev/null +++ b/modules/linuxmodules/linux_tools.go @@ -0,0 +1,252 @@ +package linuxmodules + +import ( + "fmt" + "rubric/utils" +) + +var ToolsModule = Module{ + Key: "tools", + Aliases: []string{"t", "cockpit", "regex", "awk", "sed", "инструменты"}, + Title: "Веб-интерфейс и текстовые инструменты", + Description: "Темы 60–61: Cockpit, глоббинг, регулярные выражения, grep, sed, awk", + Run: showTools, +} + +func showTools() { + utils.Header("Linux — Веб-интерфейс и текстовые инструменты") + + // ─── 60. Cockpit ────────────────────────────────────────────── + utils.Section("60. Веб-интерфейс — Cockpit") + + utils.Println("Cockpit — веб-консоль для администрирования Linux через браузер.") + utils.Println("Позволяет управлять сервисами, сетью, дисками, контейнерами и логами.") + fmt.Println() + utils.Println(utils.ColorBold + "Установка и запуск:" + utils.ColorReset) + utils.Code(`# RHEL/Fedora (обычно предустановлен): +dnf install cockpit +systemctl enable --now cockpit.socket + +# Ubuntu/Debian: +apt install cockpit +systemctl enable --now cockpit.socket + +# Открыть порт в firewalld: +firewall-cmd --permanent --add-service=cockpit +firewall-cmd --reload + +# Доступ: https://hostname:9090 +# Войти с логином/паролем системного пользователя`) + + utils.Println(utils.ColorBold + "Расширения Cockpit:" + utils.ColorReset) + utils.Code(`# Управление виртуальными машинами: +dnf install cockpit-machines + +# Управление Podman-контейнерами: +dnf install cockpit-podman + +# Управление хранилищем (LVM, RAID, Stratis): +dnf install cockpit-storaged + +# 389 DS (LDAP): +dnf install cockpit-389-ds + +# Обновления пакетов: +dnf install cockpit-packagekit + +# Применить все расширения: +systemctl restart cockpit.socket`) + + utils.Println(utils.ColorBold + "Возможности Cockpit:" + utils.ColorReset) + utils.Code(`Dashboard — обзор системы: CPU, RAM, диски, сеть +Services — управление systemd-сервисами +Storage — диски, LVM, RAID, Stratis, NFS +Networking — интерфейсы, маршруты, firewall +Accounts — пользователи и группы +Software Updates — обновление пакетов +Terminal — встроенный терминал в браузере +Logs — journald логи с фильтрами +Podman — управление контейнерами +Machines — виртуальные машины (KVM/libvirt)`) + + utils.Note("Cockpit работает в браузере, не требует постоянного подключения: сессия = одна вкладка.") + utils.Note("Порт 9090. Сертификат самоподписанный — нужно добавить исключение в браузере или подключить Let's Encrypt.") + + // ─── 61. Глоббинг и регулярные выражения ───────────────────── + utils.Section("61. Глоббинг и регулярные выражения") + + utils.Println(utils.ColorBold + "Глоббинг (Globbing) — шаблоны оболочки:" + utils.ColorReset) + utils.Code(`* — любое количество любых символов (кроме /) +? — ровно один любой символ +[abc] — один символ из набора +[a-z] — один символ из диапазона +[!abc] — один символ НЕ из набора +{a,b,c} — одно из перечисленных + +# Примеры: +ls *.log # все файлы .log +ls file?.txt # file1.txt, fileA.txt... +ls [0-9]*.conf # начинающиеся с цифры +ls /etc/{nginx,apache}* # /etc/nginx* или /etc/apache* +rm backup_{2023,2024}*.tar # удалить бэкапы 2023 и 2024 +cp /etc/*.{conf,cfg} /tmp/ # все .conf и .cfg + +# Расширенный глоббинг (shopt -s extglob): +?(pattern) — 0 или 1 вхождение +*(pattern) — 0 или более ++(pattern) — 1 или более +@(pattern) — ровно 1 +!(pattern) — всё кроме`) + + utils.Println(utils.ColorBold + "Регулярные выражения — базовые (BRE):" + utils.ColorReset) + utils.Code(`. — любой символ +* — 0 или более предыдущего +^ — начало строки +$ — конец строки +[abc] — один символ из набора +[^abc] — один символ НЕ из набора +\(abc\) — группа +\{n,m\} — от n до m повторений + +# Примеры: +grep '^root' /etc/passwd # строки начинающиеся с root +grep 'bash$' /etc/passwd # строки оканчивающиеся на bash +grep '^$' file.txt # пустые строки +grep '[0-9]\{3\}' file.txt # три цифры подряд`) + + utils.Println(utils.ColorBold + "Регулярные выражения — расширенные (ERE):" + utils.ColorReset) + utils.Code(`+ — 1 или более предыдущего +? — 0 или 1 предыдущего +| — ИЛИ +(abc) — группа (без \) +{n,m} — от n до m повторений (без \) + +# Использование ERE: grep -E, egrep, sed -E, awk + +grep -E 'cat|dog' file.txt # cat или dog +grep -E '^[0-9]+\.' file.txt # строки начинающиеся с числа. +grep -E '([0-9]{1,3}\.){3}[0-9]{1,3}' file.txt # IPv4-адрес +grep -E 'error|warning|critical' /var/log/syslog + +# Полезные классы символов: +[[:alpha:]] — буквы (a-z, A-Z) +[[:digit:]] — цифры (0-9) +[[:alnum:]] — буквы и цифры +[[:space:]] — пробельные символы +[[:upper:]] — заглавные буквы +[[:lower:]] — строчные буквы +[[:punct:]] — знаки препинания`) + + utils.Println(utils.ColorBold + "grep — поиск по шаблону:" + utils.ColorReset) + utils.Command("grep 'pattern' file", "базовый поиск") + utils.Command("grep -i 'pattern' file", "без учёта регистра") + utils.Command("grep -v 'pattern' file", "строки НЕ совпадающие") + utils.Command("grep -n 'pattern' file", "с номерами строк") + utils.Command("grep -c 'pattern' file", "количество совпадений") + utils.Command("grep -l 'pattern' *.conf", "только имена файлов") + utils.Command("grep -r 'pattern' /etc/", "рекурсивно в директории") + utils.Command("grep -A 3 'pattern' file", "3 строки ПОСЛЕ совпадения") + utils.Command("grep -B 2 'pattern' file", "2 строки ДО совпадения") + utils.Command("grep -C 2 'pattern' file", "2 строки до и после") + utils.Command("grep -E 'pat1|pat2' file", "расширенные регулярки") + utils.Command("grep -P '\\d+' file", "Perl-совместимые regex") + utils.Command("grep -o 'pattern' file", "только совпадающая часть") + utils.Command("grep -w 'word' file", "только целые слова") + fmt.Println() + + utils.Println(utils.ColorBold + "sed — потоковый редактор:" + utils.ColorReset) + utils.Code(`# Синтаксис: sed 'команда' файл +# -i — изменить файл на месте +# -E — расширенные регулярки + +# Замена (s — substitute): +sed 's/old/new/' file # первое вхождение в каждой строке +sed 's/old/new/g' file # все вхождения (global) +sed 's/old/new/gi' file # без учёта регистра +sed 's/old/new/2' file # второе вхождение + +# Разделитель можно менять (удобно для путей): +sed 's|/old/path|/new/path|g' file +sed 's#/etc#/conf#g' file + +# Изменить файл на месте: +sed -i 's/old/new/g' file.conf +sed -i.bak 's/old/new/g' file.conf # сохранить бэкап .bak + +# Удаление строк: +sed '/pattern/d' file # удалить строки с паттерном +sed '5d' file # удалить 5-ю строку +sed '2,10d' file # удалить строки 2-10 +sed '/^$/d' file # удалить пустые строки +sed '/^#/d' file # удалить комментарии + +# Вставка и добавление: +sed '3a новая строка' file # добавить после строки 3 +sed '3i новая строка' file # вставить перед строкой 3 +sed '$a последняя' file # добавить в конец + +# Вывод конкретных строк: +sed -n '5,10p' file # напечатать строки 5-10 +sed -n '/start/,/end/p' file # между паттернами + +# Несколько команд: +sed -e 's/foo/bar/' -e 's/baz/qux/' file +sed 's/foo/bar/; s/baz/qux/' file + +# Практические примеры: +# Удалить комментарии и пустые строки: +sed '/^#/d; /^$/d' nginx.conf + +# Заменить IP во всех конфигах: +sed -i 's/192\.168\.1\.100/10\.0\.0\.1/g' /etc/nginx/*.conf + +# Добавить строку после первого совпадения: +sed '/\[global\]/a log level = 2' /etc/samba/smb.conf`) + + utils.Println(utils.ColorBold + "awk — обработка текста по полям:" + utils.ColorReset) + utils.Code(`# awk обрабатывает текст построчно, разбивая на поля. +# По умолчанию разделитель — пробел/таб. + +# Поля: $1 $2 $3 ... $NF (последнее), $0 (вся строка) +# NF — количество полей, NR — номер строки + +# Вывод конкретного поля: +awk '{print $1}' file # первое поле +awk '{print $1, $3}' file # первое и третье +awk '{print NR, $0}' file # с номерами строк + +# Другой разделитель (-F): +awk -F: '{print $1}' /etc/passwd # имена пользователей +awk -F: '{print $1, $6}' /etc/passwd # имя и домашняя директория +awk -F, '{print $2}' data.csv # второй столбец CSV + +# Условия: +awk '$3 > 1000' file # строки где 3-е поле > 1000 +awk '/pattern/ {print $0}' file # строки с паттерном +awk '$1 == "root"' /etc/passwd # строки где $1 = "root" + +# Вычисления: +awk '{sum += $1} END {print sum}' file # сумма первого столбца +awk 'END {print NR}' file # количество строк (= wc -l) + +# BEGIN и END блоки: +awk 'BEGIN {print "Начало"} {print $1} END {print "Конец"}' file + +# Переменные и форматирование: +awk -F: '{printf "%-20s %s\n", $1, $6}' /etc/passwd + +# Практические примеры: +# Топ процессов по CPU: +ps aux | awk 'NR>1 {print $3, $11}' | sort -rn | head -10 + +# Сумма размеров файлов (ls -l): +ls -l | awk '{sum += $5} END {print sum " bytes"}' + +# Уникальные IP из лога nginx: +awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn + +# Обработка CSV: +awk -F, 'NR>1 && $3 > 100 {print $1, $2}' report.csv`) + + utils.Footer() +} diff --git a/modules/linuxmodules/linux_users.go b/modules/linuxmodules/linux_users.go new file mode 100644 index 0000000..7872d3f --- /dev/null +++ b/modules/linuxmodules/linux_users.go @@ -0,0 +1,223 @@ +package linuxmodules + +import ( + "fmt" + "rubric/utils" +) + +var UsersModule = Module{ + Key: "users", + Aliases: []string{"u", "perms", "sudo", "права"}, + Title: "Пользователи, права и sudo", + Description: "Темы 17–20: su, sudo, пользователи, группы, права на файлы", + Run: showUsers, +} + +func showUsers() { + utils.Header("Linux — Пользователи, права и sudo") + + // ─── 19. Пользователи и группы ─────────────────────────────── + utils.Section("19. Пользователи и группы") + + utils.Println("В Linux каждый файл принадлежит пользователю и группе.") + utils.Println("Каждый процесс запускается от имени определённого пользователя.") + fmt.Println() + utils.Println(utils.ColorBold + "Основные файлы пользователей:" + utils.ColorReset) + utils.Code(`/etc/passwd — список пользователей +/etc/shadow — хэши паролей (только root) +/etc/group — группы + +# Формат /etc/passwd: +# имя:пароль:UID:GID:комментарий:home:shell +alice:x:1000:1000:Alice Smith:/home/alice:/bin/bash +root:x:0:0:root:/root:/bin/bash +# x — пароль в /etc/shadow +# UID 0 — root (суперпользователь) +# UID 1-999 — системные пользователи +# UID 1000+ — обычные пользователи + +# Формат /etc/group: +# имя:пароль:GID:члены +sudo:x:27:alice,bob +docker:x:999:alice`) + + utils.Println(utils.ColorBold + "Информация о пользователях:" + utils.ColorReset) + utils.Command("id", "UID, GID и группы текущего пользователя") + utils.Command("id alice", "информация о пользователе alice") + utils.Command("whoami", "имя текущего пользователя") + utils.Command("groups", "группы текущего пользователя") + utils.Command("getent passwd alice", "запись alice из /etc/passwd") + utils.Command("getent group docker", "участники группы docker") + fmt.Println() + utils.Println(utils.ColorBold + "Управление пользователями (root):" + utils.ColorReset) + utils.Command("useradd alice", "создать пользователя") + utils.Command("useradd -m -s /bin/bash -G sudo alice", "с домашней директорией, оболочкой и группой") + utils.Command("passwd alice", "установить пароль") + utils.Command("usermod -aG docker alice", "добавить alice в группу docker") + utils.Command("usermod -s /bin/zsh alice", "изменить оболочку") + utils.Command("usermod -L alice", "заблокировать учётную запись") + utils.Command("usermod -U alice", "разблокировать") + utils.Command("userdel alice", "удалить пользователя") + utils.Command("userdel -r alice", "удалить с домашней директорией") + fmt.Println() + utils.Println(utils.ColorBold + "Управление группами:" + utils.ColorReset) + utils.Command("groupadd developers", "создать группу") + utils.Command("groupdel developers", "удалить группу") + utils.Command("gpasswd -a alice developers", "добавить alice в группу") + utils.Command("gpasswd -d alice developers", "удалить alice из группы") + fmt.Println() + utils.Note("После добавления в группу пользователь должен перелогиниться. Или: newgrp groupname") + + // ─── 20. Права на файлы ─────────────────────────────────────── + utils.Section("20. Права на файлы") + + utils.Println(utils.ColorBold + "Структура прав доступа:" + utils.ColorReset) + utils.Code(`ls -l file.txt +-rw-r--r-- 1 alice users 1024 Jan 15 10:00 file.txt +│└──────────┘ +│ 9 бит прав +└ тип файла (- файл, d директория, l ссылка...) + +Права разделены на 3 группы по 3 бита: +rwx rwx rwx +│ │ └── other (остальные пользователи) +│ └─────── group (группа владельца) +└─────────── owner (владелец) + +r — read (чтение): 4 +w — write (запись): 2 +x — execute (выполнение): 1 +- — нет права: 0 + +Пример: rw-r--r-- + owner: rw- = 6 (4+2) — чтение и запись + group: r-- = 4 — только чтение + other: r-- = 4 — только чтение + Численно: 644`) + + utils.Println(utils.ColorBold + "chmod — изменить права:" + utils.ColorReset) + utils.Code(`# Числовой (восьмеричный) способ: +chmod 644 file.txt # rw-r--r-- +chmod 755 script.sh # rwxr-xr-x +chmod 600 private.key # rw------- +chmod 777 dir/ # rwxrwxrwx (небезопасно!) +chmod 750 script.sh # rwxr-x--- + +# Символьный способ: +chmod u+x script.sh # добавить execute владельцу +chmod g-w file.txt # убрать write у группы +chmod o-r secret.txt # убрать чтение у остальных +chmod a+r public.txt # добавить чтение всем (a = all) +chmod u+x,g-w file # несколько изменений +chmod go=r file.txt # установить группе и остальным только r + +# Рекурсивно: +chmod -R 755 /var/www/html/`) + + utils.Println(utils.ColorBold + "Типичные значения прав:" + utils.ColorReset) + utils.Code(`644 rw-r--r-- обычный файл (конфиги, тексты) +755 rwxr-xr-x исполняемый файл, директория +700 rwx------ личный скрипт/директория +600 rw------- приватный ключ, .env файл +640 rw-r----- конфиг с секретами (owner + group) +664 rw-rw-r-- файл для работы в группе +1777 rwxrwxrwt /tmp (sticky bit)`) + + utils.Println(utils.ColorBold + "chown — изменить владельца:" + utils.ColorReset) + utils.Command("chown alice file.txt", "изменить владельца") + utils.Command("chown alice:users file.txt", "изменить владельца и группу") + utils.Command("chown :users file.txt", "изменить только группу") + utils.Command("chown -R alice:alice /home/alice/", "рекурсивно") + utils.Command("chgrp users file.txt", "изменить только группу") + fmt.Println() + utils.Println(utils.ColorBold + "Специальные биты:" + utils.ColorReset) + utils.Code(`SUID (Set User ID) — 4000: + Файл запускается с правами владельца файла, а не запускающего. + chmod u+s /usr/bin/passwd # или chmod 4755 + ls -la: -rwsr-xr-x (s вместо x у владельца) + Пример: passwd изменяет /etc/shadow (root-файл) + +SGID (Set Group ID) — 2000: + Файл: запускается от имени группы файла. + Директория: новые файлы наследуют группу директории. + chmod g+s /shared/ # или chmod 2755 + ls -la: drwxrwsr-x + +Sticky Bit — 1000: + Директория: файл может удалить только его владелец. + chmod +t /tmp/ # или chmod 1777 + ls -la: drwxrwxrwt + Применение: /tmp, /var/tmp`) + + utils.Println(utils.ColorBold + "umask — маска прав по умолчанию:" + utils.ColorReset) + utils.Code(`umask определяет права, которые НЕ назначаются новым файлам. + +umask # показать текущую маску (обычно 0022) +umask 0022 # установить маску + +# Как работает: +# Файлы создаются с 666, директории с 777. +# Umask 022 вычитается: +# 666 - 022 = 644 (файлы: rw-r--r--) +# 777 - 022 = 755 (директории: rwxr-xr-x) +# Umask 077: +# 666 - 077 = 600 (файлы: rw-------) +# 777 - 077 = 700 (директории: rwx------) + +# Установить постоянно в ~/.bashrc: +umask 0027`) + + // ─── 17–18. su и sudo ───────────────────────────────────────── + utils.Section("17–18. su, sudo и visudo") + + utils.Println(utils.ColorBold + "su — Switch User:" + utils.ColorReset) + utils.Command("su -", "переключиться в root (login shell, нужен пароль root)") + utils.Command("su", "переключиться в root (без login shell)") + utils.Command("su - alice", "переключиться в alice") + utils.Command("su -c 'команда' alice", "выполнить команду от имени alice") + fmt.Println() + utils.Code(`Разница su vs su -: +su — только смена UID, переменные окружения остаются +su - — полноценный вход, загружается окружение пользователя + (PATH, HOME и т.д.) + +Выйти из su: exit или Ctrl+D`) + + utils.Println(utils.ColorBold + "sudo — выполнить как другой пользователь:" + utils.ColorReset) + utils.Command("sudo command", "выполнить команду как root") + utils.Command("sudo -u alice command", "выполнить от имени alice") + utils.Command("sudo -i", "интерактивная сессия root (= su -)") + utils.Command("sudo -s", "оболочка root с текущим окружением") + utils.Command("sudo -l", "показать разрешённые команды для текущего пользователя") + utils.Command("sudo -l -U alice", "разрешённые команды для alice") + utils.Command("sudo !!", "повторить последнюю команду с sudo") + fmt.Println() + utils.Code(`sudo кэширует аутентификацию на 15 минут (по умолчанию). +sudo -k — сбросить кэш (следующая команда потребует пароль)`) + + utils.Println(utils.ColorBold + "visudo — редактирование /etc/sudoers:" + utils.ColorReset) + utils.Code(`# НИКОГДА не редактируйте /etc/sudoers напрямую! +# visudo проверяет синтаксис перед сохранением. + +sudo visudo + +# Формат правил: +# WHO WHERE=(AS_WHOM) WHAT + +# Примеры /etc/sudoers: +root ALL=(ALL:ALL) ALL # root имеет все права +%sudo ALL=(ALL:ALL) ALL # группа sudo — все права +%wheel ALL=(ALL:ALL) ALL # RHEL: группа wheel + +alice ALL=(ALL) ALL # alice — все команды +alice ALL=(ALL) NOPASSWD:ALL # без пароля (небезопасно!) +bob ALL=(root) /usr/bin/apt # только apt от root +netadmin ALL=(root) /usr/bin/nmtui # только nmtui +helpdesk ALL=(root) /usr/bin/passwd, !/usr/bin/passwd root # пароли кроме root + +# Файлы из /etc/sudoers.d/ включаются автоматически. +# Лучше создавать файл там, а не редактировать sudoers: +sudo visudo -f /etc/sudoers.d/alice`) + + utils.Footer() +} diff --git a/rubric b/rubric index a8755e4..6ce49a8 100755 Binary files a/rubric and b/rubric differ