InglêsFrancêsEspanhol

Ad


favicon do OnWorks

explica_lca2010 - On-line na Nuvem

Execute explica_lca2010 no provedor de hospedagem gratuita OnWorks no Ubuntu Online, Fedora Online, emulador online do Windows ou emulador online do MAC OS

Este é o comando explica_lca2010 que pode ser executado no provedor de hospedagem gratuita OnWorks usando uma de nossas múltiplas estações de trabalho online gratuitas, como Ubuntu Online, Fedora Online, emulador online de Windows ou emulador online de MAC OS

PROGRAMA:

NOME


explica_lca2010 - Nenhuma mídia encontrada: quando é hora de parar de tentar ler Strerror(3) de
mente.

MOTIVAÇÃO


A ideia do libexplain me ocorreu no início dos anos 1980. Sempre que uma chamada do sistema
retorna um erro, o kernel sabe exatamente o que deu errado... e compacta isso em
menos de 8 bits de erro. O espaço do usuário tem acesso aos mesmos dados que o kernel,
deve ser possível para o espaço do usuário descobrir exatamente o que aconteceu para provocar o erro
retorne e use isso para escrever boas mensagens de erro.

Poderia ser assim tão simples?

erro mensagens as sutileza
Boas mensagens de erro geralmente são aquelas tarefas de “um por cento” que são descartadas quando agendadas.
a pressão comprime seu projeto. No entanto, uma boa mensagem de erro pode causar um grande impacto,
melhoria desproporcional à experiência do usuário, quando o usuário entra em situações assustadoras
território desconhecido normalmente não encontrado. Esta não é uma tarefa fácil.

Como um programador larval, o autor não viu o problema com o erro (completamente preciso)
mensagens como esta:
exceção flutuante (núcleo despejado)
até que a interpretação alternativa do não programador fosse apontada. Mas isso não é o
única coisa errada com mensagens de erro do Unix. Com que frequência você vê mensagens de erro como:
$ ./estúpido
não consigo abrir o arquivo
$
Existem duas opções para um desenvolvedor neste momento:

1.
você pode executar um depurador, como gdb(1) ou

2.
você pode usar traço(1) ou treliça(1) olhar para dentro.

