У чому сенс дочірнього процесу

У чому сенс дочірнього процесу



Сенс схеми створення процесів у UNIX

Привіт. У вінді для створення процесу використовується один системний виклик. У ніксах їх два: fork а потім exec. Який сенс спочатку копіювати себе, а потім замінювати образ пам'яті?

у вінді те ж саме закамуфлювали під один виклик

спочатку копіювати себе, а потім замінювати образ пам'яті?

запропонуй спосіб краще, при цьому врахуй COW

по-перше, після fork не завжди виконують exec, а по-друге, ніхто там нічого не копіює (без потреби), читай про COW Copy-On-Write

COW – це коли для дочірнього процесу створюється свій адресний простір лише при спробі запили, чи я правильно зрозумів? Я не розумію самого сенсу створення копії. Чому не можна відразу створити окремий процес та образ пам'яті для нього?

У UNIX існує лише один системний виклик для створення нового процесу – fork. Цей виклик створює точну копію процесу, що викликає. Після виконання системного виклику fork два процеси, батьківський і дочірній, мають єдиний образ пам'яті, єдині рядки опису конфігурації та одні й самі відкриті файли. І більше нічого. Зазвичай після цього дочірній процес змінює образ пам'яті і запускає нову програму, виконуючи системний виклик execve або подібний до нього. Наприклад, коли користувач набирає в оболонці команду sort, оболонка створює дочірній процес, що відгалужується, в якому і виконується команда sort. Сенс цього двоступеневого процесу полягає в тому, щоб дозволити дочірньому процесу керувати його файловими дескрипторами після розгалуження, але перед виконанням execve з метою виконання перенаправлення стандартного введення, стандартного виводу та стандартного виведення повідомлень про помилки.

У Windows все відбувається по-іншому: одним викликом функції Win32 CreateProcess створюється процес, і в нього завантажується потрібна програма. Цей виклик має 10 параметрів, включаючи виконувану програму, параметри командного рядка для цієї програми, різні параметри безпеки, біти, що керують успадкуванням відкритих файлів, інформацію про пріоритети, специфікацію вікна, створюваного для процесу (якщо воно використовується), і покажчик на структуру, в якій програмі, що викликає, буде повернуто інформацію про щойно створений процес. На додаток до функції CreateProcess Win32 є близько 100 інших функцій для управління процесами та їх синхронізації, а також виконання всього, що з цим пов'язано.

Я зараз читаю 4 видання книги Таненбаума. Переклад, треба сказати, дуже лайновий.

Сенс цього двоступеневого процесу полягає в тому, щоб дозволити дочірньому процесу керувати його файловими дескрипторами після розгалуження, але перед виконанням execve з метою виконання перенаправлення стандартного введення, стандартного виводу та стандартного виведення повідомлень про помилки.

Я один не зрозумію сенсу цієї пропозиції?

Ні, так є vfork(), який нічого не копіює навіть при записі (UB). Але взагалі пайпи, наприклад, дуже активно юзають виведення попередньої програми. І взагалі багато сервісів, що створюють треди-копії, веб-ревер, наприклад. Тож доступ синка до віртуальної пам'яті батька (хочаби навіть рідонлі) це таки вин.

Що незрозуміло? Дочка не відкриває дескриптори наново, а юзає батьківські, заощаджує пам'ять та час.

Ось тепер зрозуміло. А в книзі чортзна що написано.

Фіча в тому, що exec() не завжди потрібен, можна виконувати одну і ту ж програму в декількох процесах, причому дочірні процеси продовжують роботу з повернення з fork(), з вже проініціалізованими файловими дескрипторами. У вінді так не вийде, дочірньому процесу доведеться виконувати програму від початку

Іноді роблять fork без exec. Іноді вони виконують без вилки. Це більш гнучке API.

Привіт. У вінді для створення процесу використовується один системний виклик. У ніксах їх два: fork а потім exec.

Один. exec не створює процесів.

ооп, успадкування, поліморфізм, інкапсуляція, уніфікація, KISS, DRY, YAGNI

