Angielskifrancuskihiszpański

Ad


Ulubiona usługa OnWorks

Wyjaśnij_lca2010 - Online w chmurze

Uruchom wyjaśnienie_lca2010 w bezpłatnym dostawcy hostingu OnWorks w systemie Ubuntu Online, Fedora Online, emulatorze online systemu Windows lub emulatorze online systemu MAC OS

To jest polecenie wyjaśniające_lca2010, które można uruchomić u dostawcy bezpłatnego hostingu OnWorks przy użyciu jednej z naszych wielu bezpłatnych stacji roboczych online, takich jak Ubuntu Online, Fedora Online, emulator online systemu Windows lub emulator online systemu MAC OS

PROGRAM:

IMIĘ


wyjaśnij_lca2010 - Nie znaleziono nośnika: kiedy nadszedł czas, aby przestać próbować czytać strrrr(3)
umysł.

MOTYWACJA


Pomysł libexplain przyszedł mi do głowy na początku lat 1980-tych. Ilekroć wywołanie systemowe
zwraca błąd, jądro wie dokładnie, co poszło nie tak... i kompresuje to do
mniej niż 8 bitów errno. Przestrzeń użytkownika ma dostęp do tych samych danych, co jądro
powinno być możliwe, aby przestrzeń użytkownika mogła dokładnie dowiedzieć się, co spowodowało błąd
return i użyj tego do napisania dobrych komunikatów o błędach.

Czy to mogłoby być takie proste?

Błąd wiadomości as delikatność
Dobre komunikaty o błędach to często te zadania „jeden procent”, które są odrzucane zgodnie z harmonogramem
presja ściska Twój projekt. Jednak dobry komunikat o błędzie może mieć ogromne,
nieproporcjonalna poprawa komfortu użytkowania, gdy użytkownik wkracza w coś przerażającego
nieznane terytorium, którego zwykle nie spotyka się. To nie jest łatwe zadanie.

Jako programista larwalny autor nie widział problemu w (całkowicie dokładnym) błędzie
wiadomości takie jak ten:
pływający wyjątek (zrzucony rdzeń)
dopóki nie wskazano alternatywnej interpretacji nieprogramistycznej. Ale to nie jest to
jedyna rzecz nie tak z komunikatami o błędach Uniksa. Jak często widzisz komunikaty o błędach, takie jak:
$ ./głupi
nie można otworzyć pliku
$
W tym momencie programista ma dwie możliwości:

1.
możesz uruchomić debuger, np gdb(1) lub

2.
możesz użyć strace(1) lub kratownica(1) zajrzeć do środka.

