англійськафранцузькаіспанська

Ad


Значок OnWorks

explain_lca2010 - Інтернет у хмарі

Запустіть expand_lca2010 у безкоштовному хостинг-провайдері OnWorks через Ubuntu Online, Fedora Online, онлайн-емулятор Windows або онлайн-емулятор MAC OS

Це команда explain_lca2010, яку можна запустити у безкоштовного хостинг-провайдера OnWorks за допомогою однієї з наших безкоштовних онлайн-робочих станцій, таких як Ubuntu Online, Fedora Online, онлайн-емулятор Windows або онлайн-емулятор MAC OS

ПРОГРАМА:

ІМ'Я


expand_lca2010 - Носія не знайдено: коли прийшов час припинити спроби читати strerror(3).
розум.

МОТИВАЦІЯ


Ідея libexplain спала мені на думку ще на початку 1980-х. Щоразу, коли системний виклик
повертає помилку, ядро ​​точно знає, що пішло не так... і стискає це в
менше 8 біт неправильно. Простір користувача має доступ до тих самих даних, що й ядро
у просторі користувача має бути можливість визначити, що саме сталося, щоб спровокувати помилку
return і використовуйте це для написання хороших повідомлень про помилки.

Чи може це бути так просто?

помилка повідомлення as тонкість
Хороші повідомлення про помилки – це часто ті «один відсоток» завдань, які скидаються за розкладом
тиск стискає ваш проект. Однак гарне повідомлення про помилку може мати величезний,
непропорційне покращення користувацького досвіду, коли користувач блукає в страху
невідома територія, яку зазвичай не зустрічають. Це непросте завдання.

Як програміст-личинка, автор не бачив проблеми з (повністю точною) помилкою
такі повідомлення:
плаваюче виключення (ядро скинуто)
доки не було вказано на альтернативну непрограмістську інтерпретацію. Але це не те
єдине, що не так із повідомленнями про помилки Unix. Як часто ви бачите такі повідомлення про помилки:
$ ./дурний
не можу відкрити файл
$
На цьому етапі для розробника є два варіанти:

1.
ви можете запустити налагоджувач, наприклад gdb(1), або

2.
ви можете використовувати страйк(1) або ферма(1) зазирнути всередину.

· Пам’ятайте, що ваші користувачі можуть навіть не мати доступу до цих інструментів, не кажучи вже про можливість
використовувати їх. (Пройшло дуже багато часу з тих пір Юнекс початківець означало «лише написав». один
драйвер пристрою».)

У цьому прикладі, однак, використовуючи страйк(1) розкриває
$ страйк -e trace=відкритий ./дурний
open("some/file", O_RDONLY) = -1 ENOENT (Немає такого файлу чи каталогу)
не можу відкрити файл
$
Це значно більше інформації, ніж надає повідомлення про помилку. Як правило,
дурний вихідний код виглядає так
int fd = open("щось/щось", O_RDONLY);
якщо (fd < 0)
{
fprintf(stderr, "неможливо відкрити файл\n");
вихід(1);
}
Користувачеві нічого не повідомляється який файл, а також не повідомляє користувачеві який помилка. Був файл
навіть там? Була проблема з дозволами? Він говорить вам, що намагався відкрити a
файл, але це, ймовірно, випадково.