патерни проектування, agile, scrum

Якщо точно, то таки два - fork і clone.

CONFORMING TO clone() є Linux-specific і не може бути використаний в програмах, що надаються до портативного.

posix_spawn() спеціально для тебе.

execve() is Posix-specific and should not be used in programs intended to be portable

Дочка не відкриває дескриптори наново, а юзає батьківські, заощаджує пам'ять та час.

Ось тепер зрозуміло.

fork-exec не був призначений для економії ресурсів (і в перші роки UNIX жодного COW не було). Створення процесів через fork - це спосіб настроїти середовище виконання нащадка (спрощено кажучи, заповнити дані у пам'яті та відкрити/закрити потрібні дескриптори).

tailgunner ★★★★★
(29.10.16 11:35:44 MSK)
Останнє виправлення: tailgunner 29.10.16 11:37:32 MSK (всього виправлень: 1)

«Функція з інтерфейсу, що переноситься, не повинна використовуватися в програмах, які хочуть бути переносимими»? Ти зовсім шизався?

fork-exec не був призначений для економії ресурсів (і в перші роки UNIX жодного COW не було).

зафіксовано у Plan 9.там rfork має додаткові поля (FreeBSD: теж rfork) - можна вказати які саме ресурси поділяються

Створення процесів через fork - це спосіб настроїти середовище виконання нащадка (спрощено кажучи, заповнити дані у пам'яті та відкрити/закрити потрібні дескриптори).

ну так. Знову ж таки, в Plan 9 можна вказати які ресурси поділяються (включаючи простори імен файлової системи) тобто, у кожного процесу точка зору на файлову систему налаштовується по-різному, клієнт-сервер файловий виступає об'єктним клієнтом і сервером, об'єкти представляються. як віртуальні псевдофайли, P9 fs як файловий протокол реалізує метаоб'єктний протокол, прозорий по мережі. мультиплексором реальних багатьох об'єктів/ресурсів/файлів в один віртуальний псевдофайл простору імен, клієнт — демультиплексор або користувач віртуального ресурсу.

наприклад: у віконній системі rio окремі нероздільні ресурси «вікна» /dev/window/NNN => «відображаються на» псеводфайл, загальний ресурс /dev/window поточного додатка. середовищі/IDDE acme: контрольні файли реалізують інтерфейс доступу до ресурсів acme, вікон програми.

точніше, не «інтерфейс API», а протокол управління ресурсами, метаоб'єктний протокол реалізований через файли.

в цьому сенсі і REST-like API для управління ресурсами Content-Addressable Memory також можна розглядати не як набір мікросервісів, а як метаоб'єктний протокол як і P9FS.

в Erlang взаємодія між легковажними процесами реалізована як пролог, як марківський алгоритм.тобто: замість процесів-процесів-алгоритмів, пов'язаних через пайпи, простим текстовим інтерфейсом (унікальним для кожної пари програм) або «об'єктним інтерфейсом», недоуніверсальним метапротоколом (як у PowerShell: передаються між пайпами не текст, а об'єкти, у яких можна рефлексією опитати властивості, посмикати за стандартні методи) - Erlang ближче до бази ЗНАНЬ, ПРОДУКЦІЙНОЇ МОДЕЛИ ЯКЩО , ТО : якщо є подія-висновок на стандартний висновок постачальника, то запустити дію-обробку події у споживача.

при цьому патерн матчінг, підстановки в Erlang, plumbing у Plan9 роблять механізм виклику більш універсальним та зручним.

від сильнопов'язаних API до більш пов'язаних компонентів, агентів-об'єктів і протоколів.

Процеси

Процеси – діюче початок. У загальному випадку з процесом пов'язані код та дані у віртуальній оперативній пам'яті, відображення віртуальної пам'яті на фізичну, стан процесора (реєстри, поточна інструкція, що виконується тощо). (у тому числі знижувальний коефіцієнт nice), інформація про відкриті файли та обробники сигналів. виконувана всередині процесу може змінюватися протягом його існування.

Створення процесів fork()

Нові процеси створюються викликом int pid=fork() , який створює точну копію процесу, що його викликав.

  • унікальний ідентифікатор процесу PID
  • ідентифікатор батьківського процесу PPID
  • значення, що повертається викликом fork() . PID дочірній процес або помилка (-1), в дочірньому fork() завжди повертає 0.

Після створення дочірній процес може завантажити в свою пам'ять нову програму (код і дані) з виконуваного файлу викликом execve (const char * filename, char * const argv [], char * const envp []);

Дочірній процес пов'язаний із батьківським значенням PPID. У разі завершення батьківського процесу PPID змінюється на особливе значення 1 - PID процесу init.

Процес init

У момент завантаження ядра створюється особливий процес з PID=1, який має існувати до перезавантаження ОС. init тому надалі я називатиму його "процес init".

У Linux процес init захищений від втручання інших процесів. procfs, йому не доставляються сигнали, що призводять до завершення процесу. init все ж таки завершиться, то ядро ​​також завершує роботу з відповідним повідомленням.

У сучасних дистрибутивах класична програма init замінена на systemd, але сутності процесу з PID=1 це змінює.

При завантаженні Linux ядро спочатку монтує кореневу файлову систему на образ диска в оперативній пам'яті initrd, Потім створюється процес з PID=1 і завантажує в нього програму із файлу /init. initrd з дистрибутива CentOS початковий /init - це скрипт для /bin/bash.Скрипт завантажує необхідні драйвери, після чого робить дві речі, необхідні для повноцінного запуску Linux:

  1. Перемонтує кореневу файлову систему на основний носій
  2. Завантажує командою exec на свою пам'ять основну програму init

Для того, щоб виконати ці два пункти через завантажувач у початковому init два параметри:

  • основний носій кореневої ФС. Наприклад: root=/dev/sda1
  • ім'я файлу з програмою init. Наприклад: init=/bin/bash

Якщо другий параметр опущено, то шукається ім'я зашите в початковий init за замовчуванням.

Якщо ви завантажите замість init /bin/bashЯк у моєму прикладі, то зможете завершити перший і єдиний процес командою exit та поспостерігати за повідомленням:

Kernel panic - не syncing: Attempted to kill init!

Цей приклад показує, як отримати права адміністратора при фізичному доступі до комп'ютера.

PID

Кожен процес має унікальний на даний момент ідентифікатор PID. Змінити PID процесу неможливо.

Значення PID 0 та 1 зарезервовані. Процес з PID==0 не використовується, PID==1 - належить програмі init.

Максимальне значення PID у Linux дорівнює PID_MAX-1. Поточне значення PID_MAX можна подивитися командою:

cat /proc/sys/kernel/pid_max

За замовчуванням це 2^16 (32768) однак у 64-розрядних Linux його можна збільшити до 222 (4194304):

echo 4194303 > /proc/sys/kernel/pid_max

*PID* призначаються послідовно. При створенні нового процесу викликом fork шукається *PID* , більший за значенням, ніж той, який повернули попереднім викликом fork . Якщо під час пошуку досягнуто значення pid_max , то пошук продовжується з PID=2. Така поведінка обрана тому, що деякі програми можуть перевіряти завершення процесу існування його PID. У цій ситуації бажано, щоб PID не використовувався деякий час після завершення процесу.

UID та GID

З процесом пов'язане поняття "власника" та "групи", що визначають права доступу процесу до інших процесів та файлів у файловій системі. "Власник" та "група", це числові ідентифікатор UID і GIDє атрибутами процесу. На відміну від файлу, процес може належати кільком групам одночасно. Користувач у діалоговому сеансі має право на доступ до своїх файлів, оскільки діалогова програма (shell), яку він використовує, виконується в процесі з тим же UIDом, що і UIDвказаний в атрибутах файлів.

Процес може змінити свого власника та групу у двох випадках:

  1. поточний UID дорівнює 0 (відповідає користувачу root) і процес звернувся до системного виклику setuid(newuid). І тут процес повністю змінює власника.
  2. процес звернувся до виклику exec(file) завантаживши у пам'ять програму з файлу в атрибутах якого виставлено прапор suid або sgid. У цьому випадку власник процесу зберігається, але права доступу будуть обчислюватися на основі UID і GID файлу.

Життєвий цикл процесу

Створення процесу

Виклик newpid=fork() створює новий процес, що є точною копією поточного і відрізняється лише значенням newpid, що повертається. У батьківському процесі newpid дорівнює PID дочірнього процесу, у дочірньому процесі newpid дорівнює 0. Свій PID можна дізнатися викликом mypid=getpid() , батьківський викликом parentpid=getppid() .

int pid, cpid; int int status; pid=fork() if( pid > 0 ) < cpid=waitpid(&status); if( cpid >0 ) < printf("Я старий процес (pid=%i) створив новий (pid=%i), що завершився з кодом %i\n", getpid(),pid,WEXITSTATUS(status) ); >>else if( pid == 0 )< printf("Я новий процес (pid=%i) створений старим (pid=%i)\n",getpid(),getppid()); >else

Запуск програми

В оперативній пам'яті процесу знаходяться код та дані, завантажені з файлу. При запуску програми з командного рядка зазвичай створюється новий процес і в його пам'ять завантажується файл із програмою. Завантаження файлу робиться викликом однієї з функцій сімейства exec (див. man 3 exec). Функції відрізняються способом передачі параметрів, а також тим, чи використовується змінна оточення PATH для пошуку файлу, що виконується. Наприклад, execl як перший параметр приймає ім'я виконуваного файлу, другим і наступними – рядки аргументи, що передаються в argv[], і, нарешті, останній параметр повинен бути NULL, він дає процедурі можливість визначити, що параметрів більше немає.

int pid = fork (); if( pid > 0 )< waitpid(NULL); >else if( pid == 0 ) < if(-1 == execl("/bin/ls","ls","-l",NULL) ) < exit(1); >>

Приклад exec з двома помилками:

if( 0 == execl("/bin/ls","-l",NULL) )< printf("Програма ls запущена успішно\n"); >else

Помилка 1: Перший аргумент, що передається програмі, це ім'я самої програми. У цьому прикладі у списку процесів буде видно програму з ім'ям -l, запущену без параметрів.

Помилка 2: Оскільки код із файлу /bin/ls буде завантажений у поточний процес, то старий код та дані, у тому числі printf("Програма ls запущена успішно\n"), буде затерто. Перший printf ніколи не спрацює.

Завершення процесу

Процес може завершитись, отримавши сигнал або через системний виклик _exit(int status) . status може приймати значення від 0 до 255. За угодою, status==0 означає успішне завершення програми, а ненульове значення означає помилку. Деякі програми (наприклад kaspersky для Linux) використовують статус повернення певної інформації про результати роботи програми.

_exit() може бути викликаний кількома шляхами.

  • return status; функції main() . У цьому випадку _exit() виконає певна службова функція, що викликає main()
  • через бібліотечну функцію exit(status) , яка завершує роботу бібліотеки libc та викликає _exit()
  • явним викликом _exit()

Видалення завершеного процесу з таблиці процесів

Після завершення процесу його pid залишається зайнятий - цей стан процесу називається "зомбі". Щоб звільнити pid батьківський процес повинен дочекатися завершення дочірнього та очистити таблицю процесів. Це досягається викликом:

pid_t cpid=waitpid(pid_t pid, int *status, int options) //або pid_t cpid=wait(int *status)

Виклик wait(&status); еквівалентний waitpid(-1, &status, 0);

waitpid чекає завершення дочірнього процесу і повертає його PID. Код завершення та обставини завершення заносяться до змінної status. Додатково поведінкою waitpid можна керувати через параметр options.

  • pid < -1 - очікування завершення дочірнього процесу із групи з pgid==-pid
  • pid == -1 - очікування завершення будь-якого дочірнього процесу
  • pid == 0 - очікування завершення дочірнього процесу із групи, pgid якої збігається з pgid поточного процесу
  • pid > 0 - очікування завершення будь-якого дочірнього процесу із зазначеним pid

Опція WNOHANG - означає неблокуючу перевірку дочірніх процесів, що завершилися.

Статус завершення перевіряється макросами:

  • WIFEXITED(status) - істина якщо дочірній процес завершився викликом _exit(st)
  • WEXITSTATUS(status) - код завершення st передано в _exit(st)
  • WIFSIGNALED(status) - істина якщо дочірній процес завершився за сигналом
  • WTERMSIG(status) - номер сигналу, що завершив
  • WCOREDUMP(status)істина якщо дочірній процес завершився з дампом пам'яті
  • WIFSTOPPED(status) істина якщо дочірній процес зупинено
  • WSTOPSIG(status) - номер сигналу, що зупинив
  • WIFCONTINUED(status) істина якщо дочірній процес перезапущено

Основи планування процесів

Для забезпечення багатозадачності кожен процес користувача періодично переривається, його контекст зберігається, а управління передається іншому процесу. Переривання виконання процесу може відбуватися за таймером або під час обробки системного виклику. Залежно від обставин перерваний процес ставиться в чергу процесів на виконання, до списку процесів, що очікують ресурси (наприклад, очікування введення користувача або завершення виведення на фізичний носій) або до списку зупинених процесів.

Переривання за таймером відбуваються відповідно до кванту часу, виділеного процесу. У Linux квант часу за умовчанням (DEF_TIMESLICE) дорівнює 0,1 секунди, але може бути перерахований планувальником процесів (sheduler).

Системний виклик може завершитися з негайним поверненням в програму користувача, завершитися одночасно з вичерпанням кванта часу або перейти в стан очікування ресурсу .

У момент повернення в програму користувача відбувається доставка сигналів - тобто. виклик процедури оброблювача сигналу, зупинка, перезапуск або завершення процесу. Деякі сигнали (SIGSTOP) - призводять до того, що процес включається до списку зупинених процесів, які не надходять у чергу процесів виконання. Сигнал SIGCONT повертає зупинений процес у чергу процесів виконання, сигнал SIGKILL завершує зупинений процес.

Після завершення процесу викликом _exit() або сигналом всі його ресурси (пам'ять, відкриті файли) звільняються, але запис у таблиці процесів залишається і займає PID. Такий процес називається "зомбі" і має бути явно очищений з таблиці процесів викликом wait() у батьківському процесі. Якщо батьківський процес завершився раніше за дочірні, то всім його дочірнім процесам приписується значення PPID (parent pid) 1, покладаючи зобов'язання з очищення від них таблиці процесів на особливий процес init з PID=1.

На діаграмі показані різні стани процесу

У Linux команда ps використовує такі позначення стану процесу:

  • R виконується (у тому числі в обробнику сигналу) або стоїть у черзі на виконання
  • S системний виклик чекає на ресурс, але може бути перерваний
  • D системний виклик чекає на ресурс, і не може бути перерваний (зазвичай це введення/виведення)
  • T зупинено сигналом
  • t зупинено відладчиком
  • Z "Зомбі" - завершено, але не видалено зі списку процесів батьківським процесом.

Планувальник процесів

Завданням планувальника процесів є вилучення процесів, готових на виконання, відповідно до деяких правил. Планувальник намагається розподілити процесорні ресурси те щоб жоден із процесів не простоював тривалий час, і щоб процеси, які вважаються пріоритетними, отримували процесорний час насамперед. У багатопроцесорних системах бажано, щоб у послідовних квантах часу процес запускався на тому самому процесорі, щоб максимально використовувати процесорний кеш. При цьому сам планувальник повинен виконувати вибір якнайшвидше.

Найпростіша реалізація черги у вигляді FIFO дуже швидка, але не підтримує пріоритети та багатопроцесорності. У Linux 2.6 скористалися простотою FIFO, додавши до неї кілька вдосконалень:

  1. Було визначено 140 пріоритетів (100 реального часу + 40 призначених динамічно), кожен із яких отримав свою чергу FIFO. На запуск вибирається перший процес у пріоритетній черзі.
  2. У багатопроцесорних системах для кожного ядра було сформовано свій набір із 140 черг. Раз на 0,2 секунди проглядаються розміри черг процесорів і, за необхідності балансування, частина процесів переноситься із завантажених ядер менш завантажені
  3. Динамічний пріоритет призначається процесу в залежності від часу очікування ресурсів до часу перебування в стані виконання. Чим довше процес очікував ресурс, тим вищий його пріоритет. Таким чином, діалогові завдання, які 99% часу чекають на введення користувача, завжди мають найвищий пріоритет.

Прикладний програміст може додатково знизити пріоритет процесу функцією int nice (int inc); (в Linux nice() - інтерфейс до виклику setpriority()). Більше значення nice означає менший пріоритет. У командному рядку використовується "запуск" з таким же ім'ям:

Процес Idle

Якщо немає процесів готових до виконання, то планувальник викликає нитку (процес) Idle. У Linux 2.2 однопроцесорна кросплатформова версія Idle виглядала так:

int cpu_idle(void *unused)

В апаратно-залежну реалізацію idle() може бути винесене керування енергозбереженням.

У ранніх версіях Linux процес Idle мав PID=0, але, власне кажучи, Idle як самостійний процес немає.

Обчислення середнього завантаження

Середнє завантаження (Load Average, LA) - усереднений захід використання ресурсів комп'ютера запущеними процесами. Величина LA пропорційна числу процесорів у системі та на ненавантаженій системі коливається від нуля до значення, що дорівнює числу процесорів.Високі значення LA (10 * число ядер і більше) говорять про надмірне навантаження на систему і потенційні проблеми з продуктивністю.

У класичному Unix LA має сенс середньої кількості процесів у черзі виконання + кількості виконуваних процесів за одиницю часу. Тобто. LA == 1 означає, що в системі вважається один процес, LA > 1 визначає скільки процесів не змогли стартувати, оскільки їм не вистачило кванта часу, а LA < 1 означає, що в системі є незавантажені ядра.

У Linux до кількості процесів додали ще й процеси, які чекають на ресурси. Тепер на зростання LA значно впливають проблеми введення/виводу, такі як недостатня пропускна здатність мережі або повільні диски.

LA усереднюється за такою формулою LAt+1=(LAcur+LAt)/2. Де LAt+1 - значення, що відображається в момент t+1, LAcur - поточне виміряне значення, LAt - значення, що відображається в момент t. Таким чином згладжуються піки і після різкого падіння навантаження значення LA повільно знижуватиметься, а короткочасний пік навантаження буде відображений половинною величиною LA.

Видача команди top

Видача команди top у Linux на комп'ютері з 36 ядрами:

top - 19:43:53 4 дні, 5:54, 1 користувач, load average: 34.07, 33.75, 33.80 Tasks: 550 total, 12 running, 538 sleeping, 0 stopped, 0 zombie %Cpu. , 0.5 sy, 0.0 ni, 5.5 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st

На комп'ютері запущено багатопоточне лічильне завдання, яке займає майже всі ядра і не використовує введення/виведення. LA трохи менше 36, що узгоджується з розподілом часу процесора: 93.9 us – користувач, 0.5 sy – ядро, 5.5 id – Idle, 0.0 wa – очікування пристроїв.

Ефективні права процесу

З кожним процесом Unix пов'язані два атрибути uid і gid - Користувач та основна група.У принципі, вони могли б визначати права доступу процесу до ФС та інших процесів, однак існує кілька ситуацій, коли права процесу відрізняються від прав його власника. Тому крім uid/gid (іноді званих реальними ruid/rgid) з процесом пов'язані атрибути прав доступу - ефективні uid/gid - euid/egid, найчастіше збігаються з ruid/rgid. Крім того, з uid пов'язаний список допоміжних груп, описаних у файлі /etc/group . euid/egid та список груп визначають права доступу процесу до ФС. Нові файли успадковують атрибути uid/gid від euid/egid процесу. Крім того euid визначає права доступу до інших процесів (налагодження, надсилання сигналів тощо).

euid рівний нулю використовується для позначення привілейованого процесу, що має особливі права на доступ до ФС та інших процесів, а також на доступ до адміністративних функцій ядра, таким як монтування диска або використання портів TCP з номерами менше 1024. euid=0 завжди має право на читання та запис файлів та каталогів. Право виконання файлів надається привілейованому процесу лише у тому випадку, коли файл виставлений хоча б один атрибут права виконання.

Примітка: у сучасних ОС особливі привілеї процесу визначаються через набір особливих прапорів. capabilities і не обов'язково прив'язані до euid=0.

(re)uid/(re)gid, і навіть допоміжні групи, успадковуються від батьківського процесу під час виклику fork(). При виклику exec() ruid/rgid зберігаються, а euid/egid можуть бути змінені якщо у файлу, що виконується, виставлений прапор зміни власника. Для скриптів прапор зміни власника ігнорується. фактично запускається інтерпретатор, а скрипт передається йому як параметр.У момент входу користувача до системи програма login зчитує файли /etc/passwd і /etc/group необхідні величини та встановлює їх перед завантаженням командного інтерпретатора.

Список допоміжних груп можна вважати масив функцією int getgroups(int size, gid_t list[]). Чи буде при цьому у списку основна група невідома, це залежить від реалізації конкретної ОС. Максимальну кількість допоміжних груп можна отримати так: long ngroups_max = sysconf(_SC_NGROUPS_MAX); або з командного рядка getconf NGROUPS_MAX . У моєму Linux'і максимальна кількість груп – 65536.

Для ініціалізації допоміжних груп у Linux можна скористатися функцією int initgroups(const char *user, gid_t group); ця функція розбирає файл /etc/group, а потім звертається до системного виклику int setgroups(size_t size, const gid_t *list);.

Існують кілька функцій для керування атрибутами uid/gid. Для економії місця далі перераховуються лише функції до роботи з uid. Отримати значення атрибутів можна за допомогою опцій getuid(), geteuid() Встановити значення можна за допомогою
setuid(id); - Встановити ruid і euid в id
seteuid(id); - Встановити euid в id
setreuid(rid,eid); - Встановити ruid і euid в rid і eid. -1 як параметр означає, що значення не змінюється

У Linux, HP-UX та інших ОС додатково підтримуються атрибут збережених прав процесу suid/sgid (Не плутати з однойменними атрибутами файлу). Відповідно є функція для встановлення всіх трьох атрибутів setresuid(rid,eid,sid);

Якщо euid=0 або ruid=0 то ruid і euid можуть змінюватися довільно. Тобто. можна зробити euid<>0 або ruid<>0, а потім повернутися в стан euid=ruid=0. Якщо обидва атрибути не дорівнюють нулю, то можлива лише зміна euid в ruid (відмова від додаткових прав). Програма su отримує euid=0 завдяки відповідному атрибуту файлу та використовує можливості привілейованого процесу для запуску програм від імені довільного користувача (у тому числі root). Веб-сервер apache, навпаки, стартує з ruid=euid=0, але потім відбирає у себе зайві права змінюючи ruid і euid на непривілейовані значення.

Схожі статті

  • У чому сенс цього твору Слово про похід Ігорів
  • У чому сенс війни та миру
  • У чому сенс лайк тайм
  • У чому сенс проповіді Онєгіна
  • У чому сенс повести гранатовий браслет
  • У чому сенс монорейки
  • У чому сенс ефект метелика
  • У чому сенс скульптури
  • Недавні статті

  • Чому взуття скрипить при ходьбі
  • Коли день народження у стрічці
  • Чи можна кішці їсти сіль
  • Варіанти планування ділянки 15 соток прямокутної форми
  • Що означає півмісяця знак
  • Рейсмусовий верстат для чого
  • У якому віці парують свиней
  • У чому полягає принцип нарахування та у яких випадках він застосовується