· Lembre-se de que seus usuários podem nem ter acesso a essas ferramentas, muito menos a capacidade
para usá-los. (Já faz muito tempo que Unix beginner significava “só escreveu um
driver do dispositivo".)

Neste exemplo, no entanto, usando traço(1) revela
$ traço -e rastreamento=aberto ./estúpido
open("algum/arquivo", O_RDONLY) = -1 ENOENT (Esse arquivo ou diretório não existe)
não consigo abrir o arquivo
$
Isso é consideravelmente mais informação do que a mensagem de erro fornece. Normalmente, o
código-fonte estúpido se parece com isso
int fd=aberto("algo", O_RDONLY);
se (fd < 0)
{
fprintf(stderr, "não é possível abrir arquivo\n");
saída(1);
}
O usuário não é informado qual arquivo e também não informa ao usuário qual erro. Foi o arquivo
mesmo lá? Houve um problema de permissões? Ele diz que estava tentando abrir um
arquivo, mas isso provavelmente foi por acidente.

Pegue seu bastão de dicas e derrote o programador larval com ele. Conte a ele sobre erro(3).
Na próxima vez que você usar o programa, você verá uma mensagem de erro diferente:
$ ./estúpido
open: Esse arquivo ou diretório não existe
$
Progresso, mas não o que esperávamos. Como o usuário pode resolver o problema se a mensagem de erro
não conta a ele qual era o problema? Olhando para a fonte, vemos
int fd=aberto("algo", O_RDONLY);
se (fd < 0)
{
erro("aberto");
saída(1);
}
É hora de outra corrida com o bastão de dicas. Desta vez, a mensagem de erro dá um passo
para frente e um passo para trás:
$ ./estúpido
algo: Não existe tal arquivo ou diretório
$
Agora sabemos o arquivo que ele estava tentando abrir, mas não somos mais informados de que foi aberto(2)
isso falhou. Neste caso, provavelmente não é significativo, mas pode ser significativo para
outras chamadas do sistema. Isso poderia ter sido creat(2) em vez disso, uma operação que implica que
permissões diferentes são necessárias.
const char *nome do arquivo = "algo";
int fd = open(nome do arquivo, O_RDONLY);
se (fd < 0)
{
erro(nome do arquivo);
saída(1);
}
Infelizmente, o código de exemplo acima também é típico de programadores não larvais. Tempo
para contar ao nosso aluno padawan sobre o Strerror(3) chamada de sistema.
$ ./estúpido
aberto algo: Não existe tal arquivo ou diretório
$
Isso maximiza as informações que podem ser apresentadas ao usuário. O código parece
esta:
const char *nome do arquivo = "algo";
int fd = open(nome do arquivo, O_RDONLY);
se (fd < 0)
{
fprintf(stderr, "abrir %s: %s\n", nome do arquivo, strerror(errno));
saída(1);
}
Agora temos a chamada do sistema, o nome do arquivo e a string de erro. Este contém todos os
informações que traço(1) impresso. Isso é o melhor que pode acontecer.

Ou é?

Limitações of erro e Strerror
O problema que o autor viu, na década de 1980, foi que a mensagem de erro estava incompleta.
“Nenhum arquivo ou diretório” refere-se ao “alguns”Diretório ou para o“coisa" arquivo em
a "alguns”diretório?

Uma rápida olhada na página de manual do Strerror(3) está dizendo:
strerror - retorna string descrevendo o número do erro
Observe bem: está descrevendo o erro número, não o erro.

Por outro lado, o núcleo sabe qual foi o erro. Houve um ponto específico no
código do kernel, causado por uma condição específica, onde o código do kernel ramificou e disse “não”.
Um programa de espaço do usuário poderia descobrir a condição específica e escrever um erro melhor
mensagem?

No entanto, o problema é mais profundo. E se o problema ocorrer durante o ler(2) sistema
ligar, em vez de aberto(2) ligar? É simples para a mensagem de erro associada ao
aberto(2) para incluir o nome do arquivo, está ali. Mas para poder incluir um nome de arquivo
no erro associado ao ler(2) chamada de sistema, você deve passar o nome do arquivo para todos
o caminho para baixo na pilha de chamadas, bem como o descritor de arquivo.

E aqui está a parte que irrita: o kernel já sabe qual nome de arquivo o arquivo
descritor está associado. Por que um programador deveria passar dados redundantes
descer na pilha de chamadas apenas para melhorar uma mensagem de erro que talvez nunca seja emitida? Em
realidade, muitos programadores não se preocupam e as mensagens de erro resultantes são piores para
.

Mas isso foi na década de 1980, num PDP11, com recursos limitados e sem bibliotecas partilhadas. Voltar
então, nenhum sabor de Unix incluído / proc mesmo em forma rudimentar, e o lsof(1) programa
estava a mais de uma década de distância. Portanto, a ideia foi arquivada como impraticável.

Nível Infinity Suporte
Imagine que você está no nível de suporte infinito. A descrição do seu trabalho diz que você nunca
sempre tem que falar com os usuários. Por que, então, ainda existe um fluxo constante de pessoas querendo
você, o guru local do Unix, para decifrar mais uma mensagem de erro?

Estranhamente, 25 anos depois, apesar de um sistema de permissões simples, implementado com total
consistência, a maioria dos usuários Unix ainda não tem ideia de como decodificar “Nenhum arquivo ou diretório”,
ou qualquer outra mensagem de erro enigmática que eles veem todos os dias. Ou, pelo menos, enigmático para
Eles.

Não seria bom se o suporte técnico de primeiro nível não precisasse decifrar mensagens de erro?
Não seria bom ter mensagens de erro que os usuários pudessem entender sem ligar
suporte técnico?

Nos dias de hoje / proc no Linux é mais do que capaz de fornecer as informações necessárias para decodificar
a grande maioria das mensagens de erro e apontam ao usuário a causa imediata de sua
problema. Em sistemas com um limite / proc implementação, o lsof(1) comando pode preencher
muitas das lacunas.

Em 2008, o fluxo de pedidos de tradução acontecia com muita frequência ao autor. Era
É hora de reexaminar essa ideia de 25 anos e o resultado é libexplain.

USANDO A BIBLIOTECA


A interface da biblioteca tenta ser consistente, sempre que possível. Vamos começar com um
exemplo usando Strerror(3)
if (renomear(caminho_antigo, caminho_novo) <0)
{
fprintf(stderr, "renomear %s %s: %s\n", caminho_antigo, caminho_novo,
strerror(errno));
saída(1);
}
A idéia por trás do libexplain é fornecer um Strerror(3) equivalente para cada chamada de sistema,
adaptado especificamente para essa chamada de sistema, para que possa fornecer um erro mais detalhado
mensagem, contendo muitas das informações que você vê sob o título “ERROS” da seção
2 e 3 homem páginas, complementadas com informações sobre condições reais, argumentos reais
valores e limites do sistema.

A simples Estudos de
A Strerror(3) substituição:
if (renomear(caminho_antigo, caminho_novo) <0)
{
fprintf(stderr, "%s\n", explicação_renome(caminho_antigo, caminho_novo));
saída(1);
}

A Erro Estudos de
Também é possível passar um explícito erro(3) valor, se você precisar primeiro fazer algumas
processamento que perturbaria erro, como recuperação de erros:
if (renomear(caminho_antigo, caminho_novo < 0))
{
int velho_errno = errno;
...código que perturba erro...
fprintf(stderr, "%s\n",explique_errno_rename(old_errno,
caminho_antigo, caminho_novo));
saída(1);
}

A Multi fio Cases
Algumas aplicações são multithread e, portanto, não conseguem compartilhar os recursos internos do libexplain.
amortecedor. Você pode fornecer seu próprio buffer usando
if (desvincular (nome do caminho))
{
mensagem de caractere[3000];
explica_message_unlink(mensagem, tamanho(mensagem), nome do caminho);
erro_dialog(mensagem);
retornar -1;
}
E para completar, ambos erro(3) e thread-safe:
ssize_t nbytes = leitura(fd, dados, sizeof(dados));
se (nbytes <0)
{
mensagem de caractere[3000];
int velho_errno = errno;
...erro recuperação...
explica_message_errno_read(mensagem, tamanho(mensagem),
old_errno, fd, dados, sizeof(dados));
erro_dialog(mensagem);
retornar -1;
}

Estes são substitutos para strerror_r(3), em sistemas que o possuem.

Interface Açucar
Um conjunto de funções adicionadas como funções de conveniência, para atrair os programadores para usar o
biblioteca libexplain, acabam sendo as funções libexplain mais comumente usadas pelo autor em
programas de linha de comando:
int fd = explica_criar_ou_die(nome do arquivo, 0666);
Esta função tenta criar um novo arquivo. Se não puder, ele imprime uma mensagem de erro e
sai com EXIT_FAILURE. Se não houver erro, ele retornará o novo descritor de arquivo.

Uma função relacionada:
int fd = explica_creat_on_error(nome do arquivo, 0666);
imprimirá a mensagem de erro em caso de falha, mas também retornará o resultado do erro original e
erro(3) também não é molestado.

Todos os Produtos que o de outros . chamadas
Em geral, cada chamada de sistema possui seu próprio arquivo de inclusão
#incluirnome.h>
que define protótipos de funções para seis funções:

· explicar_nome,

· explicar_errno_nome,

· explicar_mensagem_nome,

· explica_mensagem_errno_nome,

· explicar_nome_ou_morra e

· explicar_nome_on_error.

Cada protótipo de função possui documentação Doxygen, e esta documentação is não despojado
quando os arquivos de inclusão são instalados.

A esperar(2) a chamada do sistema (e amigos) tem algumas variantes extras que também interpretam a falha
para ser um status de saída que não seja EXIT_SUCCESS. Isso se aplica á .(3) e perto(3) como
bem.

A cobertura inclui 221 chamadas de sistema e 547 solicitações ioctl. Existem muitos mais sistemas
chamadas ainda a implementar. Chamadas do sistema que nunca retornam, como saída(2), não estão presentes
na biblioteca, e nunca estará. O exec família de chamadas de sistema e guarante que os mesmos estão apoiado, porque
eles retornam quando há um erro.

Gato
Isto é o que um hipotético programa “gato” poderia parecer, com relatórios completos de erros,
usando libexplain.
#include
#incluir
#incluir
Existe uma inclusão para libexplain, além dos suspeitos do costume. (Se você deseja reduzir o
carga do pré-processador, você pode usar o <libexplain/ específiconome.h> inclui.)
vazio estático
processo(ARQUIVO *fp)
{
para (;;)
{
buffer de char [4096];
size_t n = explica_fread_or_die(buffer, 1, sizeof(buffer), fp);
se (!n)
break;
explicar_fwrite_or_die(buffer, 1, n, stdout);
}
}
A processo função copia um fluxo de arquivo para a saída padrão. Caso ocorra um erro
para leitura ou escrita, é relatado (e o nome do caminho será incluído no
erro) e o comando sai com EXIT_FAILURE. Nós nem nos preocupamos em rastrear o
nomes de caminhos ou transmiti-los pela pilha de chamadas.
int
principal(int argc,char **argv)
{
para (;;)
{
int c = getopt(argc, argv, "o:");
se (c == EOF)
break;
interruptor (c)
{
caso 'o':
explica_freopen_or_die(optarg, "w", stdout);
break;
A parte divertida deste código é que o libexplain pode reportar erros incluam que o pathname até
se você não reabra explicitamente o stdout como é feito aqui. Nós nem nos preocupamos com
rastreando o nome do arquivo.
default:
fprintf(stderr, "Uso: %ss [ -o ] ...\n",
argv[0]);
retornar EXIT_FAILURE;
}
}
if (optar == argc)
processo(stdin);
outro
{
while (optind <argc)
{
ARQUIVO *fp = explica_fopen_or_die(argv[optind]++, "r");
processo(fp);
explicar_fclose_or_die(fp);
}
}
A saída padrão será fechada implicitamente, mas tarde demais para que um relatório de erro seja
emitido, então fazemos isso aqui, caso a E/S em buffer ainda não tenha escrito nada, e
há um erro ENOSPC ou algo assim.
explica_fflush_or_die(stdout);
retornar EXIT_SUCCESS;
}
Isso é tudo. Relatório completo de erros, código claro.

Rusty's Escala of Interface Bondade
Para aqueles que não estão familiarizados com ele, “How Do I Make This Hard to Misuse?” de Rusty Russel?
página é uma leitura obrigatória para designers de API.
http://ozlabs.org/~rusty/index.cgi/tech/2008‐03‐30.html

10. É impossível para ter errado.

As metas precisam ser estabelecidas altas, ambiciosamente altas, para que você não as alcance e pense que está
terminou quando você não está.

A biblioteca libexplain detecta ponteiros falsos e muitos outros parâmetros falsos de chamadas de sistema,
e geralmente tenta evitar falhas de segurança mesmo nas circunstâncias mais difíceis.

A biblioteca libexplain foi projetada para ser thread-safe. Mais uso no mundo real provavelmente
revelar lugares onde isso pode ser melhorado.

O maior problema está nos próprios nomes das funções. Como C não tem
espaços de nomes, a biblioteca libexplain sempre usa um prefixo de nome explica_. Isto é o
maneira tradicional de criar um pseudoespaço de nomes para evitar conflitos de símbolos.
No entanto, isso resulta em alguns nomes que soam pouco naturais.

9. A compilador or vinculador não vai deixar Você ter it errado.

Um erro comum é usar explica_open onde explica_open_or_die foi planejado.
Felizmente, o compilador frequentemente emitirá um erro de tipo neste ponto (por exemplo, não consigo atribuir
const char * rvalue para um int lvalue).

8. A compilador precisarão avisar if Você ter it errado.

Se explica_renome for usado quando explica_renome_or_die foi planejado, isso pode causar outros
problemas. O GCC possui um atributo de função warning_unused_result útil e o libexplain
biblioteca anexa-o a todos os explica_nome chamadas de função para produzir um aviso quando você
cometa esse erro. Combine isso com gcc -Erro para promover isso ao nível 9 de bondade.

7. A óbvio usar is (provavelmente) que o correta um.

Os nomes das funções foram escolhidos para transmitir o seu significado, mas isso nem sempre é
bem-sucedido. Enquanto explica_nome_ou_morra e explique_nome_on_error são bastante descritivos,
as variantes thread-safe menos usadas são mais difíceis de decodificar. Os protótipos de funções ajudam o
compilador para compreensão, e os comentários do Doxygen nos arquivos de cabeçalho ajudam o usuário
rumo à compreensão.

6. A nome conta Você como para usar .

É particularmente importante ler explicar_nome_or_die como “explicar (nome ou morra)".
Usar um prefixo de espaço de nomes explica_ consistente tem alguns efeitos colaterais infelizes no
departamento de obviedade também.

A ordem das palavras nos nomes também indica a ordem dos argumentos. O argumento
lista sempre final com os mesmos argumentos passados ​​para a chamada do sistema; todos os of eles. Se
_errno_ aparece no nome, seu argumento sempre precede os argumentos da chamada do sistema. Se
_message_ aparece no nome, seus dois argumentos sempre vêm primeiro.

5. Do it certo or it precisarão quebrar at tempo de execução.

A biblioteca libexplain detecta ponteiros falsos e muitos outros parâmetros falsos de chamadas de sistema,
e geralmente tenta evitar falhas de segurança mesmo nas circunstâncias mais difíceis. Deveria
nunca quebra em tempo de execução, mas um maior uso no mundo real sem dúvida melhorará isso.

Algumas mensagens de erro são direcionadas a desenvolvedores e mantenedores, e não a usuários finais, pois isso
pode ajudar na resolução de bugs. Não tanto “interromper em tempo de execução”, mas “ser informativo em
runtime” (após a chamada do sistema vomitar).

4. Siga-nos comum convenção e você vai ter it certo.

Como C não possui espaços para nome, a biblioteca libexplain sempre usa um nome explicativo.
prefixo. Esta é a forma tradicional de criar um pseudoespaço de nomes para evitar
conflitos de símbolos.

Os argumentos finais de todas as chamadas do libexplain são idênticos à chamada do sistema que eles
estão descrevendo. O objetivo é fornecer uma convenção consistente em comum com o
o sistema chama a si mesmo.

3. Leia que o documentação e você vai ter it certo.

A biblioteca libexplain pretende ter documentação completa do Doxygen para cada
chamada de API pública (e também internamente).

MENSAGEM CONTEÚDOS


Trabalhar no libexplain é como olhar para a parte de baixo do seu carro quando ele está ligado
a talha no mecânico. Há algumas coisas feias lá embaixo, além de lama e sujeira, e
os usuários raramente o veem. Uma boa mensagem de erro precisa ser informativa, mesmo para um usuário que
teve a sorte de não ter que olhar para o lado de baixo com muita frequência, e também
informativo para o mecânico ouvir a descrição do usuário pelo telefone. Isso é
não é uma tarefa fácil.

Revisitando nosso primeiro exemplo, o código ficaria assim se usasse libexplain:
int fd = explicar_open_or_die("alguma/coisa", O_RDONLY, 0);
falhará com uma mensagem de erro como esta
open(pathname = "some/file", flags = O_RDONLY) falhou, arquivo ou diretório não encontrado
(2, ENOENT) porque não existe nenhum diretório "algum" no diretório atual
Isso se divide em três partes
chamada de sistema falhou, erro no sistema Porque
explicação

Antes Porque
É possível ver a parte da mensagem antes de “porque” como excessivamente técnica para não
usuários técnicos, principalmente como resultado da impressão precisa da própria chamada do sistema no
início da mensagem de erro. E parece traço(1) saída, para geek de bônus
pontos.
open(pathname = "some/file", flags = O_RDONLY) falhou, arquivo ou diretório não encontrado
(2, ENOENT)
Esta parte da mensagem de erro é essencial para o desenvolvedor quando ele está escrevendo o código,
e igualmente importante para o mantenedor que tem que ler relatórios de bugs e corrigir bugs no
código. Diz exatamente o que falhou.

Se este texto não for apresentado ao usuário, o usuário não poderá copiá-lo e colá-lo em um
relatório de bug, e se não estiver no relatório de bug, o mantenedor não pode saber o que realmente aconteceu
errado.

Freqüentemente, a equipe técnica usará traço(1) ou treliça(1) para obter esta informação exata, mas
este caminho não está aberto ao ler relatórios de bugs. O sistema do repórter de bugs está muito longe
longe e, agora, em um estado muito diferente. Assim, essas informações precisam estar no
relatório de bug, o que significa que deve estar na mensagem de erro.

A representação da chamada do sistema também fornece contexto ao restante da mensagem. Se precisar
surge, o argumento de chamada do sistema ofensivo pode ser referido pelo nome na explicação
depois de “porque”. Além disso, todas as strings são strings C totalmente entre aspas e com escape, então
novas linhas incorporadas e caracteres não imprimíveis não farão com que o terminal do usuário vá
confuso.

A erro no sistema é o que sai Strerror(2), mais o símbolo de erro. Impaciente e
administradores de sistemas especialistas poderiam parar de ler neste ponto, mas a experiência do autor até o momento é
que ler mais é gratificante. (Se não for gratificante, provavelmente é uma área de
libexplain que pode ser melhorado. Contribuições de código são bem-vindas, é claro.)

Depois de Porque
Esta é a parte da mensagem de erro destinada a usuários não técnicos. Parece além
os argumentos simples de chamada do sistema e procura algo mais específico.
não há diretório "algum" no diretório atual
Esta parte tenta explicar a causa proximal do erro em linguagem simples e
é aqui que a internacionalização é essencial.

Em geral, a política é incluir o máximo de informações possível, para que o usuário
não precisa procurá-lo (e não o deixa fora do relatório de bug).

Internacionalização
A maioria das mensagens de erro na biblioteca libexplain foram internacionalizadas. Lá
ainda não há localizações, então se você quiser explicações em seu idioma nativo,
por favor contribua.

O qualificador “a maior parte”, acima, está relacionado ao fato de que a prova de conceito
a implementação não incluiu apoio à internacionalização. A base de código está sendo
revisado progressivamente, geralmente como resultado da refatoração de mensagens para que cada erro
string de mensagem aparece no código exatamente uma vez.

Foram previstas linguagens que precisam montar as partes do
chamada de sistema falhou, erro no sistema Porque explicação
em ordens diferentes para corrigir a gramática em mensagens de erro localizadas.

Post-mortem
Há momentos em que um programa ainda não usou o libexplain e você não pode usar traço(1)
qualquer. Há um обяснявам(1) comando incluído no libexplain que pode ser usado para
decifrar mensagens de erro, se o estado do sistema subjacente não mudou muito.
$ обяснявам rebatizar Foo /tmp/bar/baz -e ENOENTE
rename(oldpath = "foo", newpath = "/tmp/bar/baz") falhou, esse arquivo ou diretório não existe
(2, ENOENT) porque não há diretório "bar" no newpath "/ Tmp"diretório
$
Observe como a ambigüidade do caminho é resolvida usando o nome do argumento da chamada do sistema. De
claro, você precisa conhecer o erro e a chamada do sistema para обяснявам(1) para ser útil. Como um
Além disso, esta é uma das maneiras usadas pelo conjunto de testes automáticos libexplain para verificar se
libexplain está funcionando.

Filosofia
“Conte-me tudo, inclusive coisas que eu não sabia que deveria procurar.”

A biblioteca é implementada de tal forma que, quando vinculada estaticamente, apenas o código que você
realmente usar estará vinculado. Isto é conseguido tendo uma função por arquivo de origem,
sempre que possível.

Quando for possível fornecer mais informações, o libexplain o fará. Quanto menos o usuário
tem que rastrear por si mesmos, melhor. Isto significa que os UIDs são acompanhados pelo
nome de usuário, GIDs são acompanhados pelo nome do grupo, PIDs são acompanhados pelo processo
nome, descritores de arquivo e fluxos são acompanhados pelo nome do caminho, etc..

Ao resolver caminhos, se um componente de caminho não existir, o libexplain procurará por componentes semelhantes
nomes, a fim de sugerir alternativas para erros tipográficos.

A biblioteca libexplain tenta usar o mínimo de heap possível, e geralmente nenhum. Isso é
para evitar perturbar o estado do processo, tanto quanto possível, embora às vezes seja
inevitável.

A biblioteca libexplain tenta ser thread-safe, evitando variáveis ​​globais, mantendo
estado na pilha tanto quanto possível. Existe um único buffer de mensagens comum e o
funções que o utilizam são documentadas como não sendo thread-safe.

A biblioteca libexplain não perturba os manipuladores de sinais de um processo. Isto faz
determinar se um ponteiro causaria uma falha de segurança em um desafio, mas não impossível.

Quando as informações estão disponíveis por meio de uma chamada de sistema, bem como por meio de um / proc
entrada, a chamada do sistema é preferida. Isso evita perturbar o estado do processo.
Também há momentos em que nenhum descritor de arquivo está disponível.

A biblioteca libexplain é compilada com suporte a arquivos grandes. Não existe grande/pequeno
esquizofrenia. Onde isso afetar os tipos de argumentos na API, um erro será emitido
se as definições de arquivos grandes necessárias estiverem ausentes.

FIXME: É necessário trabalhar para garantir que as cotas do sistema de arquivos sejam tratadas no código. Esse
aplica-se a alguns getrlimit(2) limites também.

Há casos em que os caminhos dos parentes não são informativos. Por exemplo: daemons do sistema,
servidores e processos em segundo plano. Nestes casos, caminhos absolutos são usados ​​no erro
explicações.

PATH RESOLUÇÃO


Versão curta: veja resolução_do_caminho(7).

Versão longa: a maioria dos usuários nunca ouviu falar resolução_do_caminho(7) e muitos usuários avançados
nunca li. Aqui está uma versão comentada:

Passo 1: Início of que o resolução processo
Se o nome do caminho começar com o caractere de barra (“/”), o diretório de pesquisa inicial será
o diretório raiz do processo de chamada.

Se o nome do caminho não começar com o caractere de barra (“/”), a pesquisa inicial
diretório do processo de resolução é o diretório de trabalho atual do processo.

Passo 2: Andar juntamente que o caminho
Defina o diretório de pesquisa atual como o diretório de pesquisa inicial. Agora, para cada não
componente final do nome do caminho, onde um componente é uma substring delimitada por barra (“/”)
caracteres, este componente é pesquisado no diretório de pesquisa atual.

Se o processo não tiver permissão de pesquisa no diretório de pesquisa atual, um EACCES
erro é retornado ("Permissão negada").
open(pathname = "/home/archives/.ssh/private_key", flags = O_RDONLY) falhou,
Permissão negada (13, EACCES) porque o processo não possui permissão de pesquisa
para o diretório "/home/archives/.ssh" do nome do caminho, o processo efetivo GID 1000
"pmiller" não corresponde ao proprietário do diretório 1001 "archives" então o proprietário
o modo de permissão "rwx" é ignorado, o modo de permissão dos outros é "---" e o modo de permissão
o processo não é privilegiado (não possui o recurso DAC_READ_SEARCH)

Se o componente não for encontrado, um erro ENOENT será retornado ("Esse arquivo ou diretório não existe").
unlink(pathname = "/home/microsoft/rubbish") falhou, esse arquivo ou diretório não existe (2,
ENOENT) porque não há diretório "microsoft" no nome do caminho "/ Home"diretório

Há também algum suporte para os usuários quando eles digitam nomes de caminho incorretamente, fazendo sugestões quando
ENOENT é retornado:
open(pathname = "/user/include/fcntl.h", flags = O_RDONLY) falhou, esse arquivo não existe ou
diretório (2, ENOENT) porque não há diretório "usuário" no nome do caminho "/"
diretório, você quis dizer o diretório "usr"?

Se o componente for encontrado, mas não for um diretório nem um link simbólico, um ENOTDIR
erro é retornado ("Não é um diretório").
open(pathname = "/home/pmiller/.netrc/lca", flags = O_RDONLY) falhou, não é um
diretório (20, ENOTDIR) porque o arquivo regular ".netrc" no nome do caminho
O diretório "/home/pmiller" está sendo usado como diretório quando não é

Se o componente for encontrado e for um diretório, definimos o diretório de pesquisa atual para aquele
diretório e vá para o próximo componente.

Se o componente for encontrado e for um link simbólico (link simbólico), primeiro resolvemos esse problema simbólico
link (com o diretório de pesquisa atual como diretório inicial de pesquisa). Em caso de erro, isso
erro é retornado. Se o resultado não for um diretório, um erro ENOTDIR será retornado.
unlink(pathname = "/tmp/dangling/rubbish") falhou, arquivo ou diretório inexistente (2,
ENOENT) porque o link simbólico "pendente" no nome do caminho "/ Tmp"diretório
refere-se a "lugar nenhum" que não existe
Se a resolução do link simbólico for bem-sucedida e retornar um diretório, definimos o atual
diretório de pesquisa para esse diretório e vá para o próximo componente. Observe que o
o processo de resolução aqui envolve recursão. Para proteger o kernel contra pilha
overflow, e também para proteger contra negação de serviço, existem limites no máximo
profundidade de recursão e no número máximo de links simbólicos seguidos. Um erro ELOOP é
retornado quando o máximo é excedido ("Muitos níveis de links simbólicos").
open(pathname = "/tmp/dangling", flags = O_RDONLY) falhou, muitos níveis de
links simbólicos (40, ELOOP) porque um loop de link simbólico foi encontrado em
nome do caminho, começando em "/tmp/dangling"
Também é possível obter um erro ELOOP ou EMLINK se houver muitos links simbólicos, mas nenhum
loop foi detectado.
open(pathname = "/tmp/rabbit‐hole", flags = O_RDONLY) falhou, muitos níveis de
links simbólicos (40, ELOOP) porque muitos links simbólicos foram encontrados em
nome do caminho (8)
Observe como o limite real também é impresso.

Passo 3: Encontre que o final entrada
A pesquisa do componente final do nome do caminho é igual a de todos os outros
componentes, conforme descrito na etapa anterior, com duas diferenças:

(i) O componente final não precisa ser um diretório (pelo menos no que diz respeito à resolução do caminho
processo está em causa. Pode ter que ser um diretório ou não-diretório, por causa de
os requisitos da chamada de sistema específica).

(Ii)
Não é necessariamente um erro se o componente final não for encontrado; talvez estejamos apenas
criando-o. Os detalhes sobre o tratamento da entrada final estão descritos no
páginas de manual das chamadas de sistema específicas.

(iii)
Também é possível ter problema com o último componente se for um link simbólico
e não deve ser seguido. Por exemplo, usando o aberto(2) Sinalizador O_NOFOLLOW:
open(pathname = "a‐symlink", flags = O_RDONLY | O_NOFOLLOW) falhou, muitos níveis de
links simbólicos (ELOOP) porque O_NOFOLLOW foi especificado, mas o nome do caminho se refere a um
link simbólico

(iv)
É comum que os usuários cometam erros ao digitar nomes de caminhos. A biblioteca libexplain
tenta fazer sugestões quando ENOENT é retornado, por exemplo:
open(pathname = "/usr/include/filecontrl.h", flags = O_RDONLY) falhou, esse arquivo não existe ou
diretório (2, ENOENT) porque não há arquivo regular "filecontrl.h" no nome do caminho
"/ usr / include", você quis dizer o arquivo regular "fcntl.h"?

(v) Também é possível que o componente final seja algo diferente de um
arquivo normal:
readlink(pathname = "just-a-file", data = 0x7F930A50, data_size = 4097) falhou,
Argumento inválido (22, EINVAL) porque o caminho é um arquivo normal, não um link simbólico

(VI)
FIXME: manipulação do bit "t".

Limites
Existem vários limites em relação a nomes de caminhos e nomes de arquivos.

Limite de comprimento do nome do caminho
Existe um comprimento máximo para nomes de caminho. Se o nome do caminho (ou algum intermediário
nome do caminho obtido ao resolver links simbólicos) é muito longo, um ENAMETOOLONG
erro é retornado ("Nome do arquivo muito longo"). Observe como o limite do sistema está incluído
na mensagem de erro.
abrir(nomedocaminho = "muito longo", flags = O_RDONLY) falhou, nome do arquivo muito longo (36,
ENAMETOOLONG) porque o nome do caminho excede o comprimento máximo do caminho do sistema (4096)

Limite de tamanho do nome do arquivo
Algumas variantes do Unix têm um limite no número de bytes em cada componente do caminho.
Alguns deles lidam com isso silenciosamente, e alguns dão ENAMETOOLONG; o libexplicar
usos da biblioteca caminhoconf(3) _PC_NO_TRUNC para saber qual. Se esse erro acontecer, o
A biblioteca libexplain indicará o limite na mensagem de erro, o limite é
obtido de caminhoconf(3) _PC_NAME_MAX. Observe como o limite do sistema está incluído
na mensagem de erro.
abrir(nomedocaminho = "sistema7/só tinha 14 caracteres", sinalizadores = O_RDONLY) falhou, arquivo
nome muito longo (36, ENAMETOOLONG) porque o componente "só tinha 14 caracteres" é
mais longo que o limite do sistema (14)

Nome de caminho vazio
No Unix original, o caminho vazio referia-se ao diretório atual.
Hoje em dia o POSIX decreta que um caminho vazio não deve ser resolvido com sucesso.
open(pathname = "", flags = O_RDONLY) falhou, arquivo ou diretório inexistente (2,
ENOENT) porque o POSIX decreta que um caminho vazio não deve ser resolvido
com sucesso

Permissões
Os bits de permissão de um arquivo consistem em três grupos de três bits. O primeiro grupo de
três é usado quando o ID do usuário efetivo do processo de chamada é igual ao ID do proprietário do
arquivo. O segundo grupo de três é usado quando o ID do grupo do arquivo é igual ao
ID de grupo efetivo do processo de chamada ou é um dos IDs de grupo suplementares do
processo de chamada. Quando nenhum dos dois é válido, o terceiro grupo é usado.
abrir(nomedocaminho = "/ Etc / passwd", flags = O_WRONLY) falhou, permissão negada (13,
EACCES) porque o processo não possui permissão de gravação no arquivo regular "passwd"
arquivo no nome do caminho "/ Etc" diretório, o processo efetivo UID 1000 "pmiller"
não corresponde ao proprietário do arquivo normal 0 "root", portanto o modo de permissão do proprietário "rw-"
é ignorado, o modo de permissão dos outros é "r--" e o processo não é privilegiado
(não possui o recurso DAC_OVERRIDE)
É dado algum espaço considerável a esta explicação, uma vez que a maioria dos utilizadores não sabe que esta
é como funciona o sistema de permissões. Em particular: o proprietário, o grupo e outros
as permissões são exclusivas, elas não são “OR” juntas.

ESTRANHO E INTERESSANTE SISTEMA CHAMADAS


O processo de escrever um manipulador de erros específico para cada chamada de sistema geralmente revela
peculiaridades interessantes e condições de limite, ou obscuras erro(3) valores.

ENÔMÉDIO, Não média encontrado
O ato de copiar um CD foi a fonte do título deste artigo.
$ dd if=/dev/cdrom de=fubar.iso
dd: abrindo “/dev/cdrom”: Nenhuma mídia encontrada
$
O autor se perguntou por que seu computador estava lhe dizendo que não existe vidente.
médio. Independentemente do facto de um grande número de falantes nativos de inglês não
mesmo ciente de que “mídia” é um plural, e muito menos que “meio” é seu singular, a string
devolvido por Strerror(3) para ENOMEDIUM é tão conciso que é quase completamente livre de
conteúdo.

Quando aberto(2) retorna ENOMEDIUM, seria bom se a biblioteca libexplain pudesse expandir um
pouco sobre isso, com base no tipo de unidade. Por exemplo:
... porque não há disco na unidade de disquete
... porque não há disco na unidade de CD-ROM
... porque não há fita na unidade de fita
... porque não há cartão de memória no leitor de cartão

E assim aconteceu...
open(pathname = "/dev/cdrom", flags = O_RDONLY) falhou, nenhuma mídia encontrada (123,
ENOMEDIUM) porque parece não haver um disco na unidade de CD-ROM
O truque, que o autor desconhecia anteriormente, era abrir o dispositivo usando o
Sinalizador O_NONBLOCK, que permitirá que você abra uma unidade sem mídia nela. Você então
emitir específico do dispositivo ioctl(2) solicitações até descobrir o que diabos é. (Não
claro se é POSIX, mas também parece funcionar assim no BSD e no Solaris, de acordo com
que o Wodim(1) fontes.)

Observe também os diferentes usos de “disco” e “disco” no contexto. O padrão CD originou-se
na França, mas todo o resto tem um “k”.

EFAULT, Mau endereço
Qualquer chamada de sistema que receba um argumento de ponteiro pode retornar EFAULT. A biblioteca libexplain
pode descobrir qual argumento está errado e faz isso sem perturbar o processo
(ou thread) manipulação de sinal.

Quando disponível, o mincore(2) é usada uma chamada de sistema para perguntar se a região da memória é válida.
Ele pode retornar três resultados: mapeado mas não na memória física, mapeado e na memória física
memória e não mapeado. Ao testar a validade de um ponteiro, os dois primeiros são “sim”
e o último é “não”.

Verificar strings C é mais difícil porque em vez de um ponteiro e um tamanho, nós apenas
tem um ponteiro. Para determinar o tamanho teríamos que encontrar o NUL, e isso poderia
segfault, catch-22.

Para contornar isso, a biblioteca libexplain usa o lstat(2) chamada de sistema (com um conhecido
bom segundo argumento) para testar a validade das strings C. Uma falha retorna && errno == EFAULT
é um “não” e qualquer outra coisa é um “sim”. É claro que isso limita as strings a PATH_MAX
caracteres, mas isso geralmente não é um problema para a biblioteca libexplain, porque isso é
quase sempre as cordas mais longas com as quais se preocupa.

EMFILE, Também muitos aberto arquivos
Este erro ocorre quando um processo já possui o número máximo de descritores de arquivo abertos.
Se o limite real for impresso e a biblioteca libexplain tentar fazê-lo, você não poderá abrir
um arquivo em / proc para ler o que é.
open_max = sysconf(_SC_OPEN_MAX);
Este não é tão difícil, há um sysconf(3) forma de obtenção do limite.

ENFILE, Também muitos aberto arquivos in .
Este erro ocorre quando o limite do sistema no número total de arquivos abertos foi
alcançado. Neste caso não há nada útil sysconf(3) forma de obter o limite.

Indo mais fundo, pode-se descobrir que no Linux existe um / proc entrada que poderíamos ler
obter esse valor. Catch-22: estamos sem descritores de arquivo, então não podemos abrir um arquivo para
leia o limite.

No Linux existe uma chamada de sistema para obtê-lo, mas não possui função wrapper [e]glibc, então
você tem que fazer tudo isso com muito cuidado:
longo
explicar_maxfile(void)
{
#ifdef__linux__
estrutura __sysctl_args args;
int32_t arquivomax;
tamanho_t maxfile_size = tamanho(maxarquivo);
int nome[] = { CTL_FS, FS_MAXFILE };
memset(&args, 0, sizeof(struct __sysctl_args));
args.nome = nome;
args.nlen = 2;
args.oldval = &maxfile;
args.oldlenp = &maxfile_size;
if (syscall(SYS__sysctl, &args) >= 0)
retornar arquivomax;
#fim se
retornar -1;
}
Isto permite que o limite seja incluído na mensagem de erro, quando disponível.

EINVAL "Inválido argumento" vs ENOSYS "Função não implementado”
Ações não suportadas (como ligação simbólica(2) em um sistema de arquivos FAT) não são relatados
consistentemente de uma chamada de sistema para outra. É possível ter EINVAL ou
ENOSYS voltou.

Como resultado, deve-se prestar atenção a esses casos de erro para acertá-los, especialmente
já que EINVAL também pode estar se referindo a problemas com um ou mais argumentos de chamada de sistema.

Note que erro(3) is não sempre conjunto
Há momentos em que é necessário ler as fontes [e]glibc para determinar como e
quando erros são retornados para algumas chamadas do sistema.

feof(3) sem Arquivo(3)
Freqüentemente, presume-se que essas funções não podem retornar um erro. Isto só é verdade se
que o transmitir canais argumento é válido, porém eles são capazes de detectar um argumento inválido
ponteiro.

fpathconf(3) caminhoconf(3)
O valor de retorno de fpathconf(2) e caminhoconf(2) poderia legitimamente ser -1, então é
necessário ver se erro(3) foi explicitamente definido.

ioctl(2)
O valor de retorno de ioctl(2) poderia legitimamente ser -1, então é necessário ver se
erro(3) foi explicitamente definido.

readdir(3)
O valor de retorno de readdir(3) é NULL para erros e fim de arquivo. Isso é
necessário ver se erro(3) foi explicitamente definido.

setbuf(3) definir buffer(3) setlinebuf(3) setvbuf(3)
Todas essas funções, exceto a última, retornam nulas. E setvbuf(3) só é documentado como
retornando “diferente de zero” em caso de erro. É preciso ver se erro(3) foi explicitamente
definido.

Strtod(3) strtol(3) estrelado(3) passear(3) Strtoul(3) Strtoull(3)
Essas funções retornam 0 em caso de erro, mas esse também é um valor de retorno legítimo. Isso é
necessário ver se erro(3) foi explicitamente definido.

desconhecido(3)
Embora apenas um único caractere de backup seja exigido pelo padrão ANSI C, isso acontece
que [e]glibc permite mais... mas isso significa que pode falhar com ENOMEM. Pode
também falhará com EBADF se fp é falso. O mais difícil de tudo, se você passar um erro EOF
return ocorre, mas errno não está definido.

A biblioteca libexplain detecta todos esses erros corretamente, mesmo nos casos em que o
os valores de erro são mal documentados, se é que existem.

ENOSPC, Não espaço esquerda on dispositivo
Quando este erro se refere a um arquivo em um sistema de arquivos, a biblioteca libexplain imprime a montagem
ponto do sistema de arquivos com o problema. Isso pode tornar a origem do erro muito
mais claro.
write(fildes = 1 "example", data = 0xbfff2340, data_size = 5) falhou, não há espaço restante
no dispositivo (28, ENOSPC) porque o sistema de arquivos que contém fildes ("/ Home") não tem
mais espaço para dados
À medida que mais suporte especial para dispositivos é adicionado, espera-se que as mensagens de erro incluam o dispositivo
nome e tamanho real do dispositivo.

EROFS, Somente leitura lima .
Quando este erro se refere a um arquivo em um sistema de arquivos, a biblioteca libexplain imprime a montagem
ponto do sistema de arquivos com o problema. Isso pode tornar a origem do erro muito
mais claro.

À medida que mais suporte especial para dispositivos é adicionado, espera-se que as mensagens de erro incluam o dispositivo
nome e tipo.
open(pathname = "/dev/fd0", O_RDWR, 0666) falhou, sistema de arquivos somente leitura (30, EROFS)
porque o disquete tem a aba de proteção contra gravação definida

...porque um CD-ROM não é gravável
...porque o cartão de memória tem a aba de proteção contra gravação definida
...porque a fita magnética de ½ polegada não possui anel de gravação

rebatizar
A rebatizar(2) a chamada do sistema é usada para alterar a localização ou nome de um arquivo, movendo-o
entre diretórios, se necessário. Se o caminho de destino já existir, será
substituído atomicamente, de modo que não haja nenhum ponto em que outro processo tente
acessá-lo descobrirá que está faltando.

Porém, existem limitações: você só pode renomear um diretório em cima de outro
diretório se o diretório de destino não estiver vazio.
rename(oldpath = "foo", newpath = "bar") falhou, Diretório não vazio (39,
ENOTEMPTY) porque newpath não é um diretório vazio; isto é, contém entradas
outro que não seja "." e ".."
Você também não pode renomear um diretório sobre outro que não seja diretório.
rename(oldpath = "foo", newpath = "bar") falhou, não é um diretório (20, ENOTDIR)
porque oldpath é um diretório, mas newpath é um arquivo normal, não um diretório
Nem o inverso é permitido
rename(oldpath = "foo", newpath = "bar") falhou, é um diretório (21, EISDIR)
porque newpath é um diretório, mas oldpath é um arquivo normal, não um diretório

Isto, claro, torna o trabalho da biblioteca libexplain mais complicado, porque o
desvincular(2) ou rmdir(2) a chamada do sistema é chamada implicitamente por rebatizar(2), e assim todos os
desvincular(2) ou rmdir(2) os erros também devem ser detectados e tratados.

dup2
A dup2(2) a chamada do sistema é usada para criar um segundo descritor de arquivo que faz referência ao
mesmo objeto que o primeiro descritor de arquivo. Normalmente, isso é usado para implementar a entrada do shell
e redirecionamento de saída.

O engraçado é que, assim como rebatizar(2) pode renomear atomicamente um arquivo em cima de um
arquivo existente e remover o arquivo antigo, dup2(2) pode fazer isso em um arquivo já aberto
descritor.

Mais uma vez, isso torna o trabalho da biblioteca libexplain mais complicado, porque o fechar(2)
chamada do sistema é chamada implicitamente por dup2(2), e assim todos fechar(2) os erros devem ser
detectado e tratado também.

AVENTURAS IN IOCTL SUPPORT


A ioctl(2) a chamada do sistema fornece aos autores do driver de dispositivo uma maneira de se comunicar com
espaço de usuário que não cabe na API do kernel existente. Ver lista_ioctl(2).

decodificação SOLICITAÇÃO Números
De uma rápida olhada no ioctl(2) interface, pareceria haver um grande, mas finito
número de possíveis ioctl(2) solicitações. Cada um diferente ioctl(2) a solicitação é efetivamente
outra chamada de sistema, mas sem nenhuma segurança de tipo - o compilador não pode ajudar
programador acertou. Esta foi provavelmente a motivação por trás tcflush(3) e
amigos.

A impressão inicial é que você poderia decodificar ioctl(2) solicitações usando um grande switch
declaração. Isto acaba por ser inviável porque se descobre muito rapidamente que é
impossível incluir todos os cabeçalhos de sistema necessários que definem os vários ioctl(2)
solicitações, porque eles têm dificuldade em brincar bem um com o outro.

Uma análise mais aprofundada revela que há uma variedade de números de solicitação “privados” e dispositivos
os autores do driver são incentivados a usá-los. Isto significa que há uma possibilidade muito maior
conjunto de solicitações, com números de solicitação ambíguos, que são imediatamente aparentes. Também,
existem algumas ambigüidades históricas também.

Já sabíamos que a mudança era impraticável, mas agora sabemos que para selecionar o
nome e explicação apropriados da solicitação, devemos considerar não apenas o número da solicitação, mas
também o descritor de arquivo.

A implementação de ioctl(2) o suporte dentro da biblioteca libexplain é ter uma tabela de
ponteiros para ioctl(2) solicitar descritores. Cada um desses descritores inclui um opcional
ponteiro para uma função de desambiguação.

Cada solicitação é realmente implementada em um arquivo de origem separado, de modo que o necessário
Os arquivos include ficam dispensados ​​da obrigação de brincar bem com os outros.

Representação
A filosofia por trás da biblioteca libexplain é fornecer o máximo de informações possível.
possível, incluindo uma representação precisa da chamada do sistema. No caso de
ioctl(2) isso significa imprimir o número de solicitação correto (por nome) e também um número correto (ou
pelo menos útil) representação do terceiro argumento.

A ioctl(2) o protótipo fica assim:
int ioctl(int arquivos, int request, ...);
o que deve fazer com que seus alarmes de segurança de tipo disparem. Interno para [e]glibc, isso é ativado
em uma variedade de formas:
int __ioctl(int arquivos, int request, long arg);
int __ioctl(int arquivos, int request, void *arg);
e a interface syscall do kernel Linux espera
asmlinkage long sys_ioctl(unsigned int arquivos, unsigned int request, unsigned long
arg);
A extrema variabilidade do terceiro argumento é um desafio, quando a biblioteca libexplain
tenta imprimir uma representação desse terceiro argumento. No entanto, uma vez que o número da solicitação
foi desambiguada, cada entrada na tabela ioctl da biblioteca libexplain tem um
função print_data personalizada (OO feito manualmente).

Explicações
Há menos problemas para determinar a explicação a ser usada. Assim que o número da solicitação
foi desambiguada, cada entrada na tabela ioctl da biblioteca libexplain tem um nome personalizado
função print_explanation (novamente, OO feito manualmente).

Ao contrário das chamadas de sistema da seção 2 e da seção 3, a maioria ioctl(2) as solicitações não contêm erros
documentado. Isto significa que, para fornecer boas descrições de erros, é necessário ler o kernel
fontes para descobrir

· o que erro(3) valores podem ser retornados, e

· a causa de cada erro.

Devido à natureza OO do envio de chamadas de função dentro do kernel, você precisa ler
todos os fontes que implementam isso ioctl(2) solicitação, não apenas a implementação genérica. Isto
é de se esperar que diferentes kernels tenham números de erros diferentes e sutilmente
diferentes causas de erro.

EINVAL vs ENOTTY
A situação é ainda pior para ioctl(2) solicitações do que para chamadas de sistema, com EINVAL e
ENOTTY ambos sendo usados ​​para indicar que um ioctl(2) a solicitação é inadequada porque
contexto e, ocasionalmente, ENOSYS, ENOTSUP e EOPNOTSUPP (destinados a serem usados ​​para soquetes) como
bem. Existem comentários nas fontes do kernel Linux que parecem indicar uma mudança progressiva
a limpeza está em andamento. Para um caos extra, o BSD adiciona ENOIOCTL à confusão.

Como resultado, deve-se prestar atenção a esses casos de erro para acertá-los, especialmente
já que EINVAL também pode estar se referindo a problemas com um ou mais argumentos de chamada de sistema.

intptr_t
O padrão C99 define um tipo inteiro que é capaz de conter qualquer ponteiro
sem perda de representação.

O protótipo syscall da função acima seria melhor escrito
longo sys_ioctl (fildes int não assinados, solicitação int não assinada, intptr_t arg);
O problema é a dissonância cognitiva induzida por alterações específicas do dispositivo ou do sistema de arquivos.
ioctl(2) implementações, como:
longo vfs_ioctl (arquivo struct *filp, unsigned int cmd, unsigned long arg);
A maioria dos ioctl(2) as solicitações na verdade têm um terceiro argumento int *arg. Mas tendo isso
declarado longo leva ao código que trata isso como *arg longo. Isso é inofensivo em 32 bits
(sizeof(long) == sizeof(int)) mas desagradável em 64 bits (sizeof(long) != sizeof(int)).
Dependendo do endianismo, você obtém ou não o valor que espera, mas você sempre ter
um rabisco de memória ou um rabisco de pilha também.

Escrevendo tudo isso como
int ioctl(int arquivos, int request, ...);
int __ioctl(int arquivos, int request, intptr_t arg);
longo sys_ioctl (fildes int não assinados, solicitação int não assinada, intptr_t arg);
longo vfs_ioctl (arquivo struct *filp, unsigned int cmd, intptr_t arg);
enfatiza que o número inteiro é apenas um número inteiro para representar uma quantidade que é quase
sempre um tipo de ponteiro não relacionado.

CONCLUSÃO


Use libexplain, seus usuários vão gostar.

DIREITOS AUTORAIS


libexplain versão 1.4
Direitos autorais (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Peter Miller

Use o explica_lca2010 on-line usando os serviços onworks.net


Servidores e estações de trabalho gratuitos

Baixar aplicativos Windows e Linux

  • 1
    GOLE
    GOLE
    SWIG é uma ferramenta de desenvolvimento de software
    que conecta programas escritos em C e
    C ++ com uma variedade de alto nível
    linguagens de programação. SWIG é usado com
    diferente...
    Baixar SWIG
  • 2
    Tema WooCommerce Nextjs React
    Tema WooCommerce Nextjs React
    Tema React WooCommerce, construído com
    Próxima JS, Webpack, Babel, Node e
    Express, usando GraphQL e Apollo
    Cliente. Loja WooCommerce em React(
    contém: Produtos...
    Baixe o tema WooCommerce Nextjs React
  • 3
    archlabs_repo
    archlabs_repo
    Repositório de pacotes para ArchLabs Este é um
    aplicativo que também pode ser obtido
    da
    https://sourceforge.net/projects/archlabs-repo/.
    Ele foi hospedado no OnWorks em...
    Baixar archlabs_repo
  • 4
    Projeto Zephyr
    Projeto Zephyr
    O Projeto Zephyr é uma nova geração
    sistema operacional em tempo real (RTOS) que
    suporta vários hardwares
    arquiteturas. É baseado em um
    kernel de pequena pegada ...
    Baixar Projeto Zephyr
  • 5
    SCons
    SCons
    SCons é uma ferramenta de construção de software
    essa é uma alternativa superior ao
    clássica ferramenta de construção "Make" que
    todos nós conhecemos e amamos. SCons é
    implementou um ...
    Baixar SCons
  • 6
    PSeIntGenericName
    PSeIntGenericName
    PSeInt é um interpretador de pseudo-código para
    alunos de programação que falam espanhol.
    Seu principal objetivo é ser uma ferramenta para
    aprender e compreender o básico
    concep ...
    Baixar PSeInt
  • Mais "

Comandos Linux

Ad