Візьміть свою паличку-підказку та біжте нею програміста-личинок. Розкажи йому про помилка(3).
Під час наступного використання програми ви побачите інше повідомлення про помилку:
$ ./дурний
відкрити: немає такого файлу чи каталогу
$
Прогрес, але не такий, як ми очікували. Як користувач може вирішити проблему, якщо повідомлення про помилку
не каже йому в чому проблема? Дивлячись на джерело, ми бачимо
int fd = open("щось/щось", O_RDONLY);
якщо (fd < 0)
{
помилка ("відкрито");
вихід(1);
}
Час знову пробігтися з паличкою-підказкою. Цього разу повідомлення про помилку займає один крок
вперед і крок назад:
$ ./дурний
щось/щось: Немає такого файлу або каталогу
$
Тепер ми знаємо файл, який він намагався відкрити, але більше не повідомляємо, що це було відкрити(2)
що не вдалося. У цьому випадку це, ймовірно, не є значущим, але може бути значущим для
інші системні виклики. Це могло бути Creat(2) натомість операція, що передбачає це
потрібні різні дозволи.
const char *ім'я файлу = "щось/щось";
int fd = відкрити (назва файлу, O_RDONLY);
якщо (fd < 0)
{
помилка (назва файлу);
вихід(1);
}
Наведений вище приклад коду, на жаль, також типовий для неличинкових програмістів. час
щоб розповісти нашому учню padawan про strerror(3) системний виклик.
$ ./дурний
відкрити щось/щось: Немає такого файлу або каталогу
$
Це максимізує інформацію, яку можна надати користувачеві. Код виглядає так
це:
const char *ім'я файлу = "щось/щось";
int fd = відкрити (назва файлу, O_RDONLY);
якщо (fd < 0)
{
fprintf(stderr, "відкрити %s: %s\n", ім'я файлу, strerror(errno));
вихід(1);
}
Тепер у нас є системний виклик, ім’я файлу та рядок помилки. Це містить усе
інформація, що страйк(1) надруковано. Це якнайкраще.

Або це?

Недоліки of помилка та strerror
Проблема, яку побачив автор ще у 1980-х роках, полягала в тому, що повідомлення про помилку є неповним.
Чи «немає такого файлу чи каталогу» відноситься до «деякі" або до каталогу "річ” файл у
"деякі” каталог?

Короткий огляд сторінки довідки для strerror(3) говорить:
strerror - повертає рядок, що описує номер помилки
Зверніть увагу: це описує помилку номер, а не помилка.

З іншого боку, ядро знає яка була помилка. Був конкретний момент у
код ядра, спричинений певною умовою, де код ядра розгалужується та каже «ні».
Чи може програма простору користувача визначити конкретну умову та написати кращу помилку
повідомлення?

Однак проблема глибша. Що робити, якщо проблема виникає під час зчитування(2) система
виклик, а не відкрити(2) подзвонити? Це просто для повідомлення про помилку, пов’язаного з
відкрити(2) щоб включити ім’я файлу, воно тут же. Але мати можливість включити назву файлу
в помилку, пов'язану з зчитування(2) системний виклик, ви повинні передати ім'я файлу всім
шлях вниз по стеку викликів, а також дескриптор файлу.

І ось неприємний момент: ядро ​​вже знає назву файлу
дескриптор асоціюється з. Навіщо програмісту передавати всі зайві дані
шлях вниз по стеку викликів лише для покращення повідомлення про помилку, яке може ніколи не видаватися? в
У реальності багато програмістів не турбуються, і повідомлення про помилки, що виникають, є ще гіршими
його.

Але це були 1980-ті роки, на PDP11, з обмеженими ресурсами та без спільних бібліотек. Назад
потім не включено різновиди Unix / proc навіть у рудиментарній формі, і також(1) програма
було більше десяти років. Тому ідею відклали як непрактичну.

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

Дивно, але через 25 років, незважаючи на просту систему дозволів, реалізовано повну
узгодженості, більшість користувачів Unix досі не знають, як розшифрувати «Немає такого файлу чи каталогу»,
або будь-які інші загадкові повідомлення про помилки, які вони бачать щодня. Або, принаймні, загадковий
Ними.

Чи не було б добре, якби техпідтримка першого рівня не потребувала розшифровки повідомлень про помилки?
Чи не було б добре мати повідомлення про помилки, які користувачі могли б зрозуміти, не телефонуючи
технічна підтримка?

Ці дні / proc на Linux більш ніж здатний надати інформацію, необхідну для декодування
переважну більшість повідомлень про помилки та вказують користувачеві на приблизну причину їх виникнення
проблема. На системах з обмеженою / proc впровадження, в також(1) команду можна заповнити
багато прогалин.

У 2008 році потік запитів на переклад траплявся з автором занадто часто. Це було
час переглянути цю ідею 25-річної давнини, і результатом є libexplain.

ВИКОРИСТАННЯ THE БІБЛІОТЕКА


Інтерфейс бібліотеки намагається бути послідовним, де це можливо. Почнемо з
приклад використання strerror(3):
if (rename(old_path, new_path) < 0)
{
fprintf(stderr, "перейменувати %s %s: %s\n", старий_шлях, новий_шлях,
strerror(errno));
вихід(1);
}
Ідея libexplain полягає в тому, щоб забезпечити a strerror(3) еквівалент для кожен системний виклик,
призначений спеціально для цього системного виклику, щоб він міг надати більш детальну інформацію про помилку
повідомлення, що містить велику частину інформації, яку ви бачите під заголовком розділу «ПОМИЛКИ».
2 і 3 людина сторінки, доповнені інформацією про фактичні умови, фактичні аргументи
значення та системні обмеження.

Команда простий випадок
Команда strerror(3) заміна:
if (rename(old_path, new_path) < 0)
{
fprintf(stderr, "%s\n", пояснення_перейменування(старий_шлях, новий_шлях));
вихід(1);
}

Команда Errno випадок
Також можна передати явний неправильно(3) значення, якщо ви спочатку повинні щось зробити
обробка, яка б заважала неправильно, як-от відновлення помилок:
if (rename(old_path, new_path < 0))
{
int old_errno = errno;
...код Що заважає неправильно...
fprintf(stderr, "%s\n", пояснення_errno_rename(old_errno,
старий_шлях, новий_шлях));
вихід(1);
}

Команда Багатопотоковий випадки
Деякі програми є багатопоточними, тому не можуть надавати спільний доступ до внутрішньої частини libexplain
буфер. Ви можете надати власний буфер за допомогою
якщо (роз'єднати (шлях))
{
char повідомлення [3000];
expand_message_unlink(повідомлення, sizeof(повідомлення), шлях);
error_dialog(повідомлення);
return -1;
}
І, для повноти картини, обидва неправильно(3) і потокобезпечний:
ssize_t nbytes = read(fd, data, sizeof(data));
якщо (nбайт < 0)
{
char повідомлення [3000];
int old_errno = errno;
...помилка відновлення...
expand_message_errno_read(повідомлення, sizeof(повідомлення),
old_errno, fd, data, sizeof(data));
error_dialog(повідомлення);
return -1;
}

Це заміни для strerror_r(3), на системах, які його мають.

інтерфейс Цукор
Набір функцій, доданих як функції зручності, щоб залучити програмістів до використання
Бібліотека libexplain виявляється найчастіше використовуваними автором функціями libexplain у
програми командного рядка:
int fd = explain_creat_or_die(назва файлу, 0666);
Ця функція намагається створити новий файл. Якщо це не вдається, він друкує повідомлення про помилку та
виходить із EXIT_FAILURE. Якщо помилки немає, повертається новий файловий дескриптор.

Пов'язана функція:
int fd = explain_creat_on_error(назва файлу, 0666);
надрукує повідомлення про помилку в разі помилки, але також поверне оригінальний результат помилки, і
неправильно(3) також не заважає.

ВСІ інший система дзвінки
Загалом, кожен системний виклик має власний файл включення
#включатиім'я.h>
який визначає прототипи функцій для шести функцій:

· пояснювати_ім'я,

· пояснювати_помилково_ім'я,

· пояснювати_повідомлення_ім'я,

· пояснювати_повідомлення_errno_ім'я,

· пояснювати_ім'я_або_померти і

· пояснювати_ім'я_on_error.

Кожен прототип функції має документацію Doxygen і цю документацію is НЕ позбавити
коли встановлено файли включення.

Команда чекати(2) системний виклик (і друзі) мають деякі додаткові варіанти, які також інтерпретують помилку
бути статусом виходу, який не є EXIT_SUCCESS. Це стосується система(3) і pcclose(3) як
добре.

Покриття включає 221 системний виклик і 547 запитів ioctl. Існує ще багато систем
закликів ще не реалізовано. Системні виклики, які ніколи не повертаються, наприклад вихід(2), відсутні
в бібліотеці, і ніколи не буде. The Exec сімейство системних викликів він має підтримав, бо
вони повертаються, коли є помилка.

Кішка
Ось як могла б виглядати гіпотетична «котяча» програма з повним звітом про помилки,
за допомогою libexplain.
#include
#включати
#включати
Існує одне включення для libexplain, плюс звичайні підозрювані. (Якщо ви хочете зменшити
завантаження препроцесора, ви можете використовувати спеціальний <libexplain/ім'я.h> включає.)
статична порожнеча
процес (ФАЙЛ *fp)
{
для (;;)
{
char буфер[4096];
size_t n = explain_fread_or_die(buffer, 1, sizeof(buffer), fp);
якщо (!n)
break;
пояснювати_fwrite_or_die(буфер, 1, n, stdout);
}
}
Команда процес функція копіює потік файлів у стандартний вихід. Якщо сталася помилка
для читання або запису повідомляється (і шлях буде включено в
помилка) і команда завершується з EXIT_FAILURE. Ми навіть не турбуємося про відстеження
імена шляхів або передавання їх у стек викликів.
Int
main(int argc, char **argv)
{
для (;;)
{
int c = getopt(argc, argv, "o:");
якщо (c == EOF)
break;
перемикач (c)
{
регістр "о":
expand_freopen_or_die(optarg, "w", stdout);
break;
Цікава частина цього коду полягає в тому, що libexplain може повідомляти про помилки включаючи ім'я шляху навіть
якщо Ви НЕ явно повторно відкрити stdout, як це зроблено тут. Ми навіть не хвилюємося
відстеження імені файлу.
за замовчуванням:
fprintf(stderr, "Використання: %ss [ -o ] ...\n",
argv[0]);
повернення EXIT_FAILURE;
}
}
якщо (optind == argc)
процес (stdin);
ще
{
while (optind < argc)
{
ФАЙЛ *fp = explain_fopen_or_die(argv[optind]++, "r");
процес (fp);
пояснювати_fclose_or_die(fp);
}
}
Стандартний вихід буде закрито неявно, але надто пізно для повідомлення про помилку
видано, тому ми робимо це тут, на випадок, якщо буферизований ввід-вивід ще нічого не записав, і
є помилка ENOSPC чи щось таке.
пояснювати_ffflush_or_die(stdout);
повернення EXIT_SUCCESS;
}
Це все. Повний звіт про помилки, чіткий код.

Расті шкала of інтерфейс Добро
Для тих із вас, хто не знайомий із цим, Расті Рассел «Як зробити це важко для неправильного використання?»
сторінка є обов’язковою для прочитання для дизайнерів API.
http://ozlabs.org/~rusty/index.cgi/tech/2008‐03‐30.html

10. Це неможливе до отримати неправильно

Цілі потрібно ставити високі, амбітні, щоб ви не досягли їх і не думали, що досягли
закінчив, коли ви не закінчите.

Бібліотека libexplain виявляє фальшиві покажчики та багато інших фальшивих параметрів системних викликів,
і загалом намагається уникати помилок сегментів навіть у найскладніших обставинах.

Бібліотека libexplain створена для потокової безпеки. Ймовірно, буде більше використання в реальному світі
виявити місця, які можна покращити.

Найбільша проблема полягає в самих назвах функцій. Тому що C не має
простори імен, бібліотека libexplain завжди використовує префікс імені expand_. Це
традиційний спосіб створення простору псевдоімен, щоб уникнути конфліктів символів.
Однак це призводить до деяких імен, що звучать неприродно.

9. Команда компілятор or Компонувальник не буде дозволяти ви отримати it неправильно

Поширеною помилкою є використанняexplain_open там, де планувалосяexplain_open_or_die.
На щастя, на цьому етапі компілятор часто видає помилку типу (наприклад не можу призначити
const char * rvalue до int lvalue).

8. Команда компілятор волі попереджати if ви отримати it неправильно

Якщо expand_rename використовується тоді, коли планувалося expand_rename_or_die, це може спричинити інше
проблеми. GCC має корисний атрибут функції warn_unused_result і libexplain
бібліотека додає його до всіх пояснень_ім'я виклики функцій для створення попередження, коли ви
зробити цю помилку. Поєднайте це з ПКУ - Помилка щоб підвищити це до рівня доброти 9.

7. Команда Очевидний використання is (ймовірно) виправити один.

Назви функцій вибрано так, щоб передати їх значення, але це не завжди
успішний. Поки поясню_ім'я_або_померти і пояснити_ім'я_on_error є досить описовими,
менш використовувані потокобезпечні варіанти важче декодувати. Прототипи функцій допомагають
компілятор для розуміння, а коментарі Doxygen у файлах заголовків допомагають користувачеві
до розуміння.

6. Команда ім'я розповідає ви як до використання його.

Особливо важливо прочитати пояснення_ім'я_or_die як «пояснити (ім'я або померти)".
Використання узгодженого префікса простору імен expand_ має деякі невдалі побічні ефекти в
відділ очевидності, а також.

Порядок слів у іменах також вказує на порядок аргументів. Аргумент
списки завжди кінець з тими самими аргументами, що й передані системному виклику; всі of їх. Якщо
_errno_ з’являється в назві, його аргумент завжди передує аргументам системного виклику. Якщо
_message_ з’являється в назві, його два аргументи завжди стоять першими.

5. Do it право or it волі перерву at час виконання.

Бібліотека libexplain виявляє фальшиві покажчики та багато інших фальшивих параметрів системних викликів,
і загалом намагається уникати помилок сегментів навіть у найскладніших обставинах. Це повинно бути
ніколи не ламається під час виконання, але більше використання в реальному світі, без сумніву, покращить це.

Деякі повідомлення про помилки спрямовані на розробників і супроводжувачів, а не на кінцевих користувачів, як це
може допомогти з вирішенням помилок. Не стільки «перерва під час виконання», скільки «бути інформативним під час
час виконання» (після системного виклику barfs).

4. слідувати загальний угоду та ти будеш отримати it право.

Оскільки C не має простору імен, бібліотека libexplain завжди використовує пояснює_ ім’я
префікс. Це традиційний спосіб створення простору псевдоімен, щоб уникнути
символічні конфлікти.

Кінцеві аргументи всіх викликів libexplain ідентичні системним викликам they
описують. Це має на меті забезпечити узгоджену конвенцію, спільну з
самі системні виклики.

3. Читати документація та ти будеш отримати it право.

Бібліотека libexplain прагне мати повну документацію Doxygen для кожного
публічний виклик API (і внутрішній також).

З ЗМІСТ


Робота над libexplain схожа на те, щоб дивитися на дно вашого автомобіля, коли він увімкнений
підйомник у механіка. Там є якісь гидкі речі, а також бруд і бруд, і
користувачі рідко бачать це. Гарне повідомлення про помилку має бути інформативним навіть для користувача, який
пощастило не дивитися на нижню сторону дуже часто, а також
інформативна для механіка, який слухає опис користувача по телефону. Це
непросте завдання.

Повертаючись до нашого першого прикладу, код буде таким, якщо він використовує libexplain:
int fd = expand_open_or_die("щось/що", O_RDONLY, 0);
завершиться помилкою з таким повідомленням про помилку
open(pathname = "some/file", flags = O_RDONLY) не вдалося, такого файлу чи каталогу немає
(2, ENOENT), оскільки в поточному каталозі немає "деякого" каталогу
Це розпадається на три частини
системний виклик не вдалося, системна помилка оскільки
пояснення

Перед тим як Тому що
Можна побачити частину повідомлення перед «тому що» як надто технічну для не‐
технічних користувачів, здебільшого в результаті точного друку самого системного виклику на
початок повідомлення про помилку. І виглядає як страйк(1) вихід, для бонусного гіка
пунктів.
open(pathname = "some/file", flags = O_RDONLY) не вдалося, такого файлу чи каталогу немає
(2, ENOENT)
Ця частина повідомлення про помилку важлива для розробника, коли він пише код,
і не менш важливий для супроводжуючого, який має читати звіти про помилки та виправляти помилки в
код. Там точно сказано, що не вдалося.

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

Часто використовується технічний персонал страйк(1) або ферма(1), щоб отримати цю точну інформацію, але
цей напрямок не відкривається під час читання звітів про помилки. Система повідомлення про помилки далеко
далеко, і тепер у зовсім іншому стані. Таким чином, ця інформація повинна бути в
звіт про помилку, що означає, що він має бути в повідомленні про помилку.

Представлення системного виклику також надає контекст решті повідомлення. Якщо потрібно
виникає, аргумент системного виклику, що викликає порушення, може бути названий у поясненні
після «тому що». Крім того, усі рядки повністю взяті в лапки та екрановані рядки C, отже
вбудовані символи нового рядка та недруковані символи не спричинять закриття терміналу користувача
сіна.

Команда системна помилка це те, що виходить з strerror(2), плюс символ помилки. Нетерплячий і
Експерти-сисадміни можуть припинити читання на цьому етапі, але досвід автора на сьогоднішній день є
що читати далі приносить користь. (Якщо це не корисно, це, ймовірно, область
libexplain, який можна покращити. Внески коду, звичайно, вітаються.)

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

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

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

Наведений вище кваліфікатор «більшість» стосується того факту, що підтвердження концепції
реалізація не включала підтримку інтернаціоналізації. Розробляється кодова база
переглядається поступово, як правило, в результаті рефакторингу повідомлень, щоб кожна помилка
рядок повідомлення з'являється в коді рівно один раз.

Було створено умови для мов, які повинні зібрати частини
системний виклик не вдалося, системна помилка оскільки пояснення
у різних порядку для правильної граматики в локалізованих повідомленнях про помилки.

Посмертний випадок
Бувають випадки, коли програма ще не використовує libexplain, а ви не можете використовувати страйк(1)
або. Є пояснювати(1) команда, включена до libexplain, яку можна використовувати для
розшифрувати повідомлення про помилки, якщо стан основної системи не змінився надто сильно.
$ пояснювати перейменувати Foo /tmp/bar/baz -e ЕНОЕНТ
rename(oldpath = "foo", newpath = "/tmp/bar/baz") не вдалося, такого файлу чи каталогу немає
(2, ENOENT), оскільки в newpath немає каталогу "bar"/ Tmp"каталог
$
Зверніть увагу, як неоднозначність шляху вирішується за допомогою імені аргументу системного виклику. з
Звичайно, ви повинні знати помилку та системний виклик пояснювати(1) бути корисним. Як ан
Крім того, це один із способів перевірити це автоматичним набором тестів libexplain
libexplain працює.

філософія
«Розкажи мені все, включно з тим, що я не знав, що шукати».

Бібліотека реалізована таким чином, що при статичному зв’язуванні лише код ви
фактичне використання буде пов’язано. Це досягається завдяки наявності однієї функції на вихідний файл,
коли це можливо.

Якщо буде можливість надати більше інформації, libexplain зробить це. Чим менше користувача
має відстежити для себе, тим краще. Це означає, що UID супроводжуються
ім’я користувача, GID супроводжуються назвою групи, PID супроводжуються процесом
ім'я, дескриптори файлів і потоки супроводжуються іменем шляху, і т.д..

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

Бібліотека libexplain намагається використовувати якомога менше купи, і зазвичай її немає. Це
щоб уникнути порушення стану процесу, наскільки це можливо, хоча іноді це так і є
неминучий.

Бібліотека libexplain намагається бути потоково безпечною, уникаючи глобальних змінних, зберігаючи
стан на стеку якомога більше. Є єдиний загальний буфер повідомлень і
функції, які його використовують, задокументовані як небезпечні для потоків.

Бібліотека libexplain не заважає обробникам сигналів процесу. Це робить
визначення того, чи буде вказівник segfault виклик, але не неможливо.

Якщо інформація доступна як через системний виклик, так і через a / proc
запису, перевага надається системному виклику. Це робиться для того, щоб уникнути порушення стану процесу.
Бувають випадки, коли файлові дескриптори недоступні.

Бібліотека libexplain скомпільована з підтримкою великих файлів. Немає великих/малих
шизофренія. Там, де це впливає на типи аргументів в API, видається помилка
якщо необхідні визначення великого файлу відсутні.

FIXME: потрібна робота, щоб переконатися, що квоти файлової системи обробляються в коді. Це
стосується деяких getrlimit(2) також межі.

Бувають випадки, коли шляхи родичів неінформативні. Наприклад: системні демони,
сервери та фонові процеси. У цих випадках у помилці використовуються абсолютні шляхи
пояснення.

PATH РЕЗОЛЮЦІЯ


Скорочена версія: див path_resolution(7).

Довга версія: більшість користувачів ніколи не чули path_resolution(7) і багато досвідчених користувачів
ніколи не читав. Ось анотована версія:

Крок 1: Start of дозвіл процес
Якщо ім’я шляху починається з скісної риски (“/”), це початковий каталог пошуку
кореневий каталог викликаного процесу.

Якщо ім’я шляху не починається з косої риски (“/”), початковий пошук
каталог процесу вирішення — це поточний робочий каталог процесу.

Крок 2: Ходити по шлях
Установіть поточний каталог пошуку на початковий каталог пошуку. Тепер для кожного не-
кінцевий компонент шляху, де компонент є підрядком, розділеним скісною рискою (“/”)
символів, цей компонент шукається в поточному каталозі пошуку.

Якщо процес не має дозволу на пошук у поточному каталозі пошуку, EACCES
повертається помилка ("Дозвіл заборонено").
open(pathname = "/home/archives/.ssh/private_key", flags = O_RDONLY) не вдалося,
У дозволі відмовлено (13, EACCES), оскільки процес не має дозволу на пошук
до каталогу "/home/archives/.ssh", ефективний GID процесу 1000
"pmiller" не відповідає власнику каталогу 1001 "archives", тому власник
режим дозволу "rwx" ігнорується, інші режими дозволу "---", і
процес не є привілейованим (не має можливості DAC_READ_SEARCH)

Якщо компонент не знайдено, повертається помилка ENOENT («Немає такого файлу чи каталогу»).
unlink(pathname = "/home/microsoft/rubbish") не вдалося, такого файлу чи каталогу немає (2,
ENOENT), оскільки в імені шляху немає каталогу "microsoft"/ Головна"каталог

Існує також певна підтримка для користувачів, коли вони неправильно вводять шляхи, і вносяться пропозиції
ENOENT повертається:
open(pathname = "/user/include/fcntl.h", flags = O_RDONLY) не вдалося, немає такого файлу або
каталог (2, ENOENT), оскільки в шляху "/" немає каталогу "користувач"
Ви мали на увазі каталог "usr"?

Якщо компонент знайдено, але не є ні каталогом, ні символічним посиланням, ENOTDIR
повертається помилка ("Не каталог").
open(pathname = "/home/pmiller/.netrc/lca", flags = O_RDONLY) не вдалося, не
каталог (20, ENOTDIR), оскільки звичайний файл ".netrc" у імені шляху
Каталог "/home/pmiller" використовується як каталог, коли це не так

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

Якщо компонент знайдено і є символічним посиланням (символом), ми спочатку розв’язуємо цей символ
посилання (з поточним каталогом пошуку як початковим каталогом пошуку). Після помилки, що
повертається помилка. Якщо результат не є каталогом, повертається помилка ENOTDIR.
unlink(pathname = "/tmp/dangling/rubbish") не вдалося, такого файлу чи каталогу немає (2,
ENOENT), оскільки «висяче» символічне посилання в імені шляху "/ Tmp"каталог
відноситься до «ніде», якого не існує
Якщо дозвіл символічного посилання успішний і повертає каталог, ми встановлюємо поточний
знайти каталог у цей каталог і перейти до наступного компонента. Зверніть увагу, що
процес вирішення тут передбачає рекурсію. Щоб захистити ядро ​​від стека
переповнення, а також для захисту від відмови в обслуговуванні існують обмеження на максимум
глибину рекурсії та максимальну кількість символьних посилань. Помилка ELOOP
повертається, коли перевищено максимум («Забагато рівнів символічних посилань»).
open(pathname = "/tmp/dangling", flags = O_RDONLY) не вдалося, забагато рівнів
символічні посилання (40, ELOOP), оскільки в. виявлено цикл символічних посилань
шлях, починаючи з "/tmp/dangling"
Також можна отримати помилку ELOOP або EMLINK, якщо символічних посилань забагато, але ні
виявлено петлю.
open(pathname = "/tmp/rabbit‐hole", flags = O_RDONLY) не вдалося, забагато рівнів
символічні посилання (40, ELOOP), оскільки в. виявлено забагато символічних посилань
шлях (8)
Зверніть увагу, що фактичний ліміт також друкується.

Крок 3: знайти остаточний запис
Пошук кінцевого компонента імені шляху відбувається так само, як і всіх інших
компоненти, як описано в попередньому кроці, з двома відмінностями:

(i) Кінцевий компонент не обов’язково повинен бути каталогом (принаймні, що стосується роздільної здатності шляху
процес стурбований. Це може бути каталог або не каталог, через
вимоги конкретного системного виклику).

(II)
Це не обов'язково помилка, якщо остаточний компонент не знайдено; можливо ми просто
створення його. Подробиці щодо обробки остаточного запису описано в
сторінки довідки конкретних системних викликів.

(Iii)
Також можлива проблема з останнім компонентом, якщо це символічне посилання
і його не слід дотримуватися. Наприклад, використовуючи відкрити(2) Прапор O_NOFOLLOW:
open(pathname = "a-symlink", flags = O_RDONLY | O_NOFOLLOW) не вдалося, забагато рівнів
символічні посилання (ELOOP), оскільки було вказано O_NOFOLLOW, але ім’я шляху посилається на a
символічне посилання

(Iv)
Користувачі часто помиляються під час введення шляхів. Бібліотека libexplain
спроби зробити пропозиції, коли повертається ENOENT, наприклад:
open(pathname = "/usr/include/filecontrl.h", flags = O_RDONLY) не вдалося, такого файлу немає або
каталог (2, ENOENT), оскільки в імені шляху немає звичайного файлу "filecontrl.h"
"/ usr / include", ви мали на увазі звичайний файл "fcntl.h"?

(v) Також можливо, що кінцевий компонент повинен бути чимось іншим, ніж a
звичайний файл:
readlink(pathname = "just-a-file", data = 0x7F930A50, data_size = 4097) не вдалося,
Недійсний аргумент (22, EINVAL), оскільки шлях – це звичайний файл, а не символічне посилання

(Vi)
FIXME: обробка біта "t".

рамки
Існує ряд обмежень щодо шляхів і імен файлів.

Обмеження довжини шляху
Існує максимальна довжина імен шляхів. Якщо шлях (або якийсь проміжний
шлях, отриманий під час вирішення символічних посилань) задовгий, ENAMETOOLONG
повертається помилка («Назва файлу задовга»). Зверніть увагу, як включено системне обмеження
у повідомленні про помилку.
відкрити (шлях = "дуже довго", flags = O_RDONLY) не вдалося, назва файлу задовга (36,
ENAMETOOLONG), оскільки шлях перевищує максимальну довжину системного шляху (4096)

Обмеження довжини імені файлу
Деякі варіанти Unix мають обмеження на кількість байтів у кожному компоненті шляху.
Деякі з них справляються з цим мовчки, а деякі дають ENAMETOOLONG; libeexplain
користування бібліотекою pathconf(3) _PC_NO_TRUNC, щоб визначити який. Якщо ця помилка трапляється, то
Бібліотека libexplain вкаже обмеження у повідомленні про помилку, обмеження є
отриманий від pathconf(3) _PC_NAME_MAX. Зверніть увагу, як включено системне обмеження
у повідомленні про помилку.
відкрити (шлях = "system7/only-had-14-characters", flags = O_RDONLY) не вдалося, файл
надто довга назва (36, ENAMETOOLONG), оскільки компонент "only-had-14-characters" є
довше системного ліміту (14)

Порожній шлях
В оригінальному Unix порожній шлях посилався на поточний каталог.
У наш час POSIX постановляє, що порожнє ім’я шляху не повинно бути успішно розв’язане.
open(pathname = "", flags = O_RDONLY) не вдалося, такого файлу чи каталогу немає (2,
ENOENT), тому що POSIX постановляє, що порожнє ім’я шляху не повинно бути дозволено
успішно

Дозволи
Біти дозволу файлу складаються з трьох груп по три біти. Перша група
three використовується, коли ефективний ідентифікатор користувача процесу, що викликає, дорівнює ідентифікатору власника процесу
файл. Друга група з трьох використовується, коли ідентифікатор групи файлу дорівнює
ефективний ідентифікатор групи процесу виклику або є одним із додаткових ідентифікаторів групи
процес виклику. Якщо жодне з них не виконується, використовується третя група.
відкрити (шлях = "/ etc / passwd", flags = O_WRONLY) не вдалося, у дозволі відмовлено (13,
EACCES), оскільки процес не має дозволу на запис у звичайний "passwd".
файл у шляху "/ Etc" каталог, ефективний UID процесу 1000 "pmiller"
не відповідає звичайному власнику файлу 0 "root", тому режим дозволу власника "rw-"
ігнорується, іншим режимом дозволу є "r--", і процес не є привілейованим
(не має можливості DAC_OVERRIDE)
Цьому поясненню приділено чимало місця, оскільки більшість користувачів не знають про це
ось як працює система дозволів. Зокрема: власник, група та інше
дозволи є ексклюзивними, вони не об’єднуються «АБО».

СИЛЬНА І ІНТЕРЕСОВАНО SYSTEM ВИКЛИКИ


Процес написання конкретного обробника помилок для кожного системного виклику часто виявляє
цікаві примхи та граничні умови, або незрозумілі неправильно(3) значення.

ЕНОМЕДІЙ, Немає середа знайдений
Акт копіювання компакт-диска був джерелом назви для цієї статті.
$ dd if=/dev/cdrom of=fubar.iso
dd: відкриття “/dev/cdrom”: носій не знайдено
$
Автор дивувався, чому його комп’ютер говорить йому, що екстрасенса не існує
середній. Не дивлячись на той факт, що величезна кількість носіїв англійської мови не є рідною
навіть знаючи, що «медіа» — це множина, не кажучи вже про те, що «медіум» — це однина, рядок
повернуто до strerror(3) для ENOMEDIUM настільки стислий, що його майже повністю немає
зміст.

Коли відкрити(2) повертає ENOMEDIUM, було б добре, якби бібліотека libexplain могла розширити a
трохи про це, виходячи з типу приводу. Наприклад:
... тому що в дисководі немає диска
... тому що в приводі компакт-дисків немає диска
... тому що в накопичувачі немає стрічки
... тому що в картрідері немає карти пам'яті

Так і сталося...
open(pathname = "/dev/cdrom", flags = O_RDONLY) не вдалося, носій не знайдено (123,
ENOMEDIUM), оскільки в дисководі компакт-дисків немає диска
Фокус, про який автор раніше не знав, полягав у тому, щоб відкрити пристрій за допомогою
Прапор O_NONBLOCK, який дозволить вам відкрити диск без носія. Тоді ти
проблема конкретного пристрою йоктл(2) запити, поки ви не зрозумієте, що це таке. (Ні
впевнений, що це POSIX, але, здається, він також працює таким чином у BSD та Solaris
водим(1) джерела.)

Зверніть також увагу на різне використання «диск» і «диск» у контексті. Виник стандарт CD
у Франції, але все інше має «к».

ПОМИЛКА, поганий адреса
Будь-який системний виклик, який приймає аргумент покажчика, може повернути EFAULT. Бібліотека libexplain
може визначити, який аргумент є помилковим, і робить це, не заважаючи процесу
(або потоку) обробки сигналів.

Якщо доступний, то mincore(2) використовується системний виклик, щоб запитати, чи дійсна область пам’яті.
Він може повернути три результати: зіставлений, але не у фізичній пам’яті, зіставлений і у фізичній пам’яті
пам'яті, а не відображено. Під час тестування валідності вказівника перші два «так»
і останнє «ні».

Перевірити рядки C складніше, тому що замість вказівника та розміру ми лише
мати покажчик. Щоб визначити розмір, нам потрібно було б знайти NUL, і це могло б бути
segfault, catch-22.

Щоб вирішити цю проблему, бібліотека libexplain використовує lstat(2) системний виклик (з відомим
хороший другий аргумент), щоб перевірити рядки C на дійсність. Помилка повернення && errno == EFAULT
це «ні», а все інше — «так». Це, звичайно, обмежує рядки PATH_MAX
символів, але зазвичай це не проблема для бібліотеки libexplain, тому що це
майже завжди найдовші рядки, які його цікавлять.

EMFILE, Занадто багато відкрити файли
Ця помилка виникає, коли процес уже має максимальну кількість відкритих дескрипторів файлів.
Якщо фактичний ліміт потрібно надрукувати, а бібліотека libexplain намагається це зробити, ви не зможете відкрити
файл в / proc прочитати, що це таке.
open_max = sysconf(_SC_OPEN_MAX);
Це не так складно, є sysconf(3) спосіб отримання межі.

ENFILE, Занадто багато відкрити файли in система
Ця помилка виникає, коли системне обмеження на загальну кількість відкритих файлів було досягнуто
досягнуто. У цьому випадку це не зручно sysconf(3) спосіб отримання межі.

Копаючи глибше, можна виявити, що в Linux існує a / proc запис, який ми могли прочитати
отримати це значення. Перешкода 22: закінчилися дескриптори файлів, тому ми не можемо відкрити файл
читайте ліміт.

У Linux існує системний виклик для його отримання, але він не має функції обгортки [e]glibc, тому
Ви повинні все це робити дуже обережно:
довго
expand_maxfile(void)
{
#ifdef __linux__
struct __sysctl_args аргументи;
int32_t maxfile;
size_t maxfile_size = sizeof(максимальний файл);
int name[] = { CTL_FS, FS_MAXFILE };
memset(&args, 0, sizeof(struct __sysctl_args));
args.name = ім'я;
args.nlen = 2;
args.oldval = &maxfile;
args.oldlenp = &maxfile_size;
if (syscall(SYS__sysctl, &args) >= 0)
повернути максимальний файл;
#endif
return -1;
}
Це дозволяє включити обмеження в повідомлення про помилку, якщо воно доступне.

EINVAL «Недійсний аргумент" vs ENOSYS «Функція НЕ реалізовано»
Непідтримувані дії (наприклад симпосилання(2) у файловій системі FAT) не повідомляється
послідовно від одного системного виклику до іншого. Можна мати EINVAL або
ENOSYS повернувся.

Тому слід звернути увагу на ці випадки помилок, щоб виправити їх, зокрема
оскільки EINVAL також може стосуватися проблем з одним або кількома аргументами системного виклику.

примітки Що неправильно(3) is НЕ завжди комплект
Бувають випадки, коли необхідно прочитати джерела [e]glibc, щоб визначити, як і
коли повертаються помилки для деяких системних викликів.

feof(3) fileno(3)
Часто вважається, що ці функції не можуть повертати помилку. Це вірно лише в тому випадку, якщо
потік аргумент дійсний, однак вони здатні виявити недійсний
вказівник.

fpathconf(3) pathconf(3)
Повернене значення fpathconf(2) і pathconf(2) законно може бути -1, так воно і є
необхідно побачити, чи неправильно(3) встановлено явно.

йоктл(2)
Повернене значення йоктл(2) законно може бути -1, тому необхідно перевірити, чи це
неправильно(3) встановлено явно.

readdir(3)
Повернене значення readdir(3) має значення NULL як для помилок, так і для кінця файлу. Це є
необхідно побачити, чи неправильно(3) встановлено явно.

setbuf(3) setbuffer(3) setlinebuf(3) setvbuf(3)
Усі ці функції, крім останньої, повертають значення void. І setvbuf(3) задокументовано лише як
повертає значення «не нуль» у разі помилки. Треба подивитися чи неправильно(3) було вказано явно
встановлений.

strtod(3) strtol(3) strtold(3) strtoll(3) strtoul(3) strtoull(3)
Ці функції повертають 0 у разі помилки, але це також є законним повертаним значенням. Це є
необхідно побачити, чи неправильно(3) встановлено явно.

ungetc(3)
Хоча стандарт ANSI C передбачає лише один символ резервного копіювання, він повертається
що [e]glibc дозволяє більше... але це означає, що він може вийти з ладу з ENOMEM. Це може
також не працює з EBADF, якщо fp є підробкою. Найважче, якщо ви передаєте помилку EOF
повернення відбувається, але errno не встановлено.

Бібліотека libexplain правильно виявляє всі ці помилки, навіть у випадках, коли
значення помилок погано задокументовані, якщо взагалі є.

ENOSPC, Немає простір залишити on пристрій
Якщо ця помилка стосується файлу у файловій системі, бібліотека libexplain друкує монтування
точку файлової системи з проблемою. Це може зробити джерело помилки значною мірою
чіткіше.
write(fildes = 1 "example", data = 0xbfff2340, data_size = 5) не вдалося, місця не залишилося
на пристрої (28, ENOSPC), оскільки файлова система, що містить файли ("/ Головна") не має
більше місця для даних
Оскільки додається додаткова підтримка спеціальних пристроїв, очікується, що повідомлення про помилки включатимуть пристрій
назва та фактичний розмір пристрою.

EROFS, Лише для читання файл система
Якщо ця помилка стосується файлу у файловій системі, бібліотека libexplain друкує монтування
точку файлової системи з проблемою. Це може зробити джерело помилки значною мірою
чіткіше.

Оскільки додається додаткова підтримка спеціальних пристроїв, очікується, що повідомлення про помилки включатимуть пристрій
назву та тип.
відкрити (шлях = "/dev/fd0", O_RDWR, 0666) не вдалося, файлова система лише для читання (30, EROFS)
тому що дискета має вкладку захисту від запису

...оскільки компакт-диск не можна записувати
...оскільки на карті пам'яті є вкладка захисту від запису
...оскільки ½-дюймова магнітна стрічка не має кільця для запису

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

Однак існують обмеження: ви можете перейменувати каталог лише поверх іншого
каталог, якщо каталог призначення не порожній.
rename(oldpath = "foo", newpath = "bar") не вдалося, каталог не пустий (39,
ENOTEMPTY), оскільки newpath не є порожнім каталогом; тобто містить записи
окрім "." і ".."
Ви також не можете перейменувати каталог поверх іншого каталогу.
rename(oldpath = "foo", newpath = "bar") не вдалося, не каталог (20, ENOTDIR)
оскільки oldpath — це каталог, а newpath — звичайний файл, а не каталог
Також не допускається зворотне
rename(oldpath = "foo", newpath = "bar") не вдалося, це каталог (21, EISDIR)
тому що newpath є каталогом, але oldpath є звичайним файлом, а не каталогом

Це, звичайно, ускладнює роботу бібліотеки libexplain, оскільки
unlink(2) або rmdir(2) системний виклик викликається неявно перейменувати(2), і тому всі
unlink(2) або rmdir(2) помилки також повинні бути виявлені та оброблені.

dup2
Команда dup2(2) системний виклик використовується для створення другого файлового дескриптора, який посилається на
той самий об’єкт, що й перший файловий дескриптор. Зазвичай це використовується для реалізації введення в оболонку
і перенаправлення виводу.

Найцікавіше те, що так само перейменувати(2) може атомарно перейменувати файл поверх
існуючий файл і видалити старий файл, dup2(2) може зробити це у вже відкритому файлі
дескриптор.

Знову ж таки, це ускладнює роботу бібліотеки libexplain, оскільки близько(2)
системний виклик викликається неявно dup2(2), і так все близько(2) повинні бути помилки
виявлені та оброблені, а також.

ПРИГОДИ IN IOCTL ПІДТРИМКА


Команда йоктл(2) системний виклик надає авторам драйверів пристроїв спосіб спілкування
простір користувача, який не вписується в існуючий API ядра. Побачити ioctl_list(2).

Декодування Запит Номери
З побіжного погляду на йоктл(2) інтерфейс, здавалося б, великий, але кінцевий
кількість можливих йоктл(2) запити. Кожен різний йоктл(2) запит діє
інший системний виклик, але без будь-якої безпеки типів взагалі - компілятор не може допомогти a
програміст зрозуміє це правильно. Ймовірно, це була мотивація tcflush(3) і
друзі

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

Глибший погляд показує, що існує ряд «приватних» номерів запитів і пристроїв
Авторам драйверів рекомендується використовувати їх. Це означає, що існує набагато більше можливого
набір запитів із неоднозначними номерами запитів, які відразу видно. Крім того,
є також деякі історичні неясності.

Ми вже знали, що перемикач непрактичний, але тепер ми знаємо, що вибрати
відповідну назву запиту та пояснення, ми повинні враховувати не лише номер запиту, але
також дескриптор файлу.

Впровадження йоктл(2) підтримка в бібліотеці libexplain полягає в наявності таблиці
покажчики на йоктл(2) дескриптори запиту. Кожен із цих дескрипторів містить необов’язковий
покажчик на функцію усунення неоднозначності.

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

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

Команда йоктл(2) прототип виглядає так:
int ioctl(int fildes, int запит, ...);
які мають спрацьовувати ваші сигнали безпеки типу. Всередині [e]glibc, це повернуто
в різноманітних формах:
int __ioctl(int fildes, int запит, довгий аргумент);
int __ioctl(int fildes, int запит, void *arg);
і інтерфейс системного виклику ядра Linux очікує
asmlinkage long sys_ioctl(unsigned int fildes, unsigned int запит, unsigned long
arg);
Надзвичайна варіативність третього аргументу є проблемою, коли бібліотека libexplain
намагається надрукувати представлення цього третього аргументу. Правда, колись номер запиту
було усунено, кожен запис у таблиці ioctl бібліотеки libexplain має
призначена для користувача функція print_data (ОО виконується вручну).

Пояснення
Виникає менше проблем із визначенням пояснення, яке слід використовувати. Один раз номер запиту
було усунено, кожен запис у таблиці ioctl бібліотеки libexplain має настроюваний
функція print_explanation (знову ж таки, OO виконується вручну).

На відміну від системних викликів розділу 2 і розділу 3, більшість йоктл(2) запити не містять помилок
задокументовано. Це означає, що для хорошого опису помилок необхідно прочитати ядро
джерела для відкриття

· що неправильно(3) значення можуть повертатися, і

· причину кожної помилки.

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

EINVAL vs ENOTTY
Ситуація ще гірша для йоктл(2) запити, ніж для системних викликів, з EINVAL і
ENOTTY обидва використовуються для позначення того, що an йоктл(2) запит є недоречним у цьому
контексті, а іноді ENOSYS, ENOTSUP і EOPNOTSUPP (призначені для використання для сокетів) як
Ну. У вихідних кодах ядра Linux є коментарі, які, здається, вказують на прогресивність
триває очищення. Для додаткового хаосу BSD додає ENOIOCTL для плутанини.

Тому слід звернути увагу на ці випадки помилок, щоб виправити їх, зокрема
оскільки EINVAL також може стосуватися проблем з одним або кількома аргументами системного виклику.

intptr_t
Стандарт C99 визначає цілочисельний тип, який гарантовано може утримувати будь-який покажчик
без репрезентативних втрат.

Наведений вище прототип системного виклику функції було б краще написано
long sys_ioctl(unsigned int fildes, unsigned int запит, intptr_t arg);
Проблема полягає в когнітивному дисонансі, спричиненому специфікою пристрою чи файлової системи
йоктл(2) реалізації, такі як:
long vfs_ioctl(структурний файл *filp, unsigned int cmd, unsigned long arg);
Більшість йоктл(2) запити насправді мають третій аргумент int *arg. Але мати його
оголошений long призводить до коду, який розглядає це як long *arg. Це нешкідливо для 32-біт
(sizeof(long) == sizeof(int)), але погано на 64-бітах (sizeof(long) != sizeof(int)).
Залежно від порядку байтів, ви отримуєте чи ні те значення, яке очікуєте, але ви завжди отримати
каракулі пам'яті або каракулі стека також.

Записуючи все це як
int ioctl(int fildes, int запит, ...);
int __ioctl(int fildes, int запит, intptr_t arg);
long sys_ioctl(unsigned int fildes, unsigned int запит, intptr_t arg);
long vfs_ioctl(структурний файл *filp, unsigned int cmd, intptr_t arg);
наголошує, що ціле число є лише цілим числом, яке представляє кількість, яка є майже
завжди непов'язаний тип покажчика.

ВИСНОВОК


Використовуйте libexplain, вашим користувачам це сподобається.

АВТОРСЬКЕ


libexplain версія 1.4
Авторські права (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Пітер Міллер

Використовуйте explain_lca2010 онлайн за допомогою сервісів onworks.net


Безкоштовні сервери та робочі станції

Завантажте програми для Windows і Linux

  • 1
    ЛАГІТ
    ЛАГІТ
    SWIG – це інструмент розробки програмного забезпечення
    що з'єднує програми, написані на C і
    C++ з різноманітними високорівневими
    мови програмування. SWIG використовується з
    інший...
    Завантажити SWIG
  • 2
    Тема WooCommerce Nextjs React
    Тема WooCommerce Nextjs React
    Тема React WooCommerce, створена за допомогою
    Next JS, Webpack, Babel, Node і
    Express, використовуючи GraphQL і Apollo
    Клієнт. Магазин WooCommerce в React(
    містить: Продукти...
    Завантажте тему WooCommerce Nextjs React
  • 3
    archlabs_repo
    archlabs_repo
    Сховище пакетів для ArchLabs Це
    додаток, який також можна отримати
    від
    https://sourceforge.net/projects/archlabs-repo/.
    Його розміщено в OnWorks у...
    Завантажити archlabs_repo
  • 4
    Проект Зефір
    Проект Зефір
    Проект Zephyr – це нове покоління
    операційна система реального часу (RTOS).
    підтримує декілька апаратних засобів
    архітектури. Він заснований на а
    ядро малої площі...
    Завантажити Zephyr Project
  • 5
    SCONS
    SCONS
    SCons - це інструмент для створення програмного забезпечення
    що є кращою альтернативою
    класичний інструмент "Make" для створення
    ми всі знаємо і любимо. SCons є
    впроваджено...
    Завантажити SCons
  • 6
    PSeInt
    PSeInt
    PSeInt - це інтерпретатор псевдокоду для
    іспаномовні студенти програмування.
    Його головне призначення – бути інструментом для
    навчання та розуміння основ
    концепція...
    Завантажити PSeInt
  • Детальніше »

Команди Linux

  • 1
    7z
    7z
    7z - файловий архіватор з найвищими
    ступінь стиснення...
    Запустіть 7z
  • 2
    7за
    7за
    7za - файловий архіватор з найвищими
    ступінь стиснення...
    Виконати 7za
  • 3
    плазуни
    плазуни
    CREEPY - інформація про геолокацію
    агрегатор ОПИС: creepy is an
    додаток, що дозволяє збирати
    інформація про геолокацію
    користувачі з...
    Біг моторошно
  • 4
    cricket-compile
    cricket-compile
    cricket - програма для керування
    збір і відображення часових рядів
    дані ...
    Запустіть cricket-compile
  • 5
    g-wrap-config
    g-wrap-config
    g-wrap-config - скрипт для отримання
    інформація про встановлену версію
    G-Wrap ...
    Запустіть g-wrap-config
  • 6
    g.accessgrass
    g.accessgrass
    g.access – контролює доступ до
    поточний набір карт для інших користувачів на
    система. Якщо опції немає, друкує
    поточний стан. КЛЮЧОВІ СЛОВА: загальне, карта
    управління, п...
    Запустіть g.accessgrass
  • Детальніше »

Ad