· Pamiętaj, że Twoi użytkownicy mogą nawet nie mieć dostępu do tych narzędzi, nie mówiąc już o możliwościach
z nich korzystać. (Minęło bardzo dużo czasu od Unix początkujący oznaczało „tylko napisał pierwszej
sterownik urządzenia".)

Jednak w tym przykładzie użycie strace(1) ujawnia
$ strace -e śledzenie=otwarte ./głupi
open("jakiś/plik", O_RDONLY) = -1 ENOENT (Brak takiego pliku lub katalogu)
nie można otworzyć pliku
$
To znacznie więcej informacji, niż zawiera komunikat o błędzie. Zazwyczaj
głupi kod źródłowy wygląda tak
int fd = otwórz("coś", O_RDONLY);
jeśli (fd < 0)
{
fprintf(stderr, „nie można otworzyć pliku\n”);
wyjście(1);
}
Użytkownik nie jest o tym informowany który plik, a także nie informuje użytkownika który błąd. Był to plik
Nawet tam? Czy wystąpił problem z uprawnieniami? Mówi, że próbował otworzyć plik
plik, ale to prawdopodobnie przez przypadek.

Chwyć swoją wskazówkę i pokonaj nią larwalnego programistę. Opowiedz mu o przekleństwo(3).
Przy następnym użyciu programu zobaczysz inny komunikat o błędzie:
$ ./głupi
open: Nie ma takiego pliku ani katalogu
$
Postęp, ale nie taki, jakiego się spodziewaliśmy. W jaki sposób użytkownik może rozwiązać problem, jeśli wyświetli się komunikat o błędzie
nie powiedział mu, na czym polegał problem? Patrząc na źródło, widzimy
int fd = otwórz("coś", O_RDONLY);
jeśli (fd < 0)
{
perror("otwarte");
wyjście(1);
}
Czas na kolejny bieg z kijem ze wskazówkami. Tym razem komunikat o błędzie składa się z jednego kroku
do przodu i o krok do tyłu:
$ ./głupi
coś: Nie ma takiego pliku lub katalogu
$
Teraz wiemy, jaki plik próbował otworzyć, ale nie jesteśmy już o tym informowani koncepcja(2)
to się nie udało. W tym przypadku zapewne nie jest to istotne, ale dla kogoś może mieć znaczenie
inne wywołania systemowe. To mogło być creat(2) zamiast tego oznacza to operację
potrzebne są różne uprawnienia.
const char *nazwa pliku = "coś";
int fd = open(nazwa pliku, O_RDONLY);
jeśli (fd < 0)
{
perror(nazwa pliku);
wyjście(1);
}
Powyższy przykładowy kod jest niestety również typowy dla programistów nielarwalnych. Czas
aby powiedzieć naszemu uczniowi padawanu o strrrr(3) wywołanie systemowe.
$ ./głupi
koncepcja coś: Nie ma takiego pliku lub katalogu
$
Dzięki temu maksymalizuje się ilość informacji, które można przedstawić użytkownikowi. Kod wygląda
to:
const char *nazwa pliku = "coś";
int fd = open(nazwa pliku, O_RDONLY);
jeśli (fd < 0)
{
fprintf(stderr, "otwórz %s: %s\n", nazwa pliku, strerror(errno));
wyjście(1);
}
Teraz mamy wywołanie systemowe, nazwę pliku i ciąg błędu. Zawiera wszystkie
informacja, że strace(1) wydrukowano. To jest tak dobre, jak to tylko możliwe.

Albo to jest?

Ograniczenia of przekleństwo i strrrr
Problem, który dostrzegł autor w latach 1980., polegał na tym, że komunikat o błędzie był niekompletny.
Czy „nie ma takiego pliku lub katalogu” odnosi się do „kilka” lub do katalogu „rzeczplik w
kilkakatalog?

Szybkie spojrzenie na stronę podręcznika dla strrrr(3) mówi:
strerror - zwracany ciąg opisujący numer błędu
Uwaga: opisuje błąd numer, a nie błąd.

Z drugiej strony jądro wie jaki był błąd. Był konkretny punkt w
kod jądra, spowodowany specyficznym stanem, w którym kod jądra rozgałęził się i powiedział „nie”.
Czy program działający w przestrzeni użytkownika mógłby znaleźć konkretny warunek i zapisać lepszy błąd
wiadomość?

Jednak problem sięga głębiej. Co się stanie, jeśli problem wystąpi podczas czytać(2) systemu
zadzwoń, a nie koncepcja(2) zadzwonić? Komunikat o błędzie związany z tym jest prosty
koncepcja(2) aby dołączyć nazwę pliku, jest tam. Ale aby móc dołączyć nazwę pliku
w błędzie związanym z czytać(2) wywołanie systemowe, musisz przekazać nazwę pliku all
drogę w dół stosu wywołań, a także deskryptor pliku.

I tutaj jest coś, co przeszkadza: jądro już wie, jaka jest nazwa pliku
deskryptor jest powiązany z. Dlaczego programista miałby przekazywać nadmiarowe dane all
drogę w dół stosu wywołań, aby poprawić komunikat o błędzie, który może nigdy nie zostać wyświetlony? W
rzeczywistości wielu programistów nie zawraca sobie tym głowy, a wynikające z tego komunikaty o błędach są tym gorsze
to.

Ale to były lata 1980., na PDP11, z ograniczonymi zasobami i bez wspólnych bibliotek. Z powrotem
wtedy nie będzie żadnej wersji Uniksa / proc nawet w podstawowej formie i lsof(1) programu
brakowało ponad dekady. Dlatego pomysł odrzucono jako niepraktyczny.

poziom Nieskończoność Wsparcie
Wyobraź sobie, że masz wsparcie na poziomie nieskończoności. Z Twojego opisu stanowiska wynika, że ​​nigdy
kiedykolwiek muszę porozmawiać z użytkownikami. Dlaczego zatem wciąż istnieje ciągły strumień ludzi chcących
ty, lokalny guru Uniksa, rozszyfrować kolejny komunikat o błędzie?

O dziwo, 25 lat później, pomimo prostego systemu uprawnień, wdrożonego z pełnym
spójność, większość użytkowników Uniksa nadal nie ma pojęcia, jak zdekodować „Nie ma takiego pliku ani katalogu”,
lub którykolwiek z innych tajemniczych komunikatów o błędach, które widzą każdego dnia. Lub przynajmniej tajemnicze
Im.

Czy nie byłoby miło, gdyby wsparcie techniczne pierwszego poziomu nie wymagało odszyfrowywania komunikatów o błędach?
Czy nie byłoby miło mieć komunikaty o błędach, które użytkownicy mogliby zrozumieć bez dzwonienia
wsparcie techniczne?

W te dni / proc w systemie Linux jest więcej niż w stanie dostarczyć informacji niezbędnych do dekodowania
zdecydowaną większość komunikatów o błędach i wskazują użytkownikowi bezpośrednią przyczynę ich wystąpienia
problem. W systemach z ograniczoną / proc wdrożenie, lsof(1) polecenie może wypełnić
wiele luk.

W 2008 roku strumień próśb o tłumaczenie trafiał do autora zdecydowanie zbyt często. To było
czas ponownie przeanalizować ten 25-letni pomysł, a efektem jest libexplain.

ZA POMOCĄ THE BIBLIOTEKA


Tam, gdzie to możliwe, interfejs biblioteki stara się być spójny. Zacznijmy od
przykład użycia strrrr(3):
if (zmień nazwę (stara_ścieżka, nowa_ścieżka) < 0)
{
fprintf(stderr, "zmień nazwę %s %s: %s\n", stara_ścieżka, nowa_ścieżka,
strerror(numer błędu));
wyjście(1);
}
Ideą libexplain jest udostępnienie pliku strrrr(3) odpowiednik dla każdy wywołanie systemowe,
dostosowany specjalnie do tego wywołania systemowego, dzięki czemu może podać bardziej szczegółowy błąd
komunikat zawierający większość informacji widocznych pod nagłówkiem sekcji „BŁĘDY”.
2 i 3 mężczyzna stron, uzupełnione o informacje o faktycznych warunkach, aktualnej argumentacji
wartości i ograniczenia systemowe.

Połączenia Prosty Walizka
Połączenia strrrr(3) wymiana:
if (zmień nazwę (stara_ścieżka, nowa_ścieżka) < 0)
{
fprintf(stderr, "%s\n", wyjaśnij_rename(stara_ścieżka, nowa_ścieżka));
wyjście(1);
}

Połączenia Nie Walizka
Możliwe jest również przekazanie jawne errno(3) wartość, jeśli musisz najpierw coś zrobić
przetwarzanie, które mogłoby zakłócić errno, takie jak usuwanie błędów:
if (zmień nazwę (stara_ścieżka, nowa_ścieżka < 0))
{
int stary_errno = errno;
...kod że przeszkadza errno...
fprintf(stderr, "%s\n", wyjaśnij_errno_rename(old_errno,
stara_ścieżka, nowa_ścieżka));
wyjście(1);
}

Połączenia Wielowątkowy Sprawy
Niektóre aplikacje są wielowątkowe i dlatego nie mogą współdzielić zawartości wewnętrznej biblioteki libexplain
bufor. Możesz dostarczyć własny bufor za pomocą
if (odłącz(nazwa ścieżki))
{
wiadomość znakowa [3000];
wyjaśnij_wiadomość_unlink(wiadomość, rozmiar(wiadomość), ścieżka);
dialog_błędów(wiadomość);
return -1;
}
A co do kompletności, jedno i drugie errno(3) i bezpieczne dla wątków:
ssize_t nbytes = read(fd, dane, sizeof(dane));
jeśli (nbajtów < 0)
{
wiadomość znakowa [3000];
int stary_errno = errno;
...błąd regeneracja...
wyjaśnij_wiadomość_errno_read(wiadomość, rozmiar(wiadomość),
stary_błędny numer, fd, dane, rozmiar(dane));
dialog_błędów(wiadomość);
return -1;
}

Są to zamienniki strerror_r(3), w systemach, które to posiadają.

Interfejs Cukier
Zestaw funkcji dodanych jako funkcje zwiększające wygodę, mające na celu nakłonienie programistów do korzystania z
libexplain okazują się najczęściej używanymi przez autora funkcjami libexplain w
programy wiersza poleceń:
int fd = wyjaśnij_tworzenie_lub_die(nazwa pliku, 0666);
Ta funkcja próbuje utworzyć nowy plik. Jeżeli nie jest to możliwe, wyświetla komunikat o błędzie i
kończy się z EXIT_FAILURE. Jeśli nie ma błędu, zwraca nowy deskryptor pliku.

Powiązana funkcja:
int fd = wyjaśnij_creat_on_error(nazwa pliku, 0666);
wypisze komunikat o błędzie w przypadku niepowodzenia, ale także zwróci oryginalny wynik błędu, oraz
errno(3) również nie jest molestowany.

Wszystkie kategorie dotychczasowy inny system Połączenia
Ogólnie rzecz biorąc, każde wywołanie systemowe ma swój własny plik dołączany
#włączaćNazwa.h>
który definiuje prototypy funkcji dla sześciu funkcji:

· wyjaśnić_Nazwa,

· wyjaśnij_błąd_Nazwa,

· wyjaśnij_wiadomość_Nazwa,

· wyjaśnij_wiadomość_errno_Nazwa,

· wyjaśnić_Nazwa_lub_umrzeć i

· wyjaśnić_Nazwa_w_błędzie.

Każdy prototyp funkcji ma dokumentację Doxygen i tę dokumentację is nie obnażony
po zainstalowaniu plików dołączanych.

Połączenia czekać(2) wywołania systemowe (i przyjaciele) mają kilka dodatkowych wariantów, które również interpretują niepowodzenie
być statusem wyjścia, który nie jest EXIT_SUCCESS. Dotyczy to system(3) i pzamknij(3) as
dobrze.

Zasięg obejmuje 221 wywołań systemowych i 547 żądań ioctl. Systemów jest dużo więcej
wzywa do wdrożenia. Wywołania systemowe, które nigdy nie wracają, np wyjście(2), nie występują
w bibliotece i nigdy tam nie będzie. The exec rodzina wywołań systemowych jest wspierane, ponieważ
wracają, gdy wystąpi błąd.

Kot
Tak mógłby wyglądać hipotetyczny program „kota” z pełnym raportowaniem błędów,
za pomocą libexplain.
#włączać
#zawierać
#włączać
Jest jeden dodatek do libexplain i zwykłe podejrzane. (Jeśli chcesz zmniejszyć
obciążenie preprocesora, możesz użyć specyficznegoNazwa.h> zawiera.)
statyczna pustka
proces(PLIK *fp)
{
Do (;;)
{
bufor znaków [4096];
size_t n = wyjaśnij_fread_or_die(bufor, 1, sizeof(bufor), fp);
jeśli (!n)
break;
wyjaśnij_fwrite_or_die(bufor, 1, n, stdout);
}
}
Połączenia wygląda tak funkcja kopiuje strumień pliku na standardowe wyjście. Jeżeli wystąpi błąd
w przypadku odczytu lub zapisu jest zgłaszany (a nazwa ścieżki zostanie uwzględniona w pliku
błąd), a polecenie kończy się z EXIT_FAILURE. Nie martwimy się nawet śledzeniem
ścieżki lub przekazywanie ich w dół stosu wywołań.
int
main(int argc, char **argv)
{
Do (;;)
{
int c = getopt(argc, argv, "o:");
jeśli (c == EOF)
break;
przełącznik (c)
{
przypadek „o”:
wyjaśnij_freopen_or_die(optarg, "w", standardowe wyjście);
break;
Zabawną częścią tego kodu jest to, że libexplain może raportować błędy włącznie z dotychczasowy nazwa ścieżki nawet
Jeśli ty nie jawnie otwórz ponownie standardowe wyjście, tak jak to zrobiono tutaj. Nawet się nie martwimy
śledzenie nazwy pliku.
domyślna:
fprintf(stderr, "Użycie: %ss [ -o ] ...\N",
argv[0]);
zwróć EXIT_FAILURE;
}
}
jeśli (opcja == argc)
proces(stdin);
więcej
{
podczas (opcja <argc)
{
PLIK *fp = wyjaśnij_fopen_or_die(argv[optind]++, "r");
proces(fp);
wyjaśnij_fzamknij_or_die(fp);
}
}
Standardowe wyjście zostanie domyślnie zamknięte, ale będzie już za późno na raport o błędach
wydane, więc robimy to tutaj, na wypadek, gdyby buforowane wejścia/wyjścia jeszcze niczego nie zapisały, i
występuje błąd ENOSPC lub coś takiego.
wyjaśnij_fflush_or_die(stdout);
zwróć EXIT_SUCCESS;
}
To wszystko. Pełne raportowanie błędów, przejrzysty kod.

Rusty'ego Skala of Interfejs Dobroć
Dla tych z Was, którzy nie są zaznajomieni z tym, polecam książkę Rusty’ego Russela „Jak sprawić, by było to trudne do niewłaściwego użycia?”
to obowiązkowa lektura dla projektantów API.
http://ozlabs.org/~rusty/index.cgi/tech/2008-03-30.html

10. Jest niemożliwy do otrzymać źle.

Cele muszą być wyznaczane wysoko, ambitnie wysoko, abyś nie mógł ich osiągnąć i nie myślał, że je osiągasz
skończyłeś, kiedy cię nie było.

Biblioteka libexplain wykrywa fałszywe wskaźniki i wiele innych fałszywych parametrów wywołań systemowych,
i ogólnie stara się unikać błędów seg nawet w najbardziej trudnych okolicznościach.

Biblioteka libexplain została zaprojektowana tak, aby była bezpieczna dla wątków. Prawdopodobnie będzie więcej zastosowań w świecie rzeczywistym
wskaż miejsca, w których można to poprawić.

Największy problem stanowią same nazwy funkcji. Ponieważ C nie ma
przestrzenie nazw, biblioteka libexplain zawsze używa przedrostka nazwy wyjaśniającej. To jest
tradycyjny sposób tworzenia przestrzeni pseudonazw w celu uniknięcia konfliktów symboli.
Jednak skutkuje to nienaturalnie brzmiącymi nazwami.

9. Połączenia kompilator or Linki nie będzie niech ty otrzymać it źle.

Częstym błędem jest użycie wyjaśniania_open tam, gdzie miało to służyć wyjaśnieniu_open_or_die.
Na szczęście kompilator często zgłasza w tym momencie błąd typu (na przykład nie mogę przypisać
const char * rvalue na int lvalue).

8. Połączenia kompilator będzie ostrzec if ty otrzymać it źle.

Jeśli zostanie użyte wyjaśnienie_rename, gdy zamierzono wyjaśnienie_rename_or_die, może to spowodować inne
problemy. GCC ma przydatny atrybut funkcji warn_unused_result, a biblioteka libexplain
biblioteka dołącza go do wszystkich wyjaśnieńNazwa wywołania funkcji, aby wyświetlić ostrzeżenie, gdy ty
popełnij ten błąd. Połącz to z gcc -Błąd aby promować to do poziomu 9 dobroci.

7. Połączenia oczywista posługiwać się is (prawdopodobnie) dotychczasowy skorygowania jeden.

Nazwy funkcji zostały wybrane tak, aby przekazać ich znaczenie, ale nie zawsze tak jest
udany. Podczas wyjaśniania_Nazwa_lub_umrzyj i wyjaśnij_Nazwa_on_error są dość opisowe,
rzadziej używane warianty bezpieczne dla wątków są trudniejsze do dekodowania. Prototypy funkcji pomagają
kompilator w kierunku zrozumienia, a komentarze Doxygen w plikach nagłówkowych pomagają użytkownikowi
ku zrozumieniu.

6. Połączenia Nazwa mówi ty w jaki sposób do posługiwać się to.

Szczególnie ważne jest przeczytanie wyjaśnienia_Nazwa_or_die jako „wyjaśnij (Nazwa albo giń)".
Używanie spójnego przedrostka przestrzeni nazw wyjaśniania_ ma pewne niefortunne skutki uboczne w pliku
także dział oczywistości.

Kolejność słów w nazwach wskazuje również kolejność argumentów. Argument
listy zawsze zakończenia z tymi samymi argumentami, które zostały przekazane do wywołania systemowego; cała kolekcja of im. Jeśli
W nazwie pojawia się _errno_, jego argument zawsze poprzedza argumenty wywołania systemowego. Jeśli
W nazwie pojawia się _wiadomość_, jej dwa argumenty zawsze są na pierwszym miejscu.

5. Do it prawo or it będzie złamać at czas wykonywania.

Biblioteka libexplain wykrywa fałszywe wskaźniki i wiele innych fałszywych parametrów wywołań systemowych,
i ogólnie stara się unikać błędów seg nawet w najbardziej trudnych okolicznościach. Powinno
nigdy nie psują się w czasie wykonywania, ale częstsze użytkowanie w świecie rzeczywistym bez wątpienia poprawi tę sytuację.

Niektóre komunikaty o błędach są skierowane raczej do programistów i opiekunów niż do użytkowników końcowych, jak ten
może pomóc w rozwiązaniu błędów. Nie tyle „przerwa w czasie wykonywania”, co „przekazywanie informacji w
runtime” (po wywołaniu systemowym barfs).

4. Obserwuj pospolity Konwencja i będziesz otrzymać it dobrze.

Ponieważ C nie ma przestrzeni nazw, biblioteka libexplain zawsze używa nazwy wyjaśniającej
prefiks. Jest to tradycyjny sposób tworzenia przestrzeni pseudonazw w celu uniknięcia
konflikty symboli.

Końcowe argumenty wszystkich wywołań libexplain są identyczne z wywołaniami systemowymi
opisują. Ma to na celu zapewnienie spójnej konwencji wspólnej z
system sam się wywołuje.

3. Czytaj dotychczasowy dokumentacja i będziesz otrzymać it dobrze.

Biblioteka libexplain ma na celu posiadanie pełnej dokumentacji Doxygen dla każdego
publiczne wywołanie API (i także wewnętrznie).

MESSAGE TREŚĆ


Praca nad libexplain przypomina trochę patrzenie na spód samochodu, gdy jest on włączony
podnośnik u mechanika. Pod spodem jest trochę brzydkiego materiału, plus błoto i brud, i...
użytkownicy rzadko to widzą. Dobry komunikat o błędzie musi mieć charakter informacyjny, nawet dla użytkownika, który
miał szczęście, że nie musiał zbyt często patrzeć na spód, a także
informacyjny dla mechanika wysłuchującego opisu użytkownika przez telefon. To jest
nie jest to łatwe zadanie.

Wracając do naszego pierwszego przykładu, kod wyglądałby tak, gdyby korzystał z biblioteki libexplain:
int fd = wyjaśnij_open_or_die("coś/rzecz", O_RDONLY, 0);
zakończy się niepowodzeniem z powodu takiego komunikatu o błędzie
open(pathname = "jakiś/plik", flags = O_RDONLY) nie powiodło się, nie ma takiego pliku ani katalogu
(2, ENOENT), ponieważ w bieżącym katalogu nie ma „jakiegoś” katalogu
To dzieli się na trzy części
wywołanie systemowe przegrany, błąd systemu bo
wyjaśnienie

Przed Bo
Część wiadomości poprzedzającą „ponieważ” można uznać za zbyt techniczną lub nie-
użytkowników technicznych, głównie w wyniku dokładnego wydrukowania samego wywołania systemu na stronie
początek komunikatu o błędzie. I to wygląda strace(1) wyjście, dla maniaka bonusowego
punktów.
open(pathname = "jakiś/plik", flags = O_RDONLY) nie powiodło się, nie ma takiego pliku ani katalogu
(2, ENOENT)
Ta część komunikatu o błędzie jest niezbędna programiście podczas pisania kodu,
i równie ważne dla opiekuna, który musi czytać raporty o błędach i naprawiać błędy w pliku
kod. Mówi dokładnie, co się nie udało.

Jeśli ten tekst nie zostanie wyświetlony użytkownikowi, nie będzie on mógł go skopiować i wkleić do pliku
raport o błędzie, a jeśli nie ma tego w raporcie o błędzie, opiekun nie może wiedzieć, co się właściwie wydarzyło
źle.

Często będzie z niego korzystał personel techniczny strace(1) lub kratownica(1) aby uzyskać dokładnie te informacje, ale
ta droga nie jest otwarta podczas czytania raportów o błędach. System zgłaszającego błędy jest daleko
daleko i obecnie w zupełnie innym stanie. Dlatego też informacje te muszą znaleźć się w pliku
raport o błędzie, co oznacza, że ​​musi on znajdować się w komunikacie o błędzie.

Reprezentacja wywołania systemowego nadaje również kontekst pozostałej części komunikatu. Jeśli potrzeba
pojawia się, w wyjaśnieniu można przywołać nazwę argumentu wywołania systemowego powodującego naruszenie
po „ponieważ”. Ponadto wszystkie ciągi znaków są w pełni cytowane i mają znaki C ze znakami ucieczki, więc
osadzone znaki nowej linii i znaki niedrukowalne nie spowodują zamknięcia terminala użytkownika
pogmatwany.

Połączenia błąd systemu jest tym, co wychodzi strrrr(2) plus symbol błędu. Niecierpliwy i
doświadczeni administratorzy systemu mogliby w tym momencie przestać czytać, ale dotychczasowe doświadczenia autora są takie
że dalsze czytanie daje satysfakcję. (Jeśli nie jest to satysfakcjonujące, prawdopodobnie jest to obszar ok
libwyjaśnij, co można ulepszyć. Oczywiście mile widziane są wkłady w kod.)

Po Bo
To jest część komunikatu o błędzie skierowana do użytkowników nietechnicznych. Wygląda poza
proste argumenty wywołań systemowych i szuka czegoś bardziej szczegółowego.
w bieżącym katalogu nie ma „jakiegoś” katalogu
W tej części podjęto próbę wyjaśnienia bezpośredniej przyczyny błędu prostym językiem
czy w tym przypadku internacjonalizacja jest niezbędna.

Ogólnie rzecz biorąc, polityka polega na tym, aby zawrzeć jak najwięcej informacji, tak aby użytkownik
nie musi go szukać (i nie pomija go w raporcie o błędzie).

Umiędzynarodowienie
Większość komunikatów o błędach w bibliotece libexplain została umiędzynarodowiona. Tam
nie ma jeszcze lokalizacji, więc jeśli chcesz uzyskać wyjaśnienia w swoim ojczystym języku,
proszę o wsparcie.

Powyższy kwalifikator „większość” odnosi się do faktu, że dowód koncepcji
wdrożenie nie obejmowało wsparcia w zakresie internacjonalizacji. Podstawą kodu jest
poprawiane stopniowo, zwykle w wyniku refaktoryzacji komunikatów, tak aby każdy błąd był usuwany
ciąg komunikatu pojawia się w kodzie dokładnie raz.

Uwzględniono języki, które wymagają złożenia części
wywołanie systemowe przegrany, błąd systemu bo wyjaśnienie
w różnej kolejności, aby zapewnić poprawną gramatykę w zlokalizowanych komunikatach o błędach.

Post mortem
Są chwile, kiedy program nie użył jeszcze biblioteki libexplain i nie możesz jej użyć strace(1)
albo. Tam jest wyjaśniać(1) polecenie dołączone do libexplain, którego można użyć
odszyfrować komunikaty o błędach, jeśli stan podstawowego systemu nie zmienił się zbytnio.
$ wyjaśniać przemianować bla /tmp/bar/baz -e ENOENT
rename(oldpath = "foo", newpath = "/tmp/bar/baz") nie powiodło się, nie ma takiego pliku ani katalogu
(2, ENOENT), ponieważ w nowej ścieżce nie ma katalogu „bar”/ Tmp" katalog
$
Zwróć uwagę, jak niejednoznaczność ścieżki jest rozwiązywana przy użyciu nazwy argumentu wywołania systemowego. Z
oczywiście musisz znać błąd i wywołanie systemowe wyjaśniać(1) być użytecznym. jako
poza tym jest to jeden ze sposobów weryfikacji tego przez zestaw automatycznych testów libexplain
Libexplain działa.

Filozofia
„Powiedz mi wszystko, łącznie z tym, czego nie wiedziałem, czego szukać”.

Biblioteka jest zaimplementowana w taki sposób, że po statycznym połączeniu dostępny jest tylko kod
faktycznie używane będą powiązane. Osiąga się to poprzez posiadanie jednej funkcji na plik źródłowy,
kiedy tylko to możliwe.

Jeśli będzie możliwe podanie większej ilości informacji, libexplain to zrobi. Im mniej użytkownika
musi sam wyśledzić, tym lepiej. Oznacza to, że identyfikatorom UID towarzyszy plik
nazwa użytkownika, identyfikatorom GID towarzyszy nazwa grupy, identyfikatorom PID towarzyszy proces
nazwie, deskryptorom plików i strumieniom towarzyszy nazwa ścieżki, itp.

Jeśli podczas rozwiązywania ścieżek nie istnieje komponent ścieżki, libexplain będzie szukać podobnych
nazw, w celu zaproponowania alternatyw dla błędów typograficznych.

Biblioteka libexplain stara się używać jak najmniejszej sterty i zwykle nie używa jej wcale. To jest
aby w miarę możliwości uniknąć zakłócania stanu procesu, chociaż czasami tak się dzieje
nieunikniony.

Biblioteka libexplain stara się być bezpieczna dla wątków, unikając zmiennych globalnych, zachowując
stan na stosie tak bardzo, jak to możliwe. Istnieje jeden wspólny bufor komunikatów, a plik
funkcje, które go używają, są udokumentowane jako nie bezpieczne dla wątków.

Biblioteka libexplain nie zakłóca procedur obsługi sygnałów procesu. To sprawia
określenie, czy wskaźnik będzie stanowił wyzwanie, ale nie jest niemożliwe.

Gdy informacje są dostępne za pośrednictwem wywołania systemowego, a także za pośrednictwem / proc
preferowane jest wywołanie systemowe. Ma to na celu uniknięcie zakłócania stanu procesu.
Są też chwile, kiedy nie są dostępne żadne deskryptory plików.

Biblioteka libexplain jest skompilowana z obsługą dużych plików. Nie ma dużego/małego
schizofrenia. Jeśli ma to wpływ na typy argumentów w interfejsie API, zostanie wyświetlony błąd
jeśli nie ma niezbędnych definicji dużego pliku.

FIXME: Wymagana jest praca, aby upewnić się, że w kodzie są obsługiwane przydziały systemu plików. Ten
dotyczy niektórych getrlimit(2) również granice.

Zdarzają się przypadki, gdy ścieżki krewnych nie dostarczają żadnych informacji. Na przykład: demony systemowe,
serwerów i procesów w tle. W takich przypadkach w błędzie używane są ścieżki bezwzględne
wyjaśnienia.

PATH UCHWAŁA


Wersja skrócona: patrz rozdzielczość_ścieżki(7).

Wersja długa: większość użytkowników nigdy o niej nie słyszała rozdzielczość_ścieżki(7) i wielu zaawansowanych użytkowników
nigdy tego nie czytałem. Oto wersja z komentarzami:

Ewolucja krok po kroku 1: Start of dotychczasowy rozkład wygląda tak
Jeśli nazwa ścieżki zaczyna się od znaku ukośnika („/”), początkowym katalogiem wyszukiwania jest
katalog główny procesu wywołującego.

Jeśli nazwa ścieżki nie zaczyna się od znaku ukośnika („/”), oznacza to początkowe wyszukiwanie
katalog procesu rozstrzygania jest bieżącym katalogiem roboczym procesu.

Ewolucja krok po kroku 2: Spacer wzdłuż dotychczasowy ścieżka
Ustaw bieżący katalog wyszukiwania na początkowy katalog wyszukiwania. Teraz dla każdego nie-
końcowy składnik nazwy ścieżki, gdzie komponent jest podciągiem oddzielonym ukośnikiem („/”)
znaków, komponent ten jest wyszukiwany w bieżącym katalogu wyszukiwania.

Jeśli proces nie ma uprawnień do wyszukiwania w bieżącym katalogu wyszukiwania, zostanie wyświetlony komunikat EACCES
zwracany jest błąd („Odmowa dostępu”).
open(pathname = "/home/archives/.ssh/private_key", flags = O_RDONLY) nie powiodło się,
Odmowa zezwolenia (13, EACCES), ponieważ proces nie ma uprawnień do wyszukiwania
do katalogu „/home/archives/.ssh”, efektywny GID procesu wynosi 1000
„pmiller” nie pasuje do właściciela katalogu 1001 „archives”, więc właściciel
tryb uprawnień „rwx” jest ignorowany, pozostałe tryby uprawnień to „---”, a
proces nie jest uprzywilejowany (nie posiada możliwości DAC_READ_SEARCH)

Jeśli komponent nie zostanie znaleziony, zwracany jest błąd ENOENT („Nie ma takiego pliku ani katalogu”).
unlink(pathname = "/home/microsoft/śmieci") nie powiodło się, Nie ma takiego pliku ani katalogu (2,
ENOENT), ponieważ w ścieżce nie ma katalogu „microsoft”/ Home" katalog

Dostępna jest także pomoc dla użytkowników w przypadku błędnego wpisania nazw ścieżek oraz sugestie, kiedy to zrobić
Zwracany jest ENOENT:
open(pathname = "/user/include/fcntl.h", flags = O_RDONLY) nie powiodło się, Nie ma takiego pliku lub
katalog (2, ENOENT), ponieważ w ścieżce „/” nie ma katalogu „user”
katalog, czy zamiast tego miałeś na myśli katalog „usr”?

Jeśli komponent zostanie znaleziony, ale nie jest katalogiem ani dowiązaniem symbolicznym, zostanie wyświetlony plik ENOTDIR
zwracany jest błąd („To nie jest katalog”).
open(pathname = "/home/pmiller/.netrc/lca", flags = O_RDONLY) nie powiodło się, nie
katalog (20, ENOTDIR), ponieważ w ścieżce znajduje się zwykły plik „.netrc”.
Katalog „/home/pmiller” jest używany jako katalog, gdy tak nie jest

Jeśli komponent zostanie znaleziony i jest katalogiem, ustawiamy na niego bieżący katalog wyszukiwania
i przejdź do następnego komponentu.

Jeśli komponent zostanie znaleziony i jest dowiązaniem symbolicznym (dowiązaniem symbolicznym), najpierw rozwiązujemy to dowiązanie symboliczne
link (z bieżącym katalogiem wyszukiwania jako początkowym katalogiem wyszukiwania). To po błędzie
zwracany jest błąd. Jeśli wynikiem nie jest katalog, zwracany jest błąd ENOTDIR.
unlink(pathname = "/tmp/dangling/śmieci") nie powiodło się, Nie ma takiego pliku ani katalogu (2,
ENOENT), ponieważ „wiszące” łącze symboliczne w ścieżce „/ Tmp" katalog
odnosi się do „nigdzie”, które nie istnieje
Jeśli rozwiązanie dowiązania symbolicznego zakończy się pomyślnie i zwróci katalog, ustawiamy bieżący
wyszukaj katalog w tym katalogu i przejdź do następnego komponentu. Należy pamiętać, że
proces rozwiązywania obejmuje tutaj rekurencję. Aby chronić jądro przed stosem
przepełnienia, a także w celu ochrony przed odmową usługi, istnieją limity maksymalne
głębokość rekurencji i maksymalną liczbę podążanych dowiązań symbolicznych. Błąd ELOOP to
zwracany po przekroczeniu maksimum („Zbyt wiele poziomów dowiązań symbolicznych”).
open(pathname = "/tmp/dangling", flags = O_RDONLY) nie powiodło się, zbyt wiele poziomów
dowiązania symboliczne (40, ELOOP), ponieważ napotkano pętlę dowiązań symbolicznych
nazwa ścieżki, zaczynająca się od „/tmp/dangling”
Możliwe jest również otrzymanie błędu ELOOP lub EMLINK, jeśli jest zbyt wiele dowiązań symbolicznych, ale nie
wykryto pętlę.
open(pathname = "/tmp/rabbit-hole", flags = O_RDONLY) nie powiodło się, Zbyt wiele poziomów
dowiązania symboliczne (40, ELOOP), ponieważ napotkano zbyt wiele dowiązań symbolicznych
nazwa ścieżki (8)
Zwróć uwagę, jak drukowany jest również rzeczywisty limit.

Ewolucja krok po kroku 3: Znajdź dotychczasowy finał wejście
Wyszukiwanie końcowego składnika nazwy ścieżki przebiega tak samo jak wszystkich innych
komponentów, jak opisano w poprzednim kroku, z dwiema różnicami:

(i) Ostatnim komponentem nie musi być katalog (przynajmniej jeśli chodzi o rozdzielczość ścieżki
dotyczy procesu. Może to być katalog lub niekatalog, ponieważ
wymagania konkretnego wywołania systemowego).

(II)
Nieodnalezienie końcowego komponentu niekoniecznie oznacza błąd; może jesteśmy po prostu
tworzenie go. Szczegóły dotyczące postępowania z wpisem końcowym opisano w pkt
strony podręcznika konkretnych wywołań systemowych.

(iii)
Możliwe jest również wystąpienie problemu z ostatnim komponentem, jeśli jest to dowiązanie symboliczne
i nie należy tego przestrzegać. Na przykład za pomocą koncepcja(2) Flaga O_NOFOLLOW:
open(pathname = "a-dowiązanie symboliczne", flags = O_RDONLY | O_NOFOLLOW) nie powiodło się, zbyt wiele poziomów
dowiązania symboliczne (ELOOP), ponieważ określono O_NOFOLLOW, ale nazwa ścieżki odnosi się do a
link symboliczny

(iv)
Użytkownicy często popełniają błędy podczas wpisywania nazw ścieżek. Biblioteka libexplain
próbuje sugerować, kiedy zwracany jest ENOENT, na przykład:
open(pathname = "/usr/include/filecontrl.h", flags = O_RDONLY) nie powiodło się, Nie ma takiego pliku lub
katalog (2, ENOENT), ponieważ w ścieżce nie ma zwykłego pliku „filecontrl.h”.
"/ Usr / include", czy zamiast tego miałeś na myśli zwykły plik "fcntl.h"?

(v) Możliwe jest również, że końcowym komponentem będzie coś innego niż a
zwykły plik:
readlink(nazwa ścieżki = „tylko plik”, dane = 0x7F930A50, rozmiar_danych = 4097) nie powiodło się,
Nieprawidłowy argument (22, EINVAL), ponieważ ścieżka jest zwykłym plikiem, a nie dowiązaniem symbolicznym

(vi)
FIXME: obsługa bitu „t”.

Limity
Istnieje wiele ograniczeń dotyczących nazw ścieżek i plików.

Limit długości ścieżki
Istnieje maksymalna długość nazw ścieżek. Jeśli nazwa ścieżki (lub jakiś plik pośredni
ścieżka uzyskana podczas rozwiązywania dowiązań symbolicznych) jest za długa, ENAMETOOLONG
zwracany jest błąd („Nazwa pliku jest za długa”). Zwróć uwagę, w jaki sposób uwzględniono limit systemowy
w komunikacie o błędzie.
otwórz(nazwa ścieżki = "bardzo długo", flagi = O_RDONLY) nie powiodło się, nazwa pliku jest za długa (36,
ENAMETOOLONG), ponieważ nazwa ścieżki przekracza maksymalną długość ścieżki systemowej (4096)

Limit długości nazwy pliku
Niektóre warianty Uniksa mają ograniczenie liczby bajtów w każdym komponencie ścieżki.
Część z nich radzi sobie z tym po cichu, a część podaje ENAMETOOLONG; libexplain
korzysta z biblioteki ścieżka konf(3) _PC_NO_TRUNC, aby powiedzieć które. Jeśli wystąpi ten błąd, plik
Biblioteka libexplain poda limit w komunikacie o błędzie. Limit wynosi
uzyskany z ścieżka konf(3) _PC_NAME_MAX. Zwróć uwagę, w jaki sposób uwzględniono limit systemowy
w komunikacie o błędzie.
otwórz(nazwa ścieżki = "system7/tylko-miał-14-znaków", flagi = O_RDONLY) nie powiodło się, plik
nazwa jest za długa (36, ENAMETOOLONG), ponieważ komponent „tylko-miał-14-znaków” jest
dłużej niż limit systemowy (14)

Pusta nazwa ścieżki
W oryginalnym systemie Unix pusta ścieżka odnosiła się do bieżącego katalogu.
Obecnie POSIX stanowi, że pusta nazwa ścieżki nie może zostać pomyślnie rozwiązana.
open(pathname = "", flags = O_RDONLY) nie powiodło się, Nie ma takiego pliku ani katalogu (2,
ENOENT), ponieważ POSIX stanowi, że nie można rozpoznać pustej ścieżki
skutecznie

Uprawnienia
Bity uprawnień pliku składają się z trzech grup po trzy bity. Pierwsza grupa
Three jest używane, gdy efektywny identyfikator użytkownika procesu wywołującego jest równy identyfikatorowi właściciela procesu
plik. Druga grupa trzech jest używana, gdy identyfikator grupy pliku jest równy
efektywny identyfikator grupy procesu wywołującego lub jest jednym z dodatkowych identyfikatorów grup procesu
proces wywoływania. Jeśli żadna z nich nie jest spełniona, używana jest trzecia grupa.
otwórz(nazwa ścieżki = "/ Etc / passwd", flagi = O_WRONLY) nie powiodło się, Odmowa dostępu (13,
EACCES), ponieważ proces nie ma uprawnień do zapisu w zwykłym „passwd”.
plik w ścieżce „/ Etc" katalog, proces efektywny UID 1000 "pmiller"
nie pasuje do zwykłego właściciela pliku 0 „root”, więc tryb uprawnień właściciela „rw-”
jest ignorowany, innym trybem uprawnień jest „r--”, a proces nie jest uprzywilejowany
(nie ma możliwości DAC_OVERRIDE)
Wyjaśnieniu temu poświęcono sporo miejsca, ponieważ większość użytkowników o tym nie wie
tak działa system uprawnień. W szczególności: właściciel, grupa i inne
uprawnienia są wyłączne, nie można ich łączyć ze sobą za pomocą funkcji „LUB”.

DZIWNE ROLNICZE CIEKAWY SYSTEM WEZWANIA


Często ujawnia się proces pisania określonej procedury obsługi błędów dla każdego wywołania systemowego
interesujące dziwactwa i warunki brzegowe lub niejasne errno(3) wartości.

ENOMED, Nie średni znaleziono
Źródłem tytułu artykułu była czynność kopiowania płyty CD.
$ dd if=/dev/cdrom of=fubar.iso
dd: otwieranie „/dev/cdrom”: Nie znaleziono nośnika
$
Autor zastanawiał się, dlaczego komputer mówi mu, że nie ma czegoś takiego jak medium
średni. Pomijając fakt, że ogromna liczba rodzimych użytkowników języka angielskiego nie jest
nawet świadomi, że „media” to liczba mnoga, nie mówiąc już o tym, że „medium” to liczba pojedyncza, czyli ciąg znaków
zwrócone przez strrrr(3) ponieważ ENOMEDIUM jest tak zwięzłe, że prawie całkowicie pozbawione go
treści.

Kiedy koncepcja(2) zwraca ENOMEDIUM, byłoby miło, gdyby biblioteka libexplain mogła rozszerzyć a
niewiele na ten temat, w zależności od rodzaju napędu. Na przykład:
...ponieważ w stacji dyskietek nie ma dyskietki
...ponieważ w napędzie CD-ROM nie ma płyty
...ponieważ w napędzie nie ma taśmy
...ponieważ w czytniku kart nie ma karty pamięci

I tak się stało...
open(pathname = "/dev/cdrom", flags = O_RDONLY) nie powiodło się, nie znaleziono nośnika (123,
ENOMEDIUM), ponieważ wygląda na to, że w napędzie CD-ROM nie ma płyty
Sztuczka, o której autor wcześniej nie wiedział, polegała na otwarciu urządzenia za pomocą
Flaga O_NONBLOCK, która pozwoli Ci otworzyć dysk bez nośnika. Ty, zatem
wydanie specyficzne dla urządzenia ioctls(2) prośby, dopóki nie zrozumiesz, o co do cholery chodzi. (Nie
pewien, czy jest to POSIX, ale wydaje się, że działa to również w BSD i Solarisie, zgodnie z
dotychczasowy wodim(1) źródła.)

Zwróć także uwagę na różne zastosowania słów „dysk” i „dysk” w kontekście. Powstał standard CD
we Francji, ale wszystko inne ma „k”.

BŁĄD, Łazienka adres
Każde wywołanie systemowe, które przyjmuje argument wskaźnikowy, może zwrócić EFAULT. Biblioteka libexplain
może dowiedzieć się, który argument jest wadliwy, i robi to bez zakłócania procesu
(lub wątek) obsługa sygnałów.

Gdy jest dostępny, Mincore(2) używane jest wywołanie systemowe, aby zapytać, czy obszar pamięci jest ważny.
Może zwrócić trzy wyniki: zmapowany, ale nie w pamięci fizycznej, zmapowany i fizyczny
pamięci i nie są mapowane. Podczas testowania ważności wskaźnika pierwsze dwa to „tak”
a ostatnie brzmi „nie”.

Sprawdzanie ciągów C jest trudniejsze, ponieważ zamiast wskaźnika i rozmiaru mamy tylko
mieć wskaźnik. Aby określić rozmiar, musielibyśmy znaleźć NUL i to byłoby możliwe
błąd seg, catch-22.

Aby obejść ten problem, biblioteka libexplain używa metody stan(2) wywołanie systemowe (ze znanym
dobry drugi argument), aby przetestować ciągi C pod kątem ważności. Powrót błędu && errno == EFAULT
jest „nie”, a wszystko inne jest „tak”. To oczywiście ogranicza ciągi znaków do PATH_MAX
znaków, ale zwykle nie stanowi to problemu dla biblioteki libexplain, ponieważ tak jest
prawie zawsze najdłuższe ciągi, na których mu zależy.

EMFILE, Zbyt wiele koncepcja pliki
Ten błąd występuje, gdy proces ma już otwartą maksymalną liczbę deskryptorów plików.
Jeśli ma zostać wydrukowany rzeczywisty limit, a biblioteka libexplain próbuje to zrobić, nie można go otworzyć
plik w / proc przeczytać, co to jest.
open_max = sysconf(_SC_OPEN_MAX);
To nie jest takie trudne, jest sysconf(3) sposób uzyskania limitu.

ENFILE, Zbyt wiele koncepcja pliki in system
Ten błąd występuje, gdy systemowy limit całkowitej liczby otwartych plików został przekroczony
osiągnięty. W tym wypadku nie ma rady sysconf(3) sposób uzyskania limitu.

Kopiąc głębiej, można odkryć, że w systemie Linux istnieje / proc wpis, do którego mogliśmy przeczytać
uzyskać tę wartość. Paragraf 22: skończyły nam się deskryptory plików, więc nie możemy otworzyć pliku
przeczytaj limit.

W Linuksie istnieje wywołanie systemowe umożliwiające jego uzyskanie, ale nie ma ono funkcji opakowania [e]glibc, więc
musisz to wszystko bardzo ostrożnie:
długie
wyjaśnij_maxfile(void)
{
#ifdef __linux__
struktura __sysctl_args argumenty;
int32_t maksymalny plik;
rozmiar_t maks. rozmiar_pliku = rozmiar(maxplik);
int nazwa[] = {CTL_FS, FS_MAXFILE };
memset(&args, 0, sizeof(struct __sysctl_args));
args.name = nazwa;
args.nlen = 2;
args.oldval = &maxfile;
args.oldlenp = &maxfile_size;
if (syscall(SYS__sysctl, &args) >= 0)
zwróć maksymalny plik;
#endif
return -1;
}
Umożliwia to uwzględnienie limitu w komunikacie o błędzie, jeśli jest dostępny.

WAL "Nieważny argument" vs ENOSYS "Funkcjonować nie wdrożony”
Nieobsługiwane akcje (takie jak dowiązanie symboliczne(2) w systemie plików FAT) nie są zgłaszane
konsekwentnie od jednego wywołania systemowego do następnego. Możliwe jest użycie EINVAL lub
ENOSYS powrócił.

W rezultacie należy zwrócić szczególną uwagę na te przypadki błędów, aby je naprawić
ponieważ EINVAL może również odnosić się do problemów z jednym lub większą liczbą argumentów wywołania systemowego.

Note że errno(3) is nie zawsze zestaw
Są chwile, kiedy konieczne jest przeczytanie źródeł [e]glibc, aby ustalić, w jaki sposób i
gdy zwracane są błędy dla niektórych wywołań systemowych.

feof(3) plik numer(3)
Często zakłada się, że funkcje te nie mogą zwrócić błędu. Jest to prawdą tylko wtedy, gdy
dotychczasowy strumień argument jest ważny, jednak są w stanie wykryć nieprawidłowy
wskaźnik.

fpathconf(3) ścieżka konf(3)
Zwracana wartość fpathconf(2) i ścieżka konf(2) może legalnie wynosić -1, więc tak jest
trzeba zobaczyć, czy errno(3) zostało wyraźnie określone.

ioctls(2)
Zwracana wartość ioctls(2) może legalnie wynosić -1, więc konieczne jest sprawdzenie, czy
errno(3) zostało wyraźnie określone.

readdiru(3)
Zwracana wartość readdiru(3) ma wartość NULL zarówno dla błędów, jak i dla końca pliku. To jest
trzeba zobaczyć, czy errno(3) zostało wyraźnie określone.

ustaw(3) ustaw bufor(3) ustaw linię buf(3) ustaw buf(3)
Wszystkie oprócz ostatniej z tych funkcji zwracają wartość void. I ustaw buf(3) jest udokumentowane jedynie jako
zwracanie wartości „niezerowej” w przypadku błędu. Trzeba zobaczyć, czy errno(3) zostało wyraźnie określone
ustawiony.

strzod(3) strtol(3) powiedział(3) strtoll(3) strtuul(3) strtoull(3)
Funkcje te zwracają 0 w przypadku błędu, ale jest to również prawidłowa wartość zwracana. To jest
trzeba zobaczyć, czy errno(3) zostało wyraźnie określone.

ungetc(3)
Chociaż standard ANSI C wymaga tylko jednego znaku kopii zapasowej, to się zmienia
okazuje się, że [e]glibc pozwala na więcej... ale to oznacza, że ​​może zawieść w przypadku ENOMEM. To może
również kończy się niepowodzeniem w przypadku EBADF if fp jest fałszywe. Najtrudniejsze ze wszystkich, jeśli przekażesz EOF błąd
return następuje, ale errno nie jest ustawione.

Biblioteka libexplain poprawnie wykrywa wszystkie te błędy, nawet w przypadkach, gdy plik
wartości błędów są słabo udokumentowane, jeśli w ogóle.

ENOSPC, Nie przestrzeń lewo on urządzenie
Gdy ten błąd odnosi się do pliku w systemie plików, biblioteka libexplain drukuje podłączenie
punkt systemu plików, w którym występuje problem. Może to znacznie ujawnić źródło błędu
jaśniej.
zapis (fildes = 1 „przykład”, dane = 0xbfff2340, rozmiar_danych = 5) nie powiodło się, brak miejsca
na urządzeniu (28, ENOSPC), ponieważ system plików zawierający pliki („/ Home") nie ma
więcej miejsca na dane
W miarę dodawania większej liczby specjalnych obsługi urządzeń oczekuje się, że komunikaty o błędach będą obejmować urządzenie
nazwę i rzeczywisty rozmiar urządzenia.

EROFS, Tylko czytać filet system
Gdy ten błąd odnosi się do pliku w systemie plików, biblioteka libexplain drukuje podłączenie
punkt systemu plików, w którym występuje problem. Może to znacznie ujawnić źródło błędu
jaśniej.

W miarę dodawania większej liczby specjalnych obsługi urządzeń oczekuje się, że komunikaty o błędach będą obejmować urządzenie
nazwa i typ.
open(pathname = "/dev/fd0", O_RDWR, 0666) nie powiodło się, system plików tylko do odczytu (30, EROFS)
ponieważ dyskietka ma ustawioną zakładkę chroniącą przed zapisem

...ponieważ CD-ROM nie nadaje się do zapisu
...ponieważ karta pamięci ma ustawioną zakładkę chroniącą przed zapisem
...ponieważ taśma magnetyczna ½ cala nie posiada pierścienia zapisującego

przemianować
Połączenia przemianować(2) wywołanie systemowe służy do zmiany lokalizacji lub nazwy pliku, przenoszenia go
w razie potrzeby między katalogami. Jeśli docelowa nazwa ścieżki już istnieje, tak będzie
zastąpione atomowo, tak że nie ma punktu, w którym inny proces próbuje to zrobić
uzyskaj dostęp, okaże się, że go brakuje.

Istnieją jednak ograniczenia: nazwę katalogu można zmieniać tylko na innym
katalog, jeśli katalog docelowy nie jest pusty.
rename(oldpath = "foo", newpath = "bar") nie powiodło się, katalog nie jest pusty (39,
ENOTEMPTY), ponieważ nowa ścieżka nie jest pustym katalogiem; to znaczy zawiera wpisy
inny niż "." I ".."
Nie można także zmienić nazwy katalogu znajdującego się na katalogu niebędącym katalogiem.
rename(oldpath = "foo", newpath = "bar") nie powiodło się, to nie jest katalog (20, ENOTDIR)
ponieważ stara ścieżka jest katalogiem, ale nowa ścieżka jest zwykłym plikiem, a nie katalogiem
Nie jest też dozwolone odwrotność
rename(oldpath = "foo", newpath = "bar") nie powiodło się, jest katalogiem (21, EISDIR)
ponieważ nowa ścieżka jest katalogiem, ale stara ścieżka jest zwykłym plikiem, a nie katalogiem

To oczywiście komplikuje pracę biblioteki libexplain, ponieważ plik
odczepić(2) lub rmdir(2) wywołanie systemowe jest wywoływane niejawnie przez przemianować(2) i tak wszystko
odczepić(2) lub rmdir(2) Należy również wykrywać i obsługiwać błędy.

dup2
Połączenia dup2(2) wywołanie systemowe służy do utworzenia drugiego deskryptora pliku, który odwołuje się do
ten sam obiekt co pierwszy deskryptor pliku. Zwykle służy to do implementowania danych wejściowych powłoki
i przekierowanie wyjścia.

Zabawne jest to, że tak samo przemianować(2) może atomowo zmienić nazwę pliku na
istniejący plik i usuń stary plik, dup2(2) może to zrobić na już otwartym pliku
deskryptor.

Po raz kolejny komplikuje to zadanie biblioteki libexplain, ponieważ plik zamknięte(2)
wywołanie systemowe jest wywoływane niejawnie przez dup2(2) i tak dalej zamknięteBłędy (2) muszą być
również wykryte i obsługiwane.

PRZYGODY IN IOCTL WSPIERAJ


Połączenia ioctls(2) wywołanie systemowe zapewnia autorom sterowników urządzeń możliwość komunikacji
przestrzeń użytkownika, która nie mieści się w istniejącym API jądra. Widzieć ioctl_list(2).

Rozszyfrowanie PROŚBA Liczby
Z pobieżnego spojrzenia na ioctls(2) interfejs, wydaje się, że jest duży, ale skończony
ilość możliwych ioctls(2) prośby. Każdy inny ioctls(2) żądanie jest skuteczne
kolejne wywołanie systemowe, ale bez żadnego zabezpieczenia typu - kompilator nie może pomóc
programista, zrób to dobrze. Prawdopodobnie taka była motywacja tcflush(3) i
przyjaciele.

Pierwsze wrażenie jest takie, że można rozszyfrować ioctls(2) żądania przy użyciu ogromnego przełącznika
oświadczenie. Okazuje się to niewykonalne, gdyż bardzo szybko odkrywa się, że tak jest
niemożliwe jest uwzględnienie wszystkich niezbędnych nagłówków systemowych definiujących różne ioctls(2)
prośby, ponieważ ciężko im się ze sobą dobrze bawić.

Głębsze spojrzenie ujawnia, że ​​istnieje szereg „prywatnych” numerów żądań i urządzeń
Zachęcamy autorów sterowników do korzystania z nich. Oznacza to, że możliwe jest znacznie większe
zestaw żądań z niejednoznacznymi numerami żądań, niż jest to od razu widoczne. Również,
istnieją również pewne niejasności historyczne.

Wiedzieliśmy już, że przełącznik jest niepraktyczny, ale teraz wiemy, że aby wybrać
odpowiednią nazwę wniosku i wyjaśnienie, musimy wziąć pod uwagę nie tylko numer wniosku, ale
także deskryptor pliku.

Implementacja ioctls(2) obsługa w bibliotece libexplain polega na posiadaniu tabeli
wskazuje na ioctls(2) deskryptory żądania. Każdy z tych deskryptorów zawiera opcję opcjonalną
wskaźnik do funkcji ujednoznaczniającej.

Każde żądanie jest faktycznie realizowane w osobnym pliku źródłowym, dzięki czemu niezbędne
include są zwolnione z obowiązku dobrej zabawy z innymi.

Reprezentacja
Filozofią stojącą za biblioteką libexplain jest dostarczanie jak największej ilości informacji
możliwe, łącznie z dokładną reprezentacją wywołania systemowego. W przypadku
ioctls(2) oznacza to wydrukowanie prawidłowego numeru żądania (według nazwy), a także prawidłowego (lub
przynajmniej użyteczna) reprezentacja trzeciego argumentu.

Połączenia ioctls(2) prototyp wygląda następująco:
int ioctl(int fildes, int żądanie, ...);
co powinno spowodować włączenie alarmów bezpieczeństwa typu. Wewnętrznie w [e]glibc, to jest włączone
w różnych formach:
int __ioctl(int fildes, int żądanie, długi argument);
int __ioctl(int fildes, int żądanie, void *arg);
i oczekuje tego interfejs wywołań systemowych jądra Linux
asmlinkage long sys_ioctl(unsigned int fildes, unsigned int request, unsigned long
argument);
Ekstremalna zmienność trzeciego argumentu stanowi wyzwanie, gdy biblioteka libexplain
próbuje wydrukować reprezentację tego trzeciego argumentu. Jednakże, gdy numer żądania
zostało ujednoznacznione, każdy wpis w tabeli ioctl biblioteki libexplain ma plik
niestandardowa funkcja print_data (OO wykonana ręcznie).

Wyjaśnienia
Jest mniej problemów z określeniem wyjaśnienia, które należy zastosować. Po numerze żądania
zostało ujednoznacznione, każdy wpis w tabeli ioctl biblioteki libexplain ma swój zwyczaj
funkcja print_explanation (ponownie OO wykonana ręcznie).

W przeciwieństwie do wywołań systemowych sekcji 2 i 3, większość ioctls(2) żądania nie zawierają błędów
udokumentowane. Oznacza to, że aby dobrze opisać błędy, konieczne jest przeczytanie jądra
źródła do odkrycia

· Co errno(3) mogą zostać zwrócone wartości oraz

· przyczynę każdego błędu.

Ze względu na naturę OO wywoływania funkcji w jądrze, musisz przeczytać
cała kolekcja źródła to wdrażające ioctls(2) żądanie, a nie tylko ogólna implementacja. To
należy się spodziewać, że różne jądra będą miały różne numery błędów i to w sposób subtelny
różne przyczyny błędów.

WAL vs ENOTTY
Sytuacja jest jeszcze gorsza ioctls(2) żądania niż w przypadku wywołań systemowych z EINVAL i
ENOTTY oba są używane do wskazania, że ioctls(2) żądanie jest w tym zakresie niewłaściwe
kontekście, a czasami ENOSYS, ENOTSUP i EOPNOTSUPP (przeznaczone do użycia dla gniazd) jako
Dobrze. W źródłach jądra Linuksa znajdują się komentarze, które wydają się wskazywać na postęp
sprzątanie jest w toku. Aby uzyskać dodatkowy chaos, BSD dodaje ENIOIOCTL do zamieszania.

W rezultacie należy zwrócić szczególną uwagę na te przypadki błędów, aby je naprawić
ponieważ EINVAL może również odnosić się do problemów z jednym lub większą liczbą argumentów wywołania systemowego.

intptr_t
Standard C99 definiuje typ całkowity, który gwarantuje, że będzie w stanie pomieścić dowolny wskaźnik
bez utraty reprezentacji.

Powyższy prototyp wywołania systemowego funkcji byłby lepiej napisany
long sys_ioctl(unsigned int fildes, unsigned int request, intptr_t arg);
Problemem jest dysonans poznawczy wywołany przez specyficzne urządzenie lub system plików
ioctls(2) wdrożenia, takie jak:
long vfs_ioctl(plik struktury *filp, unsigned int cmd, unsigned long arg);
Wiekszosc z ioctls(2) żądania faktycznie mają trzeci argument int *arg. Ale mieć to
zadeklarowany jako long prowadzi do tego, że kod traktuje to jako długie *arg. Jest to nieszkodliwe w systemie 32-bitowym
(sizeof(long) == sizeof(int)), ale paskudnie na 64-bitach (sizeof(long) != sizeof(int)).
W zależności od endianowości otrzymujesz lub nie wartość, której oczekujesz, ale ty zawsze otrzymać
bazgroły pamięciowe lub bazgroły stosowe.

Zapisując to wszystko jako
int ioctl(int fildes, int żądanie, ...);
int __ioctl(int fildes, int żądanie, intptr_t arg);
long sys_ioctl(unsigned int fildes, unsigned int request, intptr_t arg);
long vfs_ioctl(plik struktury *filp, unsigned int cmd, intptr_t arg);
podkreśla, że ​​liczba całkowita jest tylko liczbą całkowitą reprezentującą wielkość prawie
zawsze niepowiązany typ wskaźnika.

WNIOSEK


Użyj libexplain, Twoim użytkownikom się spodoba.

PRAWA AUTORSKIE


wersja libexplain 1.4
Prawa autorskie (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Peter Miller

Skorzystaj z wyjaśniania_lca2010 online, korzystając z usług onworks.net


Darmowe serwery i stacje robocze

Pobierz aplikacje Windows i Linux

  • 1
    HAUST
    HAUST
    SWIG to narzędzie do tworzenia oprogramowania
    która łączy programy napisane w C i
    C++ z różnymi wysokopoziomowymi
    języki programowania. SWIG jest używany z
    różne...
    Pobierz SWIG
  • 2
    Motyw WooCommerce Nextjs React
    Motyw WooCommerce Nextjs React
    Motyw React WooCommerce, zbudowany z
    Następny JS, Webpack, Babel, Node i
    Express, używając GraphQL i Apollo
    Klient. Sklep WooCommerce w React(
    zawiera: Produkty...
    Pobierz motyw WooCommerce Nextjs React
  • 3
    archlabs_repo
    archlabs_repo
    Repozytorium pakietów dla ArchLabs To jest plik
    aplikacja, którą można również pobrać
    od
    https://sourceforge.net/projects/archlabs-repo/.
    Został on hostowany w OnWorks w...
    Pobierz archlabs_repo
  • 4
    Projekt Zefir
    Projekt Zefir
    Projekt Zephyr to nowa generacja
    system operacyjny czasu rzeczywistego (RTOS).
    obsługuje wiele urządzeń
    architektury. Opiera się na A
    małe jądro...
    Pobierz projekt Zephyr
  • 5
    Scons
    Scons
    SCons to narzędzie do tworzenia oprogramowania
    jest lepszą alternatywą dla
    klasyczne narzędzie do budowania „Make”.
    wszyscy znamy i kochamy. SCons jest
    wdrożył...
    Pobierz SCons
  • 6
    PSeInt
    PSeInt
    PSeInt to interpreter pseudokodu dla
    hiszpańskojęzyczni studenci programowania.
    Jego głównym celem jest bycie narzędziem do
    nauka i zrozumienie podstaw
    koncepcja...
    Pobierz PSeInt
  • więcej »

Komendy systemu Linux

Ad