You are on page 1of 441

Programao Linux Avanada ca c Autores:Mark Mitchell, Jerey Oldham e Alex Samuel http://www.advancedlinuxprogramming.com/ http://www.codesourcery.

com/

Advanced Linux Programming


Copyright 2001 by New Riders Publishing FIRST EDITION: June, 2001 Todos os direitos reservados. Nenhuma parte desse livro pode ser reproduzida ou transmitida de qualquer forma ou por quaisquer meios, eletnico o ou mecnico, incluindo fotocpia, gravao, ou por qualquer meio de armaa o ca zenamento de informao e sistema de recuperao, exceto para a incluso ca ca a de breve citao em uma publicao. ca ca Nmero International Standard Bookr: 0-7357-1043-0 u Nmero de Carto do Catlogo da Biblioteca do Congresso dos EUA: u a a 00-105343 05 04 03 02 01 7 6 5 4 3 2 1 Interpretao do cdigo de impresso: Os dois d ca o a gitos mais ` direita so a a o ano de impresso do livro; o d a gito simples mais ` direita o nmero de a e u impresso do livro. Por exemplo, o cdigo de impresso 01-1 mostra que a a o a primeira impresso do livro ocorreu em 2001. a Composto em Bembo e MCPdigital pela New Riders Publishing. Impresso nos Estados Unidos da Amrica. e Trademarks Todos os temos mencionados nesse livro que so conhecidos serem tradea marks ou service marks foram apropriadamente capitalizados. New Riders Publishing no pode atestar a preciso dessa informao. O uso de um termo a a ca nesse livro no deve ser considerado como afetando a validade de qualquer a trademark ou service mark. PostScript uma marca registrada de Adobe Systems, Inc. Linux uma e e marca registrada de Linus Torvalds. Alerta e Aviso Legal Esse livro projetado para fornecer informao sobre Programao Avane ca ca c ada em Ambiente GNU/Linux. Todo esforo foi feito para tornar esse livro c to completo e preciso quanto poss a vel, mas nenhuma garantia ou adequao ca et impl a cita. Essa informao fornecida sobre uma basicamente como et. Os autores ca e a e a New Riders Publishing no tero nenhuma dependncia nem responsabia a e lidade para com nenhuma pessoa ou entidade com relao a qualquer perda ca ou dano proveniente da informao contida nesse livro ou de uso dos discos ca ou programas que o acompanham.

Crditos e
Editor David Dwyer Editor Associado Al Valvano Editor Executivo Stephanie Wall Editor Gerente Gina Brown Editor de Aquisies co Ann Quinn Editor de Desenvolvimento Laura Loveall Gerente de Marketing de Produto Stephanie Layton Gerente de Publicidade Susan Petro Editor de Projeto Caroline Wise Editor de Cpia o Krista Hansing Indexador Snior e Cheryl Lenser Coordenador de manufatura Jim Conway Designer de Livro Louisa Klucznik Designer de Capa Brainstorm Design, Inc. Porduo de Capa ca Aren Howell Revisor Debra Neel composio ca Amy Parker

Sobre os Autores
Mark Mitchell recebeu o grau de bacharel em cincias da computao em e ca Harvard em 1994 e mestrado em Stanford em 1999. Sua rea de interesse est a a centrada em complexidade computacional e segurana computacional. Mark c participou sibstancialmente no desenvolvimento da GNU Compiler Collection, e ele tem um forte interesse em qualidade de desenvolvimento de software. Jerey Oldham recebeu o bacharelado do grau de artes em cincias da e computao na Universidade de Rice em 1991. Aps trabalhar no Center fo ca o Research on Parallel Computation, ele obteve o doutorado em losoa em Stanford no ano de 2000. Seu interesse de pesquisa centra-se em engenharia de algor tmos, concentrando-se em uxo e outros algor tmos combinatoriais. Ele traba no GCC e em software de computao cient ca ca. Alex Samuel graduado em Harvard em 1995 com um grau em f sica. Ele trabalhou como engenheiro de software na BBN antes de retornar a estudar f sica na Caltech e no Stanford Linear Accelerator Center. Alex administrou o projeto Software Carpentry e trabalha em vrios outros projetos, tais como a otimizaes no GCC. Mark e Alex fundaram a CodeSourcery LLC juntos em co 1999. Jerey juntou-se ` copanhia em 2000. A misso da CodeSourcery a a fornecer ferramentas de desenvolvimento para GNU/Linux e outros sise temas operacionais; para levar ` rede de ferramentas GNU uma qualidade a comercial, de acordo com os padres de conjunto de ferrametnas de deseno volvimento; e fornecer consultoria geral e servios de engenharia. O Web s c te da CodeSourcery http://www.codesourcery.com. e

Sobre os Revisores Tcnicos e


Esses revisores contribuiram com seu considervel experincia de trabaa e lho ao longo de todo o processo de desenvolvimento do Advanced Linux Programming. Quando o livro estava sendo escrito, esses dedicados prossionais revisaram todo o materia de contedo tcnico, a organizao, e o anu e ca damento. O dilogo com eles foi fundamental para garantir que o Advanced a Linux Programmingse ajustasse `s necessidades dos leitores por informao a ca da mais alta qualidade tcnica. e Glenn Becker tem muitas graduaes, todas em teatro. Ele atualmente co trabalha como produtor online para SCIFI.COM, o brao online do SCI FI c channel, em New York City. Em casa ele usa o Debian GNU/Linux e e obcessivo sobre tpicos com administrao de sistemas, segurana, internao ca c cionalizao de software, e XML. ca John Dean recebeu um BSc(Hons) da Universidade de Sheeld em 1974, em cincia pura. Como um graduado na Sheeld, John desenvolveu seu ine teresse em computao. Em 1986 ele recebeu um MSc do Craneld Institute ca of Science and Technology em Engenharia de Controle. Enquanto trabalhava para a Roll Royce and Associates, John tornou-se envolvido no desenvolvimento de software de controle para inspeo do vapor que emana das usinas ca nucleares assitida por computador. Uma vez que deichou a RR&A em 1978, ele trabalhou na indstria petroqu u mica desenvolvendo e mantendo software de controle de processo. John worked como desenvolvedor voluntrio de softa ware para o MySQL de 1996 at maio de 2000, quando juntou-se ao MySQL e como um funcionrio em tempo integral. A rea de responsabilidade de John a a MySQL no MS Windows e desenvolvimento de uma nova GUI do cliente e MySQL usando o kit de feramentas de aplicao Qt da Trolltech sobre ambos ca Windows e plantaforma que executa o X-11.

Agradecimentos
Apreciamos grandemente o trabalho prioneiro de Richard Stallman, sem o qual nunca teria existido o Projeto GNU, e de Linus Torvalds, sem o qual nunca teria existido o kernel do Linux. Incontveis outras pessoa trabalhaa ram sobre partes do sistema operacional GNU/Linux, e agradecemos a todos eles. Agradecemos `s faculdades de Harvard e Rice pela nosso curso superior, a e Caltech e Stanford pelo nosso treinamento de graduao. Sem todos que ca nos ensinaram, ns nunca ter o amos ousadia para ensinar outros! W. Richard Stevens escreveu trs excelentes livros sobre programao em e ca ambiente UNIX, e ns os consultamos extensivamente. Roland McGrath, o Ulrich Drepper, e muitos outros escreveram a biblioteca C GNU e sua excelente. Robert Brazile e Sam Kendall revisaram o primeiro esboo desse livro c e zeram maravilhosas sugestes sobre ajustes e contedo. Nossos editores o u tcnicos e revisores (especialmente Glenn Becker e John Dean) nos mostrae ram erros, zeram sugestes, e forneceram cont o nuo encorajamento. Certamente, quaisquer erros que restarem no so falhas deles! a a Agradecimentos a Ann Quinn, da New Riders, por se encarregar de todos os detalhes envolvidos na publicao desse livro; Laura Loveall, tambm da ca e New Riders, por no nos permitir car muito muito atrazados para nossos a compromissos; e Stephanie Wall, tambm da New Riders, fpor nos encorajar e a escrever esse livro em primeiro lugar!

Nos Diga Qual Sua Opinio a


Como leitor desse livro, voc o mais importante cr ee tico e comentarista. Valorizamos sua opinio e desejamos conhecer o que estamos fazendo cora retamene, o que podemos fazer melhor, quais reas voc gostaria de nos a e ver publicar, e quaisquer outras palavras de sabedoria voc est disposto a e a colocar em nosso caminho. Como Editora Executiva para o time de Desenvolvimento Web d New Riders Publishing, I seus comentrios so bem vindos. Voc pode enviar-nos a a e um fax, um email, ou escrever-me diretamente para me permitir saber o que voc gostou ou no sobre esse livrotambm o que podemos fazer para tornar e a e nossos livros melhores. Por favor note que Eu no posso ajudar voc com problemas tcnicos a e e relacionados aos tpicos desse livro, e que devido ao grande volume de correio o que Eu recebo, Eu posso no ser capaz de responder a todas as mensagens. a Quando voc escrever, por favor tenha certeza de incluir o t e tulo desse livro e o autor, bem como seu nome e telefone ou nmeor de faz. Eu irei u cuidadosamente revisar seus comentrios e compartilh-los com os autores e a a editores que trabalharam no livro. Fax: Email: Mail: 317-581-4663 Stephanie.Wall@newriders.com Stephanie Wall Executive Editor New Riders Publishing 201 West 103rd Street Indianapolis, IN 46290 USA

Do Tradutor

(...) Pero, con todo eso, me parece que el traducir de una lengua en otra, como no sea de las reinas de las lenguas, griega y latina, es como quien mira los tapices amencos por el revs, que aunque se veen las guras, son llenas e de hilos que las escurecen y no se veen con la lisura y tez de la haz, y el traducir de lenguas fciles ni arguye ingenio ni elocucin, como no le arguye a o el que traslada ni el que copia un papel de otro papel. (...) [II, 62] El ingenioso hidalgo Don Quijote de la Mancha Miguel de Cervantes

Essa traduo dedicada especialmente a um rapazinho que, na presente ca e data, encontra-se ainda no ventre materno. Espero que todos ns possamos o entregar `s crianas de hoje um mundo melhor que o que ns encontramos. a c o Melhor em todos os sentidos mas principalmente nos sentidos social, ecolgico o e em qualidade de vida.

Traduzido por Jorge Barros de Abreu http://sites.google.com/site/cmatinf Verso - 0.21 - 06/03/2012 a

Da Traduo ca
os cdigos fontes dos programas podem ser encontrados no s o tios citados na primeira pgina dessa traduo. a ca em algumas pginas o latex colocou espaamentos extras pelo fato de a c logo a frente encontrar-se algum objeto que no pode ser partido em a duas pginas. Posteriormente pensarei sobre colocar esses objetos no a nal de cada cap tulo, ou no, como diria nosso o ministro Gil. a nas listagens de programas colocou-se uma numerao com intuito de ca facilitar a explanao e a anlise do cdigo em condies pedaggicas. ca a o co o a traduo foi feita a partir dos originais em ingls no formato pdf e ca e convertidos com o programa pdftotext. Isso quer dizer que alguma formatao do original foi eventualmente/inadivertidamente perdida/esca quecida/omitida na converso para o texto puro. a no presente momento dedico-me apenas ` traduo propriamente dita a ca sem, no entanto, vericar os cdigos fontes. o o cap tulo 9 precisa de mais ateno dos experts em assembly. ca a bibliograa foi inclu pelo tradutor. da o alp-toc.pdf e o alp-index.pdf ainda esto por traduzir. a na traduo a expresso GNU/Linux foi usada com extensivamente e ca a enfticamente. a a traduo dos cdigos fontes dos exemplos do livro foi conclu mas ca o da a acentuao foi retirada pois o listings no trabalha com acentos. ca a

Sumrio a
I Programao UNIX Avanada com Linux ca c
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1
5 5 6 7 7 8 9 11 12 14 15 15 15 18 18 19 20 20 23 23 24 25 26 30 32 32 36 39 39

1 Iniciando 1.1 Editando com Emacs . . . . . . . . . . . . . . . . . . . 1.1.1 Abrindo um Arquivo Fonte em C ou em C++ . 1.1.2 Formatando Automaticamente . . . . . . . . . . 1.1.3 Destaque Sinttico para Palavras Importantes . a 1.2 Compilando com GCC . . . . . . . . . . . . . . . . . . 1.2.1 Compilando um Unico Arquivo de Cdigo Fonte o 1.2.2 Linkando Arquivos Objeto . . . . . . . . . . . . 1.3 Automatizando com GNU Make . . . . . . . . . . . . . 1.4 Depurando com o Depurador GNU (GDB) . . . . . . . 1.4.1 Depurando com GNU GDB . . . . . . . . . . . 1.4.2 Compilando com Informaes de Depurao . . co ca 1.4.3 Executando o GDB . . . . . . . . . . . . . . . . 1.5 Encontrando mais Informao . . . . . . . . . . . . . . ca 1.5.1 Pginas de Manual . . . . . . . . . . . . . . . . a 1.5.2 Info . . . . . . . . . . . . . . . . . . . . . . . . 1.5.3 Arquivos de Cabealho . . . . . . . . . . . . . . c 1.5.4 Cdigo Fonte . . . . . . . . . . . . . . . . . . . o 2 Escrevendo Bom Software GNU/Linux 2.1 Interao Com o Ambiente de Execuo ca ca 2.1.1 A Lista de Argumentos . . . . . . 2.1.2 Convenes GNU/Linux de Linha co 2.1.3 Usando getopt long . . . . . . . . 2.1.4 E/S Padro . . . . . . . . . . . . a 2.1.5 Cdigos de Sa de Programa . . o da 2.1.6 O Ambiente . . . . . . . . . . . . 2.1.7 Usando Arquivos Temporrios . . a 2.2 Fazendo Cdigo Defensivamente . . . . . o 2.2.1 Usando assert . . . . . . . . . . . xiii

. . . . . . . . . . . . . . . . de Comando . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

2.3

2.2.2 Falhas em Chamadas de Sistema . . . . . . 2.2.3 Cdigos de Erro de Chamadas de Sistema . o 2.2.4 Erros e Alocao de Recursos . . . . . . . . ca Escrevendo e Usando Bibliotecas . . . . . . . . . . 2.3.1 Agrupando Arquivos Objeto . . . . . . . . . 2.3.2 Bibliotecas Compartilhadas . . . . . . . . . 2.3.3 Bibliotecas Padronizadas . . . . . . . . . . . 2.3.4 Dependncia de uma Biblioteca . . . . . . . e 2.3.5 Prs e Contras . . . . . . . . . . . . . . . . o 2.3.6 Carregamento e Descarregamento Dinmico a

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

41 43 45 47 47 49 51 52 54 55 57 57 58 58 60 60 60 61 64 66 68 70 70 71 73 77 78 80 82 84 85 86 88 89 89 91 92 95 96

3 Processos 3.1 Visualizando Processos . . . . . . . . . . . . . . . . . 3.1.1 Identicadores de Processos . . . . . . . . . . 3.1.2 Visualizando os Processos Ativos . . . . . . . 3.1.3 Encerrando um Processo . . . . . . . . . . . . 3.2 Criando Processos . . . . . . . . . . . . . . . . . . . . 3.2.1 Usando system . . . . . . . . . . . . . . . . . 3.2.2 Usando bifurcar e executar . . . . . . . . . . . 3.2.3 Agendamento de Processo . . . . . . . . . . . 3.3 Sinais . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.1 Encerramento de Processos . . . . . . . . . . 3.3.2 Esperando pelo Encerramento de um Processo 3.3.3 As Chamadas de Sistema da Fam wait . . lia 3.3.4 Processos do Tipo Zumbi . . . . . . . . . . . . 3.3.5 Limpando Filhos de Forma No Sincronizada a 4 Linhas de Execuo ca 4.1 Criao de Linhas de Execuo . . . . . . . . . . . ca ca 4.1.1 Enviando Dados a uma Linha de Execuo . ca 4.1.2 Vinculando Linhas de Execuo . . . . . . . ca 4.1.3 Valores de Retorno de Linhas de Execuo . ca 4.1.4 Mais sobre IDs de Linhas de Execuo . . . ca 4.1.5 Atributos de Linha de Execuo . . . . . . . ca 4.2 Cancelar Linhas de Execuo . . . . . . . . . . . . ca 4.2.1 Linhas de Execuo Sincronas e Assincronas ca 4.2.2 Sees Cr co ticas Incancelveis . . . . . . . . . a 4.2.3 Quando Cancelar uma Linha de Execuo . ca 4.3 Area de Dados Espec cos de Linha de Execuo . ca 4.3.1 Manipuladores de Limpeza . . . . . . . . . . 4.3.2 Limpeza de Linha de Execuo em C++ . . ca

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

4.4

Sincronizao e Sees Cr ca co ticas . . . . . . . . . . . . . . . 4.4.1 Condies de Corrida . . . . . . . . . . . . . . . . . co 4.4.2 Mutexes . . . . . . . . . . . . . . . . . . . . . . . . 4.4.3 Travas Mortas de Mutex . . . . . . . . . . . . . . . 4.4.4 Testes de Mutex sem Bloqueio . . . . . . . . . . . . 4.4.5 Semforos para Linhas de Execuo . . . . . . . . . a ca 4.4.6 Variveis Condicionais . . . . . . . . . . . . . . . . a 4.4.7 Travas Mortas com Duas ou Mais Linhas de Execuo . . . . . . . . . . . . . . . . . . . . . . . ca 4.5 Implementao de uma Linha de Execuo em GNU/Linux ca ca 4.5.1 Manipulando Sinal . . . . . . . . . . . . . . . . . . 4.5.2 Chamada de Sistema clone . . . . . . . . . . . . . . 4.6 Processos Vs. Linhas de Execuo . . . . . . . . . . . . . . ca

. . . . . . . . . . . .

. . . . . . . . . . . .

97 98 100 103 105 105 109 115 116 117 118 118

5 Comunicao Entre Processos ca 5.1 Memria Compartilhada . . . . . . . . . . . . . . . . . . . . o 5.1.1 Comunicao Local Rpida . . . . . . . . . . . . . . ca a 5.1.2 O Modelo de Memria . . . . . . . . . . . . . . . . . o 5.1.3 Alocao . . . . . . . . . . . . . . . . . . . . . . . . . ca 5.1.4 Anexando e Desanexando . . . . . . . . . . . . . . . 5.1.5 Controlando e Desalocando Memria Compartilhada o 5.1.6 Um programa Exemplo . . . . . . . . . . . . . . . . . 5.1.7 Depurando . . . . . . . . . . . . . . . . . . . . . . . . 5.1.8 Prs e Contras . . . . . . . . . . . . . . . . . . . . . o 5.2 Semforos de Processos . . . . . . . . . . . . . . . . . . . . . a 5.2.1 Alocao e Desalocao . . . . . . . . . . . . . . . . ca ca 5.2.2 Inicializando Semforos . . . . . . . . . . . . . . . . . a 5.2.3 Operaes Wait e Post . . . . . . . . . . . . . . . . . co 5.2.4 Depurando Semforos . . . . . . . . . . . . . . . . . a 5.3 Arquivos Mapeados em Memria . . . . . . . . . . . . . . . o 5.3.1 Mapeando um Arquivo Comum . . . . . . . . . . . . 5.3.2 Programas Exemplo . . . . . . . . . . . . . . . . . . 5.3.3 Acesso Compartilhado a um Arquivo . . . . . . . . . 5.3.4 Mapeamentos Privados . . . . . . . . . . . . . . . . . 5.3.5 Outros Usos para Arquivos Mapeados em Mem-ria . o 5.4 Pipes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4.1 Criando Pipes . . . . . . . . . . . . . . . . . . . . . . 5.4.2 Comunicao Entre Processos Pai e Filho . . . . . . . ca 5.4.3 Redirecionando os Fluxos da Entrada Padro, da Sa a da Padro e de Erro . . . . . . . . . . . . . . . . . . . . a 5.4.4 As Funes popen e pclose . . . . . . . . . . . . . . . co

121 . 122 . 123 . 123 . 124 . 125 . 126 . 127 . 127 . 128 . 128 . 129 . 130 . 130 . 132 . 132 . 133 . 134 . 136 . 137 . 137 . 138 . 138 . 139 . 141 . 142

5.4.5

5.5

FIFOs . . . . . . . . . . . . . . . . . . . . . . . . 5.4.5.1 Criando um FIFO . . . . . . . . . . . . 5.4.5.2 Accessando um FIFO . . . . . . . . . . Sockets . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.5.1 Conceitos de Socket . . . . . . . . . . . . . . . . . 5.5.2 Chamadas de Sistema . . . . . . . . . . . . . . . 5.5.3 Servidores . . . . . . . . . . . . . . . . . . . . . . 5.5.4 Sockets Locais . . . . . . . . . . . . . . . . . . . . 5.5.5 Um Exemplo Usando um Sockets de Escopo local 5.5.6 Sockets de Dom nio Internet . . . . . . . . . . . 5.5.7 Sockets Casados . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

143 144 144 145 146 147 148 149 150 153 155

II

Dominando GNU/Linux
. . . . . . . . . . . . . . . . de Ar. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

157
. . . . . . . . . . . . . . . 161 162 163 164 165 166 167 171 171 172 173 173 175 179 180 181

6 Dispositivos 6.1 Tipos de Dispositivos . . . . . . . . . . . . . . . . . . 6.2 Nmeros de Dispositivo . . . . . . . . . . . . . . . . . u 6.3 Entradas de Dispositivo . . . . . . . . . . . . . . . . 6.3.1 O Diretrio /dev . . . . . . . . . . . . . . . . o 6.3.2 Acessando Dispositivos por meio de Abertura quivos . . . . . . . . . . . . . . . . . . . . . . 6.4 Dispositivos de Hardware . . . . . . . . . . . . . . . . 6.5 Dispositivos Especiais . . . . . . . . . . . . . . . . . . 6.5.1 O Dispositivo /dev/null . . . . . . . . . . . . 6.5.2 O Dispositivo /dev/zero . . . . . . . . . . . . 6.5.3 /dev/full . . . . . . . . . . . . . . . . . . . . . 6.5.4 Dispositivos Geradores de Bytes Aleatrios . . o 6.5.5 Dispositivos Dentro de Dispositivos . . . . . . 6.6 PTYs . . . . . . . . . . . . . . . . . . . . . . . . . . 6.6.1 Uma Demonstrao de PTY . . . . . . . . . . ca 6.7 A chamada de sistema ioctl . . . . . . . . . . . . . . 7 O Sistema de Arquivos /proc 7.1 Extraindo Informao do /proc . . . . . . ca 7.2 Entradas dos Processos . . . . . . . . . . . 7.2.1 /proc/self . . . . . . . . . . . . . . 7.2.2 Lista de Argumentos do Processo . 7.2.3 Ambiente de Processo . . . . . . . 7.2.4 O Executvel do Processo . . . . . a 7.2.5 Descritores de Arquivo do Processo

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

183 . 184 . 186 . 188 . 189 . 192 . 192 . 193

7.2.6 Estat sticas de Memria do Processo . . . o 7.2.7 Estat sticas de Processo . . . . . . . . . . 7.3 Informaes de Hardware . . . . . . . . . . . . . . co 7.3.1 Informaes sobre a CPU . . . . . . . . . co 7.3.2 Informao de Dispositivos . . . . . . . . . ca 7.3.3 Informao de Barramento . . . . . . . . . ca 7.3.4 Informaes de Porta Serial . . . . . . . . co 7.4 Informao do Kernel . . . . . . . . . . . . . . . ca 7.4.1 Informao de verso . . . . . . . . . . . . ca a 7.4.2 Nome do Host e Nome de Dom nio . . . . 7.4.3 Utilizao da Memria . . . . . . . . . . . ca o 7.5 Acionadores, Montagens, e Sistemas de Arquivos . 7.5.1 Sistemas de Arquivo . . . . . . . . . . . . 7.5.2 Acionadores e Parties . . . . . . . . . . co 7.5.3 Montagens . . . . . . . . . . . . . . . . . . 7.5.4 Travas . . . . . . . . . . . . . . . . . . . . 7.6 Estat sticas de Sistema . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

195 196 196 196 197 197 197 198 198 199 199 201 201 201 203 204 206

8 Chamadas de Sistema do GNU/Linux 209 8.1 Usando strace . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 8.2 A Chamada access: Testando Permisses de Arquivos . . . . . 212 o 8.3 A Chamada de Sistema fcntl : Travas e Outras Operaes em co Arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214 8.4 As Chamadas fsync e fdatasync: Descarregando para o Disco . 216 8.5 As Chamadas getrlimit e setrlimit: Limites de Recurso . . . . 218 8.6 a Chamada getrusage: Estat sticas de Processo . . . . . . . . 220 8.7 A Chamada gettimeofday: Hora Relgio Comum . . . . . . . . 221 o 8.8 A Fam mlock : Travando Memria lia o F sica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222 8.9 mprotect: Ajustando as Permisses da Memria . . . . . . . . 224 o o 8.10 A Chamada nanosleep: Temporizador de Alta Preciso . . . . 227 a 8.11 readlink: Lendo Links Simblicos . . . . . . . . . . . . . . . . 228 o 8.12 A Chamada sendle: Transferncia de Dados Rpida . . . . . 229 e a 8.13 A Chamada setitimer : Ajustando Intervalos em Temporizadores231 8.14 A Chamada de Sistema sysinfo: Obtendo Estat sticas do Sistema232 8.15 A Chamada de Sistema uname . . . . . . . . . . . . . . . . . 233 9 Cdigo Assembly Embutido o 9.1 Quando Usar Cdigo em Assembly . . . . . . . . . . . . . . o 9.2 Assembly Embutido Simples . . . . . . . . . . . . . . . . . . 9.2.1 Convertendo Instrues asm em Instrues Assembly co co 235 . 236 . 237 . 238

9.3

9.4 9.5 9.6

Sintaxe Assembly Extendida . . . . . . . 9.3.1 Instrues Assembler . . . . . . . co 9.3.2 Sa das . . . . . . . . . . . . . . . 9.3.3 Entradas . . . . . . . . . . . . . . 9.3.4 Cr tica . . . . . . . . . . . . . . . Exemplo . . . . . . . . . . . . . . . . . . Recursos de Otimizao . . . . . . . . . ca Manutenso e Recursos de Portabilidade a

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

239 239 239 241 241 241 244 244

10 Segurana c 10.1 Usurios e Grupos . . . . . . . . . . . . a 10.1.1 O Superusurio . . . . . . . . . . a 10.2 IDs de Usurio e IDs de Grupo . . . . . a 10.3 Permisses do Sistema de Arquivos . . . o 10.3.1 Falha de Segurana: c Sem Permisso de Execuo . . . a ca 10.3.2 Sticky Bits . . . . . . . . . . . . . 10.4 ID Real e ID Efetivo . . . . . . . . . . . 10.4.1 Programas Setuid . . . . . . . . . 10.5 Autenticando Usurios . . . . . . . . . . a 10.6 Mais Falhas de Segurana . . . . . . . . c 10.6.1 Sobrecarga no Espao Temporrio c a 10.6.2 Condioes de Corrida no /tmp . . c 10.6.3 Usando system ou popen . . . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . . . . . . . . . . .

245 . 246 . 247 . 248 . 249 . . . . . . . . . 253 254 255 257 259 262 263 266 269

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . de Armazenagem . . . . . . . . . . . . . . . . . . . .

11 Um Modelo de Aplicao GNU/Linux ca 11.1 Viso Geral . . . . . . . . . . . . . . . . . a 11.1.1 Ressalvas . . . . . . . . . . . . . . 11.2 Implementao . . . . . . . . . . . . . . . ca 11.2.1 Funes Comuns . . . . . . . . . . co 11.2.2 Chamando Mdulos de Servidor . . o 11.2.3 O Servidor . . . . . . . . . . . . . . 11.2.4 O Programa Principal . . . . . . . 11.3 Modulos . . . . . . . . . . . . . . . . . . . 11.3.1 Mostra a Hora do Relgio Comum o 11.3.2 Mostra a Distribuio GNU/Linux ca 11.3.3 Mostrando o Espao Livre do Disco c 11.3.4 Sumarizando Processos Executando 11.4 Usando o Servidor . . . . . . . . . . . . . 11.4.1 O Makele . . . . . . . . . . . . . . 11.4.2 Gerando o Executvel do Programa a

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Server

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

273 . 273 . 274 . 276 . 277 . 280 . 282 . 288 . 291 . 292 . 293 . 294 . 295 . 301 . 302 . 303

11.4.3 Executando o Programa Server . . . . . . . . . . . . . 303 11.5 Terminando . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305

III

Apndices e

307
311 . 311 . 313 . 316 . 316 . 317 . 318 . 320 . 321 . . . . . . . 321 323 324 325 325 328 328

A Outras Ferramentas de Desenvolvimento A.1 Anlise Esttica do Programa . . . . . . . . . . . . . . . . . a a A.2 Encontrando Erros de Memria Alocada Dinmicamente . . o a A.2.1 Um Programa para Testar Alocao e ca Desalocao de Memria . . . . . . . . . . . . . . . . ca o A.2.2 malloc Checking . . . . . . . . . . . . . . . . . . . . . A.2.3 Encontrando Vazamento de Memria Usando o mtrace . . . . . . . . . . . . . . . . . . . . . . . . . . A.2.4 Usando ccmalloc . . . . . . . . . . . . . . . . . . . . A.2.5 Electric Fence . . . . . . . . . . . . . . . . . . . . . . A.2.6 Escolhendo Entre as Diferentes Ferramentas Depuradoras de Memria . . . . . . . . . . . . . . . . . . . . o A.2.7 Cdigo Fonte para o Programa de Memria o o Dinmica . . . . . . . . . . . . . . . . . . . . . . . . a A.3 Montando Perl . . . . . . . . . . . . . . . . . . . . . . . . . A.3.1 Uma Calculadora Simples . . . . . . . . . . . . . . . A.3.2 Coletando Informaes de Montagem de Perl . . . . co A.3.3 Mostrando Dados de Montagem de Perl . . . . . . . A.3.4 Como gprof Coleta Dados . . . . . . . . . . . . . . . A.3.5 Cdigo Fonte do Programa Calculadora . . . . . . . . o B E/S de Baixo N vel B.1 Lendo e Escrevendo Dados . . . . . . . . . . . . . . . . . B.1.1 Abrindo um Arquivo . . . . . . . . . . . . . . . . B.1.2 Fechando Descritores de Arquivo . . . . . . . . . B.1.3 Escrevendo Dados . . . . . . . . . . . . . . . . . . B.1.4 Lendo Dados . . . . . . . . . . . . . . . . . . . . B.1.5 Movendo-se ao Longo de um Arquivo . . . . . . . B.2 stat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.3 Leituras e Escritas de Vetor . . . . . . . . . . . . . . . . B.4 Relao de Funes de E/S da Biblioteca C GNU Padro ca co a B.5 Outras Operaes de Arquivo . . . . . . . . . . . . . . . co B.6 Lendo o Contedo de um Diretrio . . . . . . . . . . . . u o C Tabela de Sinais

. . . . . . . . . . .

. . . . . . . . . . .

333 . 334 . 334 . 337 . 337 . 339 . 341 . 344 . 346 . 349 . 350 . 351 355

D Recursos Online D.1 Informao Geral . . . . . . . . . . . . . . . . . . . . . . . . ca D.2 Informao Sobre Software GNU/Linux . . . . . . . . . . . . ca D.3 Outros S tios . . . . . . . . . . . . . . . . . . . . . . . . . . E Open Publication License F GNU General Public License G Sa das Diversas do /proc G.1 cat /proc/cpuinfo . . . . . . . . . . . . G.2 Entradas de um Diretrio de Processo . o G.3 cat /proc/version . . . . . . . . . . . . G.4 cat /proc/scsi/scsi . . . . . . . . . . . G.5 cat /proc/sys/dev/cdrom/info . . . . . G.6 cat /proc/mounts . . . . . . . . . . . . G.7 cat /proc/locks . . . . . . . . . . . . .

359 . 359 . 359 . 360 361 365 373 373 380 380 381 381 382 382

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

H Adicionais ao Cap tulo 8 H.1 strace hostname . . . . . . . . . . . . . . . . . . . . . . . . . H.2 sysctl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . H.3 Ano de 1970 . . . . . . . . . . . . . . . . . . . . . . . . . . . I

385 . 385 . 386 . 398

Assembly 401 I.1 Al Mundo . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401 o I.2 bsrl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402

J Segurana c 403 J.1 Setuid no Debian 6.0.2 . . . . . . . . . . . . . . . . . . . . . . 403 K Anexos aos Apndices e 405 K.1 Signal.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405 K.2 Analizadores de Cdigo . . . . . . . . . . . . . . . . . . . . . . 405 o L Licena de Livre Publicao c ca M A Licena P blica Geral do GNU - pt BR c u 407 409

Lista de Tabelas
2.1 6.1 6.2 7.1 9.1 Opes do Programa Exemplo . . . . . . . . . . . . . . . . . . 26 co Lista Parcial de Dispositivos de Bloco Comuns . . . . . . . . . 168 Alguns Dispostivos de Caractere Comuns . . . . . . . . . . . . 169 Caminhos Completos para os Quatro Poss veis Dispositivos IDE202 Letras de registradores para a Arquitetura x86 Intel. . . . . . 240

A.1 Capacidades das Ferramentas de Vericao Dinmica de Memria ca a o (X Indica Deteco, e O Indica Deteco para Alguns Casos) . 315 ca ca C.1 Sinais do GNU/Linux . . . . . . . . . . . . . . . . . . . . . . . 356 C.2 Sinais do GNU/Linux - Continuao . . . . . . . . . . . . . . 357 ca

xxi

Listagem Cdigos Fonte o


1.1 1.2 1.3 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 2.10 3.1 3.2 3.3 3.4 3.5 3.6 3.7 4.1 4.2 4.3 4.4 4.5 4.6 4.7 Arquivo Cdigo fonte em C main.c . . . . . . . . . . . . . . o Arquivo Cdigo fonte em C++ reciprocal.cpp . . . . . . . . o Arquivo de cabealho reciprocal.hpp . . . . . . . . . . . . . c (Arquivo arglist.c) Usando argc e argv. . . . . . . . . . . . . . (getopt long.c) Usando a funo getopt long . . . . . . . . . . ca (getopt long.c) Continuao . . . . . . . . . . . . . . . . . . . ca (print-env.c) Mostrando o Ambiente de Execuo . . . . . . . ca (client.c) Parte de um Programa Cliente de Rede . . . . . . . (temp le.c) Usando mkstemp . . . . . . . . . . . . . . . . . . (readle.c) Liberando Recursos em Condies Inesperadas . . co (test.c) Area da Biblioteca . . . . . . . . . . . . . . . . . . . . Um Programa Que Utiliza as Funes da Biblioteca Acima . . co (titest.c) Usando a libti . . . . . . . . . . . . . . . . . . . . ( print-pid.c) Mostrando o ID do Processo . . . . . . . . . . . (system.c) Usando uma chamada ` funo system . . . . . . . a ca ( fork.c) Usando fork para Duplicar o Processo de um Programa ( fork-exec.c) Usando fork e exec Juntas . . . . . . . . . . . . (sigusr1.c) Usando um Manipulador de Sinal . . . . . . . . . . (zombie.c) Fazendo um Processo Zumbi . . . . . . . . . . . . . (sigchld.c) Limpando Processos lhos pelo manuseio de SIGCHLD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ( thread-create.c) Criando uma Linha de Execuo . . . . . . ca ( thread-create2) Cria Duas Linhas de Execuo . . . . . . . . ca Funo main revisada para thread-create2.c . . . . . . . . . . ca ( primes.c) Calcula Nmeros Primos em uma Linha de Execuo u ca (detached.c) Programa Esqueleto Que Cria uma Linha dde Execuo Desvinculada . . . . . . . . . . . . . . . . . . . . . . ca (critical-section.c) Protege uma Transao Bancria com uma ca a Seo Cr ca tica . . . . . . . . . . . . . . . . . . . . . . . . . . . (tsd.c) Log Por Linhas de Execuo Implementado com Dados ca Espec cos de Linha de Execuo . . . . . . . . . . . . . . . . ca xxiii 9 9 9 25 29 30 35 35 38 46 48 48 52 58 61 62 64 68 72 74 80 81 83 85 87 91 94

4.8 4.9 4.10 4.11 4.12 4.13 4.14 4.15 4.16 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 5.10 5.11 5.12 6.1 6.2 7.1 7.2 7.3 7.4 7.5 7.6

(cleanup.c) Fragmento de Programa Demonstrando um Manipulador de Limpeza de Linha de Execuo . . . . . . . . . . . 96 ca (cxx-exit.cpp) Implementando Sa Segura de uma Linha de da Execuo com Excees de C++ . . . . . . . . . . . . . . . . 97 ca co ( job-queue1.c) Funo de Linha de Execuo para Processar ca ca Trabalhos Enleirados . . . . . . . . . . . . . . . . . . . . . . 99 ( job-queue2.c) Funo de Tarefa da Fila de Trabalho, Proteca gida por um Mutex . . . . . . . . . . . . . . . . . . . . . . . . 102 ( job-queue3.c) Fila de Trabalhos Controlada por um Semforo 108 a ( job-queue3.c) Continuao . . . . . . . . . . . . . . . . . . . 109 ca (spin-condvar.c) Uma Implementao Simples de Varivel Conca a dicional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 (condvar.c) Controla uma Linha de Execuo Usando uma ca Varivel Condicional . . . . . . . . . . . . . . . . . . . . . . . 114 a (thread-pid) Imprime IDs de processos para Linhas de Execuo116 ca Exerc de Memria Compartilhada . . . . . . . . . . . . . . 127 cio o (sem all deall.c) Alocando e Desalocando um semforo Binrio 129 a a (sem init.c) Inicializando um Semforo Binrio . . . . . . . . . 130 a a co a a (sem pv.c) Operaes Wait e Post para um Semforo Binrio 131 (mmap-write.c) Escreve um Nmero Aleatrio para um Aru o quivo Mapeado em Memria . . . . . . . . . . . . . . . . . . . 134 o (mmap-read.c) L um Inteiro a partir de um Arquivo Mapeado e em Memria, e Dobra-o . . . . . . . . . . . . . . . . . . . . . 135 o (pipe.c) Usando um pipe para Comunicar-se com um Processo Filho . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 (dup2.c) Redirecionar a Sa de um pipe com dup2 . . . . . . 142 da (popen.c) Exemplo Usando popen . . . . . . . . . . . . . . . . 143 (socket-server.c) Servidor de Socket de Escopo Local . . . . . 151 (socket-client.c) Cliente de Socket de Escopo Local . . . . . . 152 (socket-inet.c) L de um Servidor WWW . . . . . . . . . . . . 154 e ca u o (random number.c) Funo para Gerar um Nmero Aleatrio 175 (cdrom-eject.c) Ejeta um CD-ROM/DVD . . . . . . . . . . . . 182 (clock-speed.c) Extraindo a Velocidade de Clock da CPU de /proc/cpuinfo . . . . . . . . . . . . . . . . . . . . . . . . . . . 186 (get-pid.c) Obtendo o ID de Processo de /proc/self . . . . . . 189 (print-arg-list.c) Mostra na Tela a Lista de Arguentos de um Processo que est Executando . . . . . . . . . . . . . . . . . . 191 a (print-environment.c) Mostra o Ambiente de um Processo . . . 192 (get-exe-path.c) Pega o Caminho do Programa Executando Atualmente . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193 (open-and-spin.c) Abre um Arquivo para Leitura . . . . . . . 195

7.7 (print-uptime.c) Mostra o Tempo Ligado e o Tempo Ocioso . . 8.1 (check-access.c) Check File Access Permissions . . . . . . . . . 8.2 (lock-le.c) Create a Write Lock with fcntl . . . . . . . . . . . 8.3 (write journal entry.c) Write and Sync a Journal Entry . . . . 8.4 (limit-cpu.c) Demonstrao do Tempo Limite de Uso da CPU ca 8.5 (print-cpu-times.c) Mostra Usurio de Processo e Horas do a Sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.6 (print-time.c) Mostra a Data e a Hora . . . . . . . . . . . . . 8.7 (mprotect.c) Detecta Acesso ` Memria Usando mprotect . . . a o 8.8 (better sleep.c) High-Precision Sleep Function . . . . . . . . . 8.9 (print-symlink.c) Mostra o Alvo de um Link Simblico . . . . o 8.10 (copy.c) Cpia de Arquivo Usando sendle . . . . . . . . . . . o 8.11 (itimer.c) Exemplo de Temporizador . . . . . . . . . . . . . . 8.12 (sysinfo.c) Mostra Estat sticas do Sistema . . . . . . . . . . . 8.13 (print-uname.c) Mostra o nmero de Verso do GNU/Linux e u a Informao de Hardware . . . . . . . . . . . . . . . . . . . . . ca 9.1 (bit-pos-loop.c) Encontra a Posio do Bit Usando um Lao . ca c 9.2 (bit-pos-asm.c) Encontra a posio do Bit Usando bsrl . . . . ca 10.1 (simpleid.c) Mostra ID de usurio e ID de grupo . . . . . . . . a 10.2 (stat-perm.c) Determina se o Proprietrio do Arquivo Tem a Permisso de Escrita . . . . . . . . . . . . . . . . . . . . . . . a 10.3 (setuid-test.c) Programa de Demonstrao do Setuid . . . . . ca 10.4 ( pam.c) Exemplo de Uso do PAM . . . . . . . . . . . . . . . 10.5 (temp-le.c) Cria um Arquivo Temporrio . . . . . . . . . . . a 10.6 ( grep-dictionary.c) Busca por uma Palavra no Dicionrio . . . a 11.1 (server.h) Declaraes de Funes e de Variveis . . . . . . . . co co a 11.2 (common.c) Funes de Utilidade Geral . . . . . . . . . . . . . co 11.3 (common.c) Continuao . . . . . . . . . . . . . . . . . . . . . ca 11.4 (module.c) Carregando e Descarregando Mdulo de Servidor . o 11.5 (server.c) Implementao do Servidor . . . . . . . . . . . . . . ca 11.6 (server.c) Continuao . . . . . . . . . . . . . . . . . . . . . . ca 11.7 (server.c) Continuao . . . . . . . . . . . . . . . . . . . . . . ca 11.8 (server.c) Continuao . . . . . . . . . . . . . . . . . . . . . . ca 11.9 (main.c) Programa Principal do Servidor e Tratamento de Linha de Comando . . . . . . . . . . . . . . . . . . . . . . . . . 11.10(main.c) Continuao . . . . . . . . . . . . . . . . . . . . . . . ca 11.11(main.c) Continuao . . . . . . . . . . . . . . . . . . . . . . . ca 11.12(time.c) Mdulo do Servidor para Mostrar a Hora Relgio Coo o mum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.13(issue.c) Mdulo de Servidor para Mostrar Informao da Diso ca tribuio GNU/Linux . . . . . . . . . . . . . . . . . . . . . . . ca

206 213 215 217 219 220 222 226 228 229 230 232 233 234 243 243 249 252 258 261 268 270 277 278 279 281 283 284 285 286 289 290 291 292 293

11.14(diskfree.c) Mdulo de Servidor para Mostrar Informaes Soo co bre Espao Livre no Disco . . . . . . . . . . . . . . . . . . . c 11.15( processes.c) Mdulo de Servidor para Sumarizar Processos o 11.16( processes.c) Continuao . . . . . . . . . . . . . . . . . . . ca 11.17( processes.c) Continuao . . . . . . . . . . . . . . . . . . . ca 11.18( processes.c) Continuao . . . . . . . . . . . . . . . . . . . ca 11.19(Makele) GNU Make Conguration File for Server Example A.1 (hello.c) Programa Al Mundo . . . . . . . . . . . . . . . . . o A.2 (malloc-use.c) Exemplo de Como Testar Alocao Dinmica ca a de Memria . . . . . . . . . . . . . . . . . . . . . . . . . . . o A.3 (malloc-use.c) Exemplo de Como Testar Alocao Dinmica ca a de Memria . . . . . . . . . . . . . . . . . . . . . . . . . . . o A.4 (calculator.c) Programa Principal da Calculadora . . . . . . A.5 (calculator.c) Continuao . . . . . . . . . . . . . . . . . . . ca A.6 (number.c) Implementao de Nmero Unrio . . . . . . . . ca u a A.7 (number.c) Continuao . . . . . . . . . . . . . . . . . . . . ca A.8 (stack.c) Pilha do Nmero Unrio . . . . . . . . . . . . . . . u a A.9 (stack.c) Continuao . . . . . . . . . . . . . . . . . . . . . . ca A.10 (denitions.h) Header File for number.c and stack.c . . . . . B.1 (create-le.c) Create a New File . . . . . . . . . . . . . . . . B.2 (timestamp.c) Anexa uma Timestamp a um Arquivo . . . . B.3 (write-all.c) Escreve Tudo de uma Area Temporria de Armaa zenagem de Dados . . . . . . . . . . . . . . . . . . . . . . . B.4 (hexdump.c) Mostra uma Remessa de caracteres em Hexadecimal de um Arquivo . . . . . . . . . . . . . . . . . . . . . . B.5 (lseek-huge.c) Cria Grandes Arquivos com lseek . . . . . . . B.6 (read-le.c) L um Arquivo para dentro de um Espao Teme c porrio de Armazenagem . . . . . . . . . . . . . . . . . . . . a B.7 (write-args.c) Escreve a Lista de Argumentos para um Arquivo com writev . . . . . . . . . . . . . . . . . . . . . . . . . . . . B.8 (listdir.c) Print a Directory Listing . . . . . . . . . . . . . .

. . . . . . .

294 296 297 298 299 302 312

. 322 . . . . . . . . . . 323 329 330 330 331 331 332 332 336 338

. 339 . 341 . 343 . 346 . 348 . 352

Parte I Programao UNIX Avanada ca c com Linux

1 Iniciando 2 O Sistema de Arquivos /proc 3 Processos 4 Linhas de Execuo ca 5 Comunicao Entre Processos ca

Cap tulo 1 Iniciando


ESSE CAP ITULO MOSTRA COMO EXECUTAR OS PASSOS bsicos rea queridos para criar um programa Linux usando a linguagem C ou a linguagem C++. Em particular, esse cap tulo mostra como criar e modicar cdigo o fonte C e C++, compilar esse cdigo modicado, e depurar o resultado. Se o voc tem experincia em programao em ambiente Linux, voc pode pue e ca e lar agora para o Cap tulo 2, Escrevendo Bom Software GNU/Linux prestando cuidadosa ateno ` seo 2.3, Escrevendo e Usando Bibliotecas para ca a ca informaes sobre linkagem/vinculao esttica versus linkagem/vinculao co ca a ca dinmica `s quais voc pode no conhecer ainda. a a e a No decorrer desse livro, assumiremos que voc est familiarizado com as e a linguagens de programao C ou C++ e as funes mais comuns da biblioteca ca co C GNU padro. Os exemplos de cdigo fonte nesse livro esto em C, exceto a o a quando for necessrio demonstrar um recurso particular ou complicao de a ca programa em C++. Tambm assumiremos que voc conhece como executar e e operaes bsicas na linha de comando do Linux, tais como criar diretrios e co a o copiar arquivos. Pelo fato de muitos programadores de ambiente GNU/Linux terem iniciado programao no ambiente Windows, iremos ocasionalmente ca mostrar semelhanas e diferenas entre Windows e GNU/Linux. c c

1.1

Editando com Emacs

Um editor o programa que voc usa para editar o cdigo fonte. Muitos e e o editores esto dispon a veis para Linux, mas o editor mais popular e cheio de recursos provavelmente GNU Emacs. e 5

Sobre o Emacs: Emacs muito mais que um editor. Emacs um programa inacreditavelmente e e poderoso, tanto que em CodeSourcery, Emacs afetuosamente conhecido como e Um Verdadeiro Programa, ou apenas o UVP de forma curta. Voc pode ler e e enviar mensagens eletrnicas de dentro do Emacs, e voc pode personalizar e o e extender o Emacs de formas muito numerosas para discorrer aqui. Voc pode e at mesmo navegar na web de dentro do Emacs! e

Caso voc esteja familiarizado com outro editor, voc pode certamente e e us-lo no lugar do Emacs. Note que o restante desse livro est vinculado ao a a uso do Emacs. Se voc ainda no tem um editor Linux favorito, ento voc e a a e deve seguir adiante com o mini-tutorial fornecido aqui. Se voc gosta do Emacs e deseja aprender sobre seus recursos avanados, e c voc pode considerar ler um dos muitos livros sobre Emacs dispon e veis. Um excelente tutorial Learning GNU Emacs, escrito por Debra Cameron, e Bill Rosenblatt, e Eric S. Raymond (Editora OReilly, 1996).

1.1.1

Abrindo um Arquivo Fonte em C ou em C++

Voc pode iniciar o Emacs digitando emacs em sua janela de terminal e e pressionado a tecla Enter. Quando Emacs tiver iniciado, voc pode usar e os menus localizados na parte superior para criar um novo arquivo fonte. Clique no menu File, escolha Open File, ento digite o nome do arquivo a que voc deseja abrir no minibuer localizado na parte inferior da tela.1 e Se quiser criar um arquivo fonte na linguagem C, use um nome de arquivo que termine em .c ou em .h. Se voc quiser criar um arquivo fonte em e C++, use um nome de arquivo que termine em .cpp, .hpp, .cxx, .hxx, .C, ou .H. Quando o arquivo estiver aberto, voc pode digitar da mesma forma e que faria em qualquer programa processador de texto comum. Para gravar o arquivo, escolha a entrada Save no menu File. Quando voc tiver e encerrado a utilizao do Emacs, voc pode escolher a opo Exit Emacs ca e ca no menuFile. Se voc no gosta de apontar e clicar, voc pode usar teclas de atalho e a e de teclado para automaticamente abrir arquivos, gravar arquivos, e sair do Emacs. Para abrir um arquivo, digite C-x C-f. (O C-x signica pressionar a tecla ctrl e ento pressionar a tecla x.) Para gravar um arquivo, digite C-x a C-s. Para sair do Emacs, apenas digite C-x C-c. Se voc desejar adquirir um e pouco mais de habilidade com Emacs, escolha a entrada Emacs Tutorial no menu Help.O tutorial abastece voc com uma quantidade grande de e dicas sobre como usar Emacs efetivamente.
Se voc no est executando em um sistema X Window, voc ter de pressionar F10 e a a e a para acessar os menus.
1

1.1.2

Formatando Automaticamente

Se voc est acostumado a programar em um Ambiente Integrado de Dee a senvolvimento (IDE)2 , voc consequentemente estar tambm acostumado a e a e ter o editor ajudando voc a formatar seu cdigo. Emacs pode fornecer o e o mesmo tipo de funcionalidade. Se voc abre um arquivo de cdigo em C e o ou em C++, Emacs automaticamente detecta que o arquivo contm cdigo e o fonte, no apenas texto comum. Se voc pressiona a tecla Tab em uma linha a e em branco, Emacs move o cursor para um ponto ajustado apropriadamente. Se voc pressionar a tecla Tab em uma linha que j contm algum texto, e a e Emacs ajusta o texto. Ento, por exemplo, suponha que voc tenha digitado a e o seguinte: int main ( ) { p r i n t f ( Alo , mundo\n ) ; } Se voc pressionar a tecla Tab na linha com a chamada ` funo printf, e a ca Emacs ir reformatar seu cdigo para parecer como mostrado abaixo: a o int main ( ) { p r i n t f ( Alo , mundo\n ) ; } Note como a linha foi apropriadamente indentada. ` A medida que seu uso do Emacs for acontecendo, voc ver como o Emacs e a pode ajudar voc a executar todo tipo de complicadas tarefas de formatao. e ca Se voc for ambicioso, voc pode programar o Emacs para executar literale e mente qualquer tipo de formatao automtica que voc puder imaginar. ca a e Pessoas tm usado essa facilidade de programao para implementar modos e ca Emacs para editar todo tipo de documento, para implementar jogos3 e para implementar interfaces para usurios acessarem bases de dados. a

1.1.3

Destaque Sinttico para Palavras Importantes a

Adicionalmente ` formatao de seu cdigo, Emacs pode destacar palavras a ca o facilmente ao ler cdigo em C e em C++ atravs da colorao de diferentes o e ca
Do ingls Integrated Development Environment. Em nosso bom portugus caria e e AID. 3 Tente executar o comando M-x dunnet se voc desejar divertir-se com um antiquae dro jogo de aventura em modo texto. Nota do tradutor: Dunnet um jogo distribu e do junto com o emacs cuja primeira verso datava dos idos de 1983. a
2

elementos sintticos. Por exemplo, Emacs pode atribuir a palavra chaves uma a certa cor, atribuir uma segunda cor diferente da anterior a tipos de dados internos tais como int, e atribuir a comentrios outra terceira cor diferente a das duas primeiras. A utilizao de cor torna muito mais fcil destacar alguns ca a erros comum de sintaxe. A forma mais fcil de habilitar cores editar o arquivo a e /.emacs e inserir a seguinte sequncia de caracteres: e

(global-font-lock-mode t) Grave o arquivo, saia do Emacs, e volte a ele em seguida. Agora abra um cdigo fonte em C ou em C++ e aproveite! o Voc possivelmente pode ter notado que a sequncia de caracteres que e e voc inseriu dentro do seu .emacs semelhante a um cdigo da linguagem de e e o programao LISP.Isso ocorre pelo fato de ser um cdigo LISP! Muitas partes ca o de cdigo do Emacs so atualmente escritas em LISP. Voc pode adicionar o a e funcionalidades ao Emacs por meio de acrscimos em cdigo LISP. e o

1.2

Compilando com GCC

Um compilador converte um cdigo fonte leg o vel a seres humanos em um cdigo objeto leg o vel a computadores que pode ento ser executado. Os a compiladores dispon veis em sistemas linux so todos parte da coleo de a ca 4 compiladores GNU, comumente conhecido como GCC. GCC tambm inclui e compiladores para as linguagens C, C++, Java, Objective-C, Fortran, e Ada. Esse livro est dirigido em sua grande parte para programao em C e C++. a ca Suponhamos que voc tenha um projeto como o da Listagem 1.2 com um e arquivo de cdigo em C++ (reciprocal.cpp) e um arquivo de cdigo fonte em o o C (main.c) como o da Listagem 1.1. Esses dois arquivos so supostamente a para serem compilados e ento linkados juntos para produzir um programa a chamado reciprocal.5 Esse programa ir calcular o rec a proco/inverso de um inteiro.
Para mais informao sobre GCC, visite http://gcc.gnu.org. ca Em Windows, arqu vos executveis geralmente possuem nomes que terminam em a .exe. Programas GNU/Linux, por outro lado, geralmente no possuem extenso. Ento, a a a o equivalente Windows do programa reciprocal pode provavelmente ser chamado reciprocal.exe; a verso GNU/Linux somente reciprocal. a e
5 4

Listagem 1.1: Arquivo Cdigo fonte em C main.c o


1 2 3 4 5 6 7 8 9 10 11 12 #include <s t d i o . h> #include < s t d l i b . h> #include r e c i p r o c a l . hpp i n t main ( i n t a r g c , char a r g v ) { int i ; i = a t o i ( argv [ 1 ] ) ; p r i n t f ( The r e c i p r o c a l return 0 ; }

o f %d i s %g \n , i ,

reciprocal

(i));

Listagem 1.2: Arquivo Cdigo fonte em C++ reciprocal.cpp o


1 2 3 4 5 6 7 8 #include <c a s s e r t > #include r e c i p r o c a l . hpp double r e c i p r o c a l ( i n t // A v a r i a v e l i d e v e a s s e r t ( i != 0 ) ; return 1 . 0 / i ; } i) { s e r nao n u l a .

Existe tambm um arquivo de cabealho chamado reciprocal.hpp (veja a e c Listagem 1.3). Listagem 1.3: Arquivo de cabealho reciprocal.hpp c
1 2 3 4 5 6 7 8 9 #i f d e f cplusplus extern C { #e n d i f extern #i f d e f } #e n d i f double r e c i p r o c a l cplusplus ( int i);

O primeiro passo converter o cdigo fonte em C e em C++ em cdigo e o o objeto.

1.2.1

Compilando um Unico Arquivo de Cdigo Fonte o

O nome do compilador C gcc. Para compilar um cdigo fonte em C (gerar e o o arquivo objeto), voc usa a opo -c. Ento, por exemplo, inserindo o -c e ca a no prompt de comando compila o arquivo de cdigo fonte main.c: o % gcc -c main.c O arquivo objeto resultante chamado main.o. O compilador C++ e e chamado g++. Sua operao muito similar ao gcc; a compilao de recica e ca procal.cpp realizada atravs do seguinte comando: e e 9

% g++ -c reciprocal.cpp A opo -c diz ao compilador g++ para fornecer como sa um arquivo ca da objeto somente; sem essa opo, g++ iria tentar linkar o programa para ca produzir um executvel. Aps voc ter digitado esse comando, voc ir ter a o e e a um arquivo objeto chamado reciprocal.o. Voc ir provavelmente precisar de algumas outras opes para construir e a co qualquer programa razovelmente grande. A opo -I usada para dizer a ca e ao GCC onde procurar por arquivos de cabealho. Por padro, GCC olha c a no diretrio atual e nos diretrios onde cabealhos para bibliotecas C GNU o o c padro esto instalados. Se voc precisar incluir arquivos de cabealho loa a e c calizados em algum outro lugar, voc ir precisar da opo -I. Por exemplo, e a ca suponhamos que seu projeto tenha um diretrio chamado src, para aro quivos fonte, e outro diretrio chamado include. Voc pode compilar o o e arquivo reciprocal.cpp como segue abaixo para indicar que g++ deve usar o diretrio ../include adicionalmente para encontrar o arquivo de cabealho o c reciprocal.hpp: % g++ -c -I ../include reciprocal.cpp Algumas vezes voc ir desejar denir macros na linha de comando. Por e a exemplo, no cdigo de produo, voc no ir querer o trabalho adicional da o ca e a a checagem de declarao presente em reciprocal.cpp; a checagem s existe para ca o ajudar a voc a depurar o programa. Voc desabilita a checagem denindo a e e macro NDEBUG. Voc pode ter adicionado uma declarao expl e ca cita #dene em reciprocal.cpp, mas isso requer modicao no cdigo fonte em si. E ca o mais fcil simplesmente denir NDEBUG na linha de comando, como segue: a % g++ -c -D NDEBUG reciprocal.cpp Se voc tiver desejado denir NDEBUG para algum valor particular, voc e e pode ter feito algo como: % g++ -c -D NDEBUG=3 reciprocal.cpp Se voc estiver realmente construindo cdigo fonte de produo, voc e o ca e provavelmente deseja que o GCC otimize o cdigo de forma que ele rode to o a rapidamente quanto poss vel.Voc pode fazer isso atravs da utilizao da e e ca opo -O2 de linha de comando. (GCC tem muitos diferentes n ca veis de otimizao; o segundo n apropriado para a maioria dos programas.) Por ca vel e exemplo, o comando adiante compila reciprocal.cpp com otimizao habilica tada: 10

% g++ -c -O2 reciprocal.cpp Note que compilando com otimizao pode fazer seu programa mais dif ca cil de depurar com um depurador (veja a Seo 1.4, Depurando com o Depuca rador GNU (GDB)). Tambm, em certas instncias, compilando com otie a mizao pode revelar erros em seu programa que no apareceriam em outras ca a situaes anteriores. co Voc pode enviar muitas outras opes ao compilador gcc e ao compilador e co g++. A melhor forma de pegar uma lista completa ver a documentao e ca em tempo real. Voc pode fazer isso digitando o seguinte na sua linha de e comando: % info gcc

1.2.2

Linkando Arquivos Objeto

Agora que voc compilou main.c e reciprocal.cpp, voc ir desejar juntar e e a os cdigos objeto e gerar o executvel. Voc deve sempre usar o g++ para o a e linkar um programa que contm cdigo em C++, mesmo se esse cdigo C++ e o o tambm contenha cdigo em C. Se seu programa contiver somente cdigo em e o o C, voc deve usar o gcc no lugar do g++. Pelo fato de o g++ est apto a e a tratar ambos os arquivos em C e em C++, voc deve usar g++, como segue e adiante: % g++ -o reciprocal main.o reciprocal.o A opo -o fornece o nome do arquivo a ser gerado como sa no passo ca da de linkagem. Agora voc pode executar o reciprocal como segue: e % ./reciprocal 7 The reciprocal of 7 is 0.142857 Como voc pode ver, g++ linkou/vinculou automaticamente a biblioe teca C GNU padro em tempo de execuo contendo a implementao da a ca ca funo. Se voc tiver precisado linkar outra biblioteca (tal como uma coleo ca e ca de rotinas/cdigos prontos para facilitar a criao de uma interface grca o ca a de usurio)6 , voc pode ter especicado a biblioteca com a opo -l. Em a e ca GNU/Linux, nomes de biblioteca quase sempre comeam com lib. Por c exemplo, a biblioteca Pluggable Authentication Module (PAM) chamada e libpam.a. Para linkar a libpam.a, voc usa um comando como o seguinte: e
6

Nota do tradutor: QT ou Gtk.

11

% g++ -o reciprocal main.o reciprocal.o -lpam O compilador automaticamente adiciona o prexo lib e o suxo .a7 . Da mesma forma que para os arquivos de cabealho, o linkador procura por c bibliotecas em alguns lugares padro, incluindo os diretrios /lib e /usr/lib a o onde esto localizadas as bibliotecas padro do sistema. Se voc deseja que a a e o linkador procure em outros diretrios tambm, voc deve usar a opo -L, o e e ca que a correspondente da opo -I discutida anteriormente. Voc pode usar e ca e essa linha para instruir o linkador a procurar por bibliotecas no diretrio o /usr/local/lib/pam antes de procurar nos lugares usuais:
% g++ -o reciprocal main.o reciprocal.o -L/usr/local/lib/pam -lpam

Embora voc no tenha a opo -I para instruir o preprocessor para proe a ca curar o diretrio atual, voc deve usar a opo -L para instruir o linkador o e ca a procurar no diretrio atual. Dizendo mais claramente, voc pode usar a o e seguinte linha para instruir o linkador a encontrar a biblioteca test no diretrio atual: o % gcc -o app app.o -L. -ltest

1.3

Automatizando com GNU Make

Se voc est acostumado a programar para o sistema operacional Windows, e a voc est provavelmente acostumado a trabalhar com um Ambiente Intee a grado de Desenvolvimento (IDE).Voc adiciona arquivos de cdigo fonte a e o seu projeto, e ento o IDE contri seu projeto automaticamente. Embora a o IDEs sejam dispon veis para GNU/Linux, esse livro no vai discut a -las. Em lugar de discutir IDEs, esse livro mostra a voc como usar o GNU Make para e automaticamente recompilar seu cdigo, que o que a maioria dos prograo e madores GNU/Linux atualmente fazem. A idia bsica por trs do make simples. Voc diz ao make os alvos que e a a e e voc deseja construir e ento fornece regras explanatria de como construir os e a o alvos desejados. Voc tambm especica dependncias que indicam quando e e e um alvo em particular deve ser reconstru do. Em nosso projeto exemplo reciprocal, existem trs alvos bvios: reciproe o cal.o, main.o, e o reciprocal executvel propriamente dito. Voc j tinha a e a regras em mente para reconstruir esses alvos na forma da linha de comando fornecidas previamente. As dependncias requerem um pouco de racioc e nio.
Nota do tradutor: a biblioteca PAM pode ser encontrada em http://ftp.mgts.by/ pub/linux/libs/pam/library/.
7

12

Claramente, reciprocal depende de reciprocal.o e de main.o pelo fato de voc e no poder linkar o programa at voc ter constru cada um dos arquivos a e e do objetos. Os arquivos objetos devem ser reconstru dos sempre que o correspondente arquivo fonte mudar. Se acontece mais uma modicao em ca reciprocal.hpp isso tambm deve fazer com que ambos os arquivos objetos e sejam reconstru dos pelo fato de ambos os arquivos fontes incluirem o reciprocal.hpp. Adicionalmente aos alvos bvios, deve-se ter sempre um alvo de limpeza. o Esse alvo remove todos os arquivos objetos gerados e programas de forma que voc possa iniciar de forma suave. A regra para esse alvo utiliza o comando e rm para remover os arquivos. Voc pode reunir toda essa informao para o make colocando a ine ca formao em um arquivo chamado Makele. Aqui est um exemplo de ca a contedo de Makele: u reciprocal: main.o reciprocal.o g++ $(CFLAGS) -o reciprocal main.o reciprocal.o main.o: main.c reciprocal.hpp gcc $(CFLAGS) -c main.c reciprocal.o: reciprocal.cpp reciprocal.hpp g++ $(CFLAGS) -c reciprocal.cpp clean: rm -f *.o reciprocal Voc pode ver que alvos so listados do lado esquerdo, seguidos por dois e a pontos e ento quaisquer dependncia so colocadas adiante dos dois pontos. a e a A regra para construir o referido alvo localiza-se na linha seguinte. (Ignore o $(CFLAGS) um pouco por um momento.) A linha com a regra para esse alvo deve iniciar com um caractere de tabulao, ou make ir se confundir. Se ca a voc editar seu Makele no Emacs, Emacs ir ajudar voc com a formatao. e a e ca Se voc tiver removido os arquivos objetos que voc construiu anteriormente, e e e apenas digitar % make na linha de comando, voc ir ver o seguinte: e a % make gcc -c main.c 13

g++ -c reciprocal.cpp g++ -o reciprocal main.o reciprocal.o Voc pode ver que make contri automaticamente os arquivos objetos e e o ento linka-os. Se voc agora modicar por algum motivo o main.c e digitar a e make novemente, voc ir ver o seguinte: e a % make gcc -c main.c g++ -o reciprocal main.o reciprocal.o Voc pode ver que make soube reconstruir main.o e re-linkar o programa, e mas o make no se incomodou em recompilar reciprocal.cpp pelo fato de a nenhuma das dependncias para reciprocal.o ter sofrido alguma modicao. e ca O $(CFLAGS) uma varivel do make. Voc pode denir essa varvel ou no e a e a Makele mesmo ou na linha de comando. GNU make ir substituir o valor a da varivel quando executar a regra. Ento, por exemplo, para recompilar a a com otimizao habilitada, voc deve fazer o seguinte: ca e % make clean rm -f *.o reciprocal % make CFLAGS=-O2 gcc -O2 -c main.c g++ -O2 -c reciprocal.cpp g++ -O2 -o reciprocal main.o reciprocal.o

1.4

Depurando com o Depurador GNU (GDB)

Note que o sinalizador -O2 foi inserido no lugar de $(CFLAGS) na regra. Nessa seo, voc viu somente as mais bsicas capacidades do make. Voc ca e a e pode encontrar mais informaes digitando: co % info make Nas pginas info de manual, voc ir encontrar informaes sobre como a e a co fazer para manter um Makele simples, como reduzir o nmero de regras que u voc precisa escrever, e como automaticamente calcular dependncias. Voc e e e pode tambm encontrar mais informao no livro GNU Autoconf, Automake, e ca and Libtool escrito por Gary V.Vaughan, Ben Elliston,Tom Tromey, e Ian Lance Taylor (New Riders Publishing, 2000). 8
Nota do tradutor: A verso eletrnica do livro pode ser encontrada em http:// a o sources.redhat.com/autobook/download.html.
8

14

1.4.1

Depurando com GNU GDB

O depurador um programa que voc usa para descobrir porque seu proe e grama no est seguindo o caminho que voc pensa que ele deveria. Voc a a e e 9 far isso muitas vezes. O depurador GNU (GDB) o depurador usado pela a e maioria dos programadores em ambiente Linux. Voc pode usar GDB para e passear atravs de seu cdigo fonte, escolhendo pontos de parada, e examinar e o o valor de variveis locais. a

1.4.2

Compilando com Informaes de Depurao co ca

Para usar o GDB, voc ir ter que compilar com as informaes de depurao e a co ca habilitadas. Faa isso adicionado o comutador -g na linha de comando de c compilao. Se voc estiver usando um Makele como descrito anteriormente, ca e voc pode apenas escolher CFLAGS para -g quando voc executar o make, e e como mostrado aqui: % make CFLAGS=-g g++ -c -o reciprocal.o reciprocal.cpp cc -g -O2 main.c reciprocal.o -o main Quando voc compila com -g, o compilador inclui informaes extras nos e co arquivos objetos e executveis. O depurador usa essas informaes para a co descobrir quais endereos correspodem a determinada linha de cdigo e em c o qual arquivo fonte, como mostrar os valores armazenados em variveis locais, a e assim por diante.

1.4.3

Executando o GDB

Voc pode iniciar digitando: e % gdb reciprocal Quando o gdb iniciar, voc ver o prompt do GDB : e a (gdb) O primeiro passo executar seu programa dentro do depurador. Apenas e insira o comando run e quaisquer argumentos do programa que voc est e a depurando. Tente executar o programa sem qualquer argumento, dessa forma 10 :
...a menos que seus programas sempre funcionem da primeira vez. Nota do tradutor: a sa foi obtida em um gdb verso 6.8 em 2009 sendo portanto da a uma atualizao da verso dispon em 2000 que foi o ano da publicao original. ca a vel ca
10 9

15

(gdb) run Starting program: reciprocal Program received signal SIGSEGV, Segmentation fault. 0xb7e7e41b in ____strtol_l_internal () from /lib/libc.so.6 O problema que no existe nenhum cdigo de vericao de entradas e a o ca errneas na funo main. O programa espera um argumento, mas nesse o ca caso o programa estava sendo executado sem argumentos. A mensagem de SIGSEGV indicar uma interrupo anormal do programa 11 . GDB sabe que ca a interrupo anormal que ocorreu agora aconteceu em uma funo chamada ca ca strtol l internal. Aquela funo est na biblioteca C GNU padro. Voc ca a a e 12 pode ver a pilha usando o comando where : (gdb) where #0 0xb7e7e41b #1 0xb7e7e180 #2 0xb7e7b401 #3 0x08048486 ) at main.c:9

in in in in

____strtol_l_internal () from /lib/libc.so.6 strtol () from /lib/libc.so.6 atoi () from /lib/libc.so.6 main (argc=Cannot access memory at address 0x0

Voc pode ver a partir dessa tela que a funo main chamou a funo e ca ca atoi com um apontador NULL, que a fonte de todo o problema. e Voc pode subir dois n e veis na pilha at encontrar a funo main atravs e ca e do uso do comando up: (gdb) up 2 #2 0xb7e7b401 in atoi () from /lib/libc.so.6 Note que gdb capaz de encontrar o cdigo de main.c, e mostra a linha e o onde a chamada errnea de funo ocorreu. Voc pode ver os valores das o ca e variveis usando o comando print: a (gdb) print argv[1] No symbol "argv" in current context. O que conrma que o problema relamente um apontador NULL passado e dentro da funo atoi. ca Voc pode escolher um ponto de parada atravs do uso do comando break : e e
Em ingls: crash. e Nota do tradutor: a sa foi obtida em um gdb verso 6.8 em 2009 sendo portanto da a uma atualizao da verso dispon em 2000 que foi o ano da publicao original. ca a vel ca
12 11

16

(gdb) break main Breakpoint 1 at 0x8048475: file main.c, line 9. Esse comando dene um ponto de parada na primeira linha de main. Agora tente executar novamente o programa com um argumento, dessa forma:
13

(gdb) run 7 The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: reciprocal 7 Breakpoint 1, main (argc=2, argv=0xbfa0d334) at main.c:9 9 i = atoi (argv[1]); Voc pode ver que o depurador alcanou o ponto de parada. Voc pode e c e dar um passo adiante da chamada ` funo atoi usando o comando next: a ca
(gdb) next 10 printf ("The reciprocal of \%d is \%g\\n", i, reciprocal (i));

Se voc desejar ver o que est acontecendo dentro de reciprocal, use o e a comando step como segue: (gdb) step reciprocal (i=7) at reciprocal.cpp:6 6 assert (i != 0); Current language: auto; currently c++ Voc est agora no corpo da funo reciprocal. Voc pode perceber que e a ca e mais conveniente o uso do gdb de dentro do Emacs em lugar de usar o gdb e diretamente na linha de comando. Use o comando M-x gdb para iniciar o gdb em uma janela Emacs. Se voc tiver parado em um ponto de parada, e Emacs automaticamente mostra o arquivo fonte apropriado. Dessa forma ca mais fcil descobrir o que est acontecendo quando voc olha no arquivo a a e completo em lugar de apenas em uma linha de texto.
Algumas pessoas tm comentado que colocando um ponto de parada em main um e e pouco esquisito porque de maneira geral voc somente desejar fazer isso quando main j e a a estiver quebrada.
13

17

1.5

Encontrando mais Informao ca

Praticamente toda distribuio GNU/Linux vem com uma grande quantica dade de documentao util. Voc pode ter aprendido mais do que estamos ca e falando aqui nesse livro por meio da leitura da documentao em sua disca tribuio Linux (embora isso possa provavelmente levar mais tempo). A ca documentao no est sempre bem organizada, de forma que a parte comca a a plicada encontrar o que precisa. Documentao tambm algumas vezes e ca e e desatualizada, ento tome tudo que voc vier a ler como pouca informao. a e ca Se o sistema no comportar-se no caminho apontado pela pgina de manual a a e como ela diz que deve ser, por exemplo, isso pode estar ocorrendo pelo fato de a pgina de manual estar desatualizada. Para ajudar voc a navegar, a e aqui est as mais uteis fontes de informao sobre programao avanada em a ca ca c GNU/Linux.

1.5.1

Pginas de Manual a

Distribuies GNU/Linux incluem pginas de manual para os comandos mais co a padronizados, chamadas de sistema, e funes da biblioteca C GNU padro. co a As man pages so divididas em sees numeradas; para programadores, as a co mais importantes so as seguintes: a (1) Comandos de usurio a (2) Chamadas de sistema (3) Funes da biblioteca C GNU padro co a (8) Comandos de Sistema/administrativos Os nmeros denotam sees das pginas de manual. As pginas de mau co a a nual do GNU/Linux vm instaladas no seu sistema; use o comando man e para acess-las. Para ver uma pgina de manual, simplesmente chame-a esa a crevendo man nome, onde nome um comando ou um nome de funo. Em e ca alguns poucos casos, o mesmo nome aparece em mais de uma seo; voc ca e pode especicar a seo explicitamente colocando o nmero da seo antes ca u ca do nome. Por exemplo, se voc digitar o seguinte, voc ir receber de volta a e e a pgina de manual para o comando sleep (na seo 1 da pagina de manual a ca do GNU/Linux): % man sleep Para ver a pgina de manual da funo de biblioteca sleep, use o coa ca mando adiante: 18

% man 3 sleep Cada pgina de manual inclui um sumrio on-line do comando ou da a a funo. O comando whatis nome mostra todas as pginas de manual (em ca a todas as sees) para um comando ou funo que coincidir com nome. Se co ca voc no tiver certeza acerca de qual comando ou funo voc deseja, voc e a ca e e pode executar uma pesquisa por palavra chave sobre as linhas de sumrio, a usando man -k palavrachave. Pginas de manual incluem uma grande quantidade de informaes muito a co uteis e deve ser o primeiro lugar onde voc vai para obter ajuda. A pgina e a de manual para um comando descreve as opes de linha de comando e arguco mentos, entrada e sa da, cdigos de erro, congurao, e coisas semelhantes. o ca A pgina de manual para um chamada de sistema ou para uma funo de a ca biblioteca descreve os parmetros e valores de retorno, listas de cdigos de a o efeitos colaterais, e especica quais arquivos devem ser colocados na diretiva include se voc desejar chamar essa funo. e ca

1.5.2

Info

A documentao de sistema do tipo Info possuem documentao mais detaca ca lhada para muitos dos principais componentes do sistema GNU/Linux, alm e de muitos outros programas. Pginas Info so documentos no formato de a a hipertexto, semelhantes a pginas Web. Para ativar o navegador de pginas a a Info no formato texto, apenas digite info em uma janela de shell. Voc ir e a ser presenteado com um menu de documentos Info instalado em seu sistema. (Pressione Ctrl+H para mostrar teclas de navegao em um documento Info.) ca O conjunto de documentos Info que so mais uteis em nosso contexto so a a esses: gcc O compilador gcc Libc A biblioteca C GNU padro, incluindo muitas chamadas de a sistema Gdb O depurador GNU Emacs O editor de texto Emacs Info O sistema Info propriamente dito A maioria de todas as ferramentas padronizadas de programao em amca biente GNU/Linux (incluindo o ld, o linkador; as, o assemblador; e gprof, o proler ) so acompanhados com pginas Info bastante uteis. Voc pode ir a a e 19

diretamente a uma documento Info em particular especicando o nome da pgina Info na linha de comando: a % info libc Se voc zer a maioria de sua programao no Emacs, voc pode acessar e ca e o navegador interno de pginas Info digitando M-x info ou C-h i. a

1.5.3

Arquivos de Cabealho c

Voc pode aprender muito sobre funes de sistema que esto dispon e co a veis e como us-las olhando nos arquivos de cabealho do sistema. Esses arquivos a c localizam-se em /usr/include e em /usr/include/sys. Se voc estiver recee bendo erros de compilao ao utilizar uma chamada de sistema, por exemplo, ca d uma olhada no arquivo de cabealho correspondente para vericar se a e c assinatura da funo a mesma que a que est listada na pgina de manual. ca e a a Em sistemas GNU/Linux, muitos dos detalhes importantes e centrais de como as chamadas de sistema trabalham esto reetidos nos arquivos de a cabealho nos diretrios /usr/include/bits, /usr/include/asm, e /usr/incluc o de/linux. Por exemplo, os valores numricos dos sinais (descritos na Seo e ca 3.3, Sinais no Cap tulo 3, Processos) so denidos em /usr/include/a bits/signum.h. Esses arquivos de cabealho so uma boa leitura para mentes c a inquiridoras. No inclua-os diretamente em seus programas; sempre use os a arquivos de cabealho em /usr/include ou como mencionado na pgina de c a manual para a funo que voc est usando. ca e a

1.5.4

Cdigo Fonte o

Isso cdigo aberto, certo? O rbitro nal de como o sistema trabalha e o a e o prprio cdigo fonte do sistema, e afortunadamente para programadores o o em ambiente GNU/Linux, para os quais o cdigo livremente dispon o e vel. Casualmente, sua distribuio inclue o cdigo fonte completo para o sistema ca o completo e todos os programas inclu dos nele; se no, voc est autorizado a e a nos termos da Licena Pblica Geral GNU a requisitar esse cdigo ao disc u o tribuidor. (O Cdigo Fonte pode no estar instalado no seu disco. Veja a o a documentao da sua distribuio para instrues de como instalar os cdigos ca ca co o fonte.) O cdigo fonte para o kernel do GNU/Linux est comumente armazenado o a no diretrio /usr/src/linux. Se esse livro deixa voc ansioso por detalher de o e como os processos, a memria compartilhada, e os dispositivos de sistema o trabalham, voc sempre pode aprender um pouco mais a partir do cdigo e o 20

fonte. A maioria das funes de sistema descritas nesse livro esto impleco a mentadas na biblioteca C GNU padro; verique na documentao de sua a ca distribio pela localizao do cdigo fonte da biblioteca C GNU padro. ca ca o a

21

22

Cap tulo 2 Escrevendo Bom Software GNU/Linux


ESSE CAP ITULO ABRANGE ALGUMAS TECNICAS BASICAS QUE GRANDE PARTE dos programadores GNU/Linux utilizam. Atravs das e orientaes apresentadas adiante, voc estar apto a escrever programas que co e a trabalhem bem dentro do ambiente GNU/Linux e atenda `s expectativas a dos usurios GNU/Linux no que corresponde a como os programas devem a trabalhar.

2.1

Interao Com o Ambiente de Execuo ca ca

Quando voc estudou inicialmente C ou C++, aprendeu que a funo especial e ca main o ponto de entrada principal para um programa. Quando o sistema e operacional executa seu programa, o referido sistema operacional fornece automaticamente certas facilidades que ajudam ao programa comunicar-se com o prprio sistema operacional e com o usurio. Voc provavelmente o a e aprendeu sobre os dois primeiros parmetros para a funo principal main, a ca comumente chamados argc e argv, os quais recebem entradas para o seu programa. Voc aprendeu sobre stdout e stdin (ou sobre os uxos cout e e cin na linguagem C++) que fornecem entrada e sa no console. Esses da recursos so fornecidos atravs das linguagens C e C++, e eles interagem a e com o sistema GNU/Linux de certas maneiras. GNU/Linux fornece outras formas de interagir com o sistema operacional alm das especicadas nesse e pargrafo. a 23

2.1.1

A Lista de Argumentos

Voc executa um programa a partir de um prompt de shell atravs da e e digitao do nome do programa. Opcionalmente, voc pode fornecer inca e formaes adicionais para o programa atravs da digitao de uma ou mais co e ca palavras aps o nome do programa, separadas por espaos. Essas palao c vras adiconais so chamadas argumentos de linha de comando. (Voc pode a e tambm incluir um argumento que contm espaos, empacotando os argue e c mentos entre apstrofos.) De forma mais geral, o tpico atual referente a o o e como a lista de argumentos do programa passada pelo fato de essa lista e no precisar ser originria de linha de comando de shell. No Cap a a tulo 3, Processos voc ir ver outro caminho para chamar um programa, no qual e a um programa pode especicar a lista de argumentos de outro programa diretamente. Quando um programa chamado a partir do shell, a lista de e argumentos contm a linha de comando completa, incluindo o nome do proe grama e quaisquer argumentos de linha de comando que possa ter sido fornecido. Suponhamos, por exemplo, que voc chame o comando ls em seu shell e para mostrar o contedo do diretrio ra e os correspondentes tamanhos dos u o z arquivos com essa linha de comando: % ls -s / A lista de argumentos que o programa ls acima consta de trs argumentos. e O primeiro deles o nome do programa propriamente dito, como especicado e na linha de comando, ls a saber. O segundo e o terceiro elementos da lista de argumentos so os dois argumentos de linha de comando, o -s e a /. a A funo main de seu programa pode acessar a lista de argumentos por ca meio dos parmetros da funo main argc e argv (se voc por acaso no a ca e a utiliza esses dois argumentos, voc pode simplesmente omit e -los). O primeiro parmetro, argc, um inteiro que representa o nmero de argumentos na lista a e u de argumentos. O segundo parmentro, argv, um vetor de apontadores de a e caracteres. O tamanho do vetor argc, e os elementos do vetor apontam para e os elementos da lista de argumentos, com cada elemento da lista terminado com o caractere nulo /0.1 A utilizao de argumentos de linha de comando to fcil quanto exaca e a a minar os contedos de argc e argv. Se voc no estiver interessado no nome u e a do programa propriamente dito, lembre-se de ignorar o primeiro elemento. Logo abaixo temos a Listagem 2.1 que demonstra como usar argc e argv.

Nota do tradutor: ver [K & R (1989)] p. 113.

24

Listagem 2.1: (Arquivo arglist.c) Usando argc e argv.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <s t d i o . h> i n t main ( i n t a r g c , char a r g v [ ] ) { p r i n t f ( O nome d e s s e programa e % s . \ n , a r g v [ 0 ] ) ; p r i n t f ( E s s e programa f o i chamado com %d a r g u m e n t o s . \ n , a r g c 1 ) ; / Ondes q u a i s q u e r a r g u m e n t o s d e l i n h a i f ( argc > 1) { / Sim , imprimao s . / int i ; p r i n t f ( Os a r g u m e n t o s s a o : \ n ) ; f o r ( i = 1 ; i < a r g c ; ++i ) p r i n t f ( %s \n , a r g v [ i ] ) ; } return 0 ; } d e comando s a o especificados ? /

2.1.2

Convenes GNU/Linux de Linha de Comando co

Quase todos os programas GNU/Linux obedecem algumas convenes sobre co como argumentos de linha de comando so interpretados. O argumentos que a so passados a programas so de duas categorias: opes (ou sinalizadores) a a co e outros argumentos. As opes modicam como o programa se comporta, co enquanto outros argumentos fornecem entradas (por exemplo, os nomes de arquivos de entrada). Opes chegam de duas formas: co Opes curtas consistindo de um unico hifen e um unico caractere co (comumente em caixa baixa ou caixa alta). Opes curtas so co a rpidas de digitar. a Opes longas consistindo de dois h co fens, seguidos por um nome composto em caixa baixa e caixa alta e h fens. Opes longas so co a fceis de lembrar e fceis de ler (em scripts shell, por exemplo). a a Habitualmente, um programa fornece ambas as formas curta e longa para a maioria das opes que so suportadas pelo referido programa, a forma co a curta por uma questo de brevidades e a forma longa por uma questo de a a clareza. Por exemplo, a maioria dos programas entendem as opes -h e co --help, e as tratam de forma idntica. Normalmente, quando um programa e chamado em um shell sem nenhum argumento, quaisquer opes desejae co das seguem o nome do programa imediatamente. Algumas opes esperam co que um argumento as siga imediatamente. Muitos programas, por exemplo, interpretam a opo output qualquercoisa como especicando que ca a sa de um programa deva ser colocada em um arquivo chamado qualda quercoisa. Aps as opes, podem existir adiante delas outros argumentos o co de linha de comando, tipicamente arquivos de entrada ou dados de entrada. 25

Por exemplo, o comando ls -s / mostra o contedo do diretrio ra A u o z. Opo -s modica o comportamento padro do ls instruindo o ls a mostrar ca a o tamanho (em kilobytes) de cada entrada.O argumento / diz ao ls qual diretrio listar. A opo size sinnima da opo -s, de forma que o o ca e o ca mesmo comando pode poderia ter sido digitado como ls size /. A codicao GNU padro lista os nomes de algumas opes de linha ca a co de comando comumente usadas. Se voc planeja fornecer quaisquer opes e co similares a alguma dessas, uma boa idia usar os nomes especicados na e e codicao padro. Seu programa ir se comportar mais como outros proca a a gramas e ir ser mais fcil para os usurios aprenderem. Voc pode visualizar a a a e o guia de Condicao GNU Padro para opes de linha de comando digica a co tando o seguinte em um prompt de comandos de um shell na maioria dos sistemas GNU/Linux2 : % info "(standards)User Interfaces"

2.1.3

Usando getopt long

A passagem de opes de linha de comando uma tarefa tediosa. Felizmente, co e a biblioteca C GNU padro fornece um funo que voc usa em programas a ca e em C e em programas em C++ para fazer esse trabalho de alguma forma um pouco mais fcil (embora ainda assim um pouco incmoda). Essa funo, a o ca a getopt long, recebe ambas as formas curta e longa de passagem de parmetros. Se voc for usar essa funo, inclua o arquivo de cabealho <getopt.h>. e ca c Suponha, por exemplo, que voc est escrevendo um programa que para e a e aceitar as trs opes mostradas na tabela 2.1. e co Tabela 2.1: Opes do Programa Exemplo co Forma Curta Forma Longa Propsito o -h help Mostra sumrio de uso e sai a -o nomearquivo output nomearquivo Especica o nome do arquivo de sa da -v verbose Mostra mensagens detalhadas

Adicionalmente, o programa deve aceitar zero ou mais argumentos de linha de comando, que so os nomes de arquivos de entrada. a
Nota do tradutor: o guia de Condicao GNU Padro tambm pode ser acesca a e sado via http://www.gnu.org/prep/standards/html node/User-Interfaces.html# User-Interfaces.
2

26

Para usar a funo getopt long, voc deve fornecer duas estruturas de ca e dados. A primeira uma sequncia de caracteres contendo as opes vlidas e e co a em sua forma curta, cada letra unica. Uma opo que necessite de um ca argumento seguida de dois pontos. Para o seu programa, a sequncia de e e caracteres ho:v indica que as opes vlidas so -h, -o, e -v, com a segunda co a a dessas trs opes devendo ser seguida por um argumento. e co Para especicar as opes longas dispon co veis, voc constri um vetor de e o elementos de estruturas de opes. Cada elemento corespondendo a uma co opo longa e tendo quatro campos. Em circunstncias normais, o primeiro ca a campo o nome da opo longa (na forma de uma seqncia de caracteres, e ca ue sem os dois h fens); o segundo campo 1 se a opo precisa de argumento, e ca ou 0 em caso contrrio; o terceiro campo NULL; e o quarto um caractere a e e constante especicando a forma curta que sinnimo da referida opo de e o ca forma longa. O ultimo elemento do vetor deve ter todos os campos zerados como adiante. Voc pode construir o vetor como segue: e

const struct option long_options[] = { { "help", 0, NULL, h }, { "output", 1, NULL, o }, { "verbose", 0, NULL, v }, { NULL,0, NULL, 0} };

Voc chama a funo getopt long, passando a ela os argumentos argc e e ca argv que so passados ` funo main, a sequncia de caracteres descrevendo a a ca e as opes curtas, e o vetor de elementos de estruturas de opes descrevendo co co as opes longas. co 27

Cada vez que voc chamar getopt long, a funo getopt long informa e ca uma unica opo, retornando a letra da forma curta para aquela ca opo ou -1 se nenhuma opo for encontrada. ca ca Tipicamente, voc ir chamar getopt long dentro de um lao, para e a c processar todas as opes que o usurio tiver especicado, e voc co a e ir manusear as opes espec a co cas usando o comando switch. Se a funo getopt long encontra uma opo invlida (uma opo ca ca a ca que voc no especicou como uma opo curta vlida ou como uma e a ca a opo longa vlida), a funo getopt long imprime uma mensagem ca a ca de erro e retorna o caractere ? (um ponto de interrogao). A ca grande maioria dos programas ir encerrar a execuo em resposta a ca a isso, possivelmente aps mostrar informaes de utilizao. o co ca Quando se estiver manuseando uma opo que precisa de um arca gumento, a varvel global optarg aponta para o texto daquele ara gumento. co a Aps getopt long terminar de manusear todas as opes, a varivel o global optind conter o a ndice (dentro de argv ) do primeiro argumento no classicado como vlido. a a

A Listagem 2.2 mostra um exemplo de como voc pode usar getopt long e para processar seus argumentos. 28

Listagem 2.2: (getopt long.c) Usando a funo getopt long ca


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <g e t o p t . h> #include <s t d i o . h> #include < s t d l i b . h> / O nome d e s s e p r o g r a m a . const char program name ; /

/ M o s t r e i n f o r m a c a o d e como u s a r e s s e p r o g r a m a p a r a STREAM ( t i p i c a m e n t e s t d o u t ou s t d e r r ) , e s a i a do p r o g r a m a com EXIT CODE . Nao retorne . / void p r i n t u s a g e { f p r i n t f ( stream f p r i n t f ( stream h o v exit ( exit code } ( FILE stream , int exit code ) [ arquivoentrada ... ] \ n , program name ) ;

, Uso : %s o p c o e s , h e l p o u t p u t f i l e n a m e v e r b o s e );

Mostra e s s a i n f o r m a c a o de u s o . \ n E s c r e v e a s a i d a p a r a a r q u i v o . \ n Mostra mensagens d e t a l h a d a s . \ n ) ;

/ P o n t o d e e n t r a d a do p r o g r a m a p r i n c i p a l . ARGC c o n t e m o numero d e e l e m e n t o s da l i s t a de 23 a r g u m e n t o s ; ARGV i s an a r r a y o f p o i n t e r s t o them . / 24 25 i n t main ( i n t a r g c , char a r g v [ ] ) 26 { 27 int next option ; 28 29 / Uma s t r i n g l i s t a n d o l e t r a s v a l i d a s d e o p c o e s c u r t a s . / 30 const char const s h o r t o p t i o n s = ho : v ; 31 / Um a r r a y d e s c r e v e n d o o p c o e s l o n g a s v a l i d a s . / 32 const s t r u c t o p t i o n l o n g o p t i o n s [ ] = { 33 { help , 0 , NULL, h } , 34 { output , 1 , NULL, o } , 35 { verbose , 0 , NULL, v } , 36 { NULL, 0 , NULL, 0 } / R e q u e r i d o no f i m do a r r a y . / 37 }; 38 39 / O nome do a r q u i v o q u e r e c e b e a s a i d a do programa , ou NULL p a r a 40 s a i d a padrao . / 41 const char o u t p u t f i l e n a m e = NULL ; 42 / Se m o s t r a m e n s a g e n s d e t a l h a d a s . / 43 int verbose = 0 ; 44 45 / R e l e m b r e a o nome do programa , p a r a i n c o r p o r a r n a s m e n s a g e n s . 46 O nome e a r m a z e n a d o em a r g v [ 0 ] . / 47 program name = a r g v [ 0 ] ; 48 49 do { 50 n e x t o p t i o n = g e t o p t l o n g ( a r g c , argv , s h o r t o p t i o n s , 51 l o n g o p t i o n s , NULL) ; 52 switch ( n e x t o p t i o n ) 53 { 54 case h : / h ou h e l p / 55 / O u s u a r i o r e q u i s i t o u i n f o r m a c o e s d e u s o . M o s t r ea s na s a i d a 56 p a d r a o , e s a i a com c o d i g o d e s a i d a z e r o ( e n c e r r a d o n o r m a l m e n t e ) . / 57 p r i n t u s a g e ( stdout , 0) ; 58 59 case o : / o ou o u t p u t / 60 / E s s a o p c a o r e c e b e um a r g u m e n t o , o nome do a r q u i v o d e s a i d a . / 61 output filename = optarg ; 62 break ; 63 64 case v : / v ou v e r b o s e / 65 verbose = 1; 66 break ; 67 68 case ? : / O u s u a r i o e s p e c i f i c o u uma o p c a o i n v a l i d a . / 69 / M o s t r e i n f o r m a c o e s d e u s o p a r a s t a n d a r d e r r o r , e s a i a com c o d i g o d e 70 s a i d a um ( i n d i c a n d o e n c e r r a m e n t o a n o r m a l ) . / 71 p r i n t u s a g e ( stderr , 1) ; 72 73 case 1: / Terminado com a s o p c o e s . / 74 break ; 75 76 default : / Alguma c o i s a a m a i s : i n e x p e r a d o . / 77 abort () ; 78 } 79 } 80 while ( n e x t o p t i o n != 1) ;

29

Listagem 2.3: (getopt long.c) Continuao ca


81 82 83 84 85 86 87 88 89 90 91 92 93 } / Terminado com o p c o e s . OPTIND a p o n t a p a r a o p r i m e i r o a r g u m e n t o nao o p c a o . Por p r o p o s i t o s d e d e m o n s t r a c a o , m o s t r e o s e a o p c a o v e r b o s e f o i especificada . / i f ( verbose ) { int i ; f o r ( i = o p t i n d ; i < a r g c ; ++i ) p r i n t f ( Argumento : %s \n , a r g v [ i ] ) ; } / O p r o g r a m a return 0 ; principal e desenvolvido aqui . /

O uso de getopt long pode ser visto como muito trabalho, mas escrevendo cdigo para passar as opes de linha de comando propriamente ditas pode o co ser mais trabalhoso ainda. A funo getopt long muito sosticada e permite ca e grande exibilidade na especicao de qual tipo de opo aceitar. Todavia, ca ca uma boa idia adiar a adoo de recursos mais avanados e segurar-se um e e ca c pouco na estrutura bsica de opo descrita acima. a ca

2.1.4

E/S Padro a

A biblioteca C GNU padro fornece uxos de entrada e sa padro (stdin a da a e stdout, respectivamente). Tanto a entrada como a sa padro so usadas da a a por scanf, printf, e outras funes da biblioteca C GNU padro. Na tradio co a ca UNIX, o uso da entrada e da sa padro comum e habitual para programas da a e GNU/Linux. Isso permite encadeamento de multiplos programas usando pipes de shell e redirecionamentos de entrada e sa da. (Veja a pgina de a manual para o seu shell preferido para aprender a sintaxe nesses casos de pipes e redirecionamentos.) A biblioteca C GNU padro tambm fornece stderr, o uxo padro de a e a erro. Programas podem mostrar mensagens de erro para a sa padro da a de erro em lugar de enviar para a sa padro. Esse tipo de comportada a mento permite aos usurios separarem a sa normal e mensagens de erro, a da por exemplo, atravs do redirecionamento da sa padro para um arquivo e da a enquanto permite a impresso da sa de erro para o console. A funo a da ca fprintf pode ser usada para imprimir para a sa padro de erro stderr, por da a exemplo: fprintf (stderr, (Error: ...")); Esses trs uxos3 so tambm access e a e veis com os comandos bsicos UNIX a de E/S (read, write, e assim por diante) por meio dos trs descritores de e
3

Nota do tradutor:stdin, stdout e stderr.

30

arquivo usados em shell. Os descritores so 0 para stdin, 1 para stdout, e 2 a para stderr. Quando um programa for chamado, pode ser algumas vezes util redireci onar ambas, a sa padro e a sa de erro, para um arquivo ou pipe. A da a da sintaxe para fazer isso varia nos diversos shells; para shells do estilo Bourne (incluindo o bash, o shell padro na maioria das distribuies GNU/Linux), a co dois exemplos so mostrados logo abaixo: a % programa > arquivo_saida.txt 2>&1 % programa 2>&1 | filtro A sintaxe 2>&1 indica que o descritor 2 de arquivo (stderr ) deve ser entregue no descritor de arquivo 1 (stdout). Note que 2>&1 deve vir aps o um redirecionamento de arquivo (a primeira linha exemplo logo acima) mas deve vir antes de um redirecionamento por meio de pipe (a segunda linha exemplo logo acima). Note que stdout armazenada em uma rea temporria. Dados escritos e a a para stdout no so enviados para o console (ou para outro dispositivo caso a a haja redirecionamento) imediatamente. Dados escritos para stdout so ena viados para o console em trs situaes: quando a rea de armazenamento e co a temporrio esteja preenchida completamente, quando o programa terminar a normalmente ou quando stdout for fechada. Voc pode explicitamente dese carregar a rea de armazenamento temporria atravs da seguinte chamada: a a e fflush (stdout); Por outro lado, stderr no armazenada em um local temporrio; dados a e a 4 escritos para stderr vo diretamente para o console. a Isso pode produzir alguns resultados surpreendentes. Por exemplo, esse lao no mosta um ponto a cada segundo; em vez disso, os pontos so armac a a zenados em uma rea temporria, e um grupo de pontos mostrado todos a a e de uma unica vez quando o limite de armazenamento da rea temporria a a e alcanado. c while ( 1 ) { printf ( . ); sleep (1); }
Em C++, a mesma distino se mantm para cout e para cerr, respectivamente. Note ca e que a marca endl descarrega um uxo adicionalmente ` impresso um caractere de nova a a linha; se voc no quiser descarregar um uxo (por razes de performace, por exemplo), e a o use em substituio a endl uma constante de nova linha, \n. ca
4

31

No lao adiante, todavia, o ponto aparece uma vez a cada segundo: c while ( 1 ) { f p r i n t f ( stderr , . ) ; sleep (1); }

2.1.5

Cdigos de Sa de Programa o da

Quando um programa termina, ele indica sua situao de sa com um ca da cdigo de sa o da. O cdigo de sa um inteiro pequeno; por conveno, um o da e ca cdigo de sa zero denota execuo feita com sucesso, enquanto um cdigo o da ca o de sa diferente de zero indica que um erro ocorreu. Alguns programas da usam diferentes valores de cdigos diferentes de zero para distinguir erros o espec cos. Com a maioria dos shells, poss obter o cdigo de sa do e vel o da programa executado mais recentemente usando a varivel especial $? (ponto a de interrogao). Aqui est um exemplo no qual o comando ls chamado ca a e duas vezes e seu cdigo de sa mostrado a cada chamada. No primeiro o da e caso, ls executa corretamente e retorna o cdigo de sa zero. No segundo o da caso, ls encontrou um erro (porque o nome de arquivo especicado na linha de comando no existe) e dessa forma retorna um cdigo de sa diferente a o da de zero: % ls / bincoda etc libmisc nfs proc sbinusr boot dev home lost+found mnt opt root tmp var % echo $? 0 % ls bogusfile ls: bogusfile: No such file or directory % echo $? 1 Um programa em C ou em C++ especica seu cdigo de sa atravs o da e do retorno do cdigo de sa devolvido pela funo main. Existem ouo da ca tros mtodos de fornecer cdigos de sa e o da, e cdigos de sa especial so o da a atribu dos a programas que terminam de forma diferente da esperada (por meio de um sinal). Isso ser discutido adicionalmente no Cap a tulo 3.

2.1.6

O Ambiente

GNU/Linux fornece a cada programa sendo executado um ambiente. O ambiente uma coleo de pares varivel/valor. Ambos nome de variveis e ca a a 32

de ambiente e seus valores respectivos so sequncias de caracteres. Por a e conveno, nomes de variveis de ambiente so grafados com todas as letras ca a a em maiscula. u Voc provavelmente j est familiarizado com muitas variveis de ambie a a a ente mais comuns. Por exemplo:

USER contm seu nome de usurio. e a HOME contm o caminho para seu diretrio de usurio. e o a PATH contm uma lista de itens separada por ponto e v e rgula dos diretrios os quais GNU/Linux busca pelo comando que voc o e chamar. DISPLAY contm o nome e o nmero do display do servidor sobre e u o qual janelas de programas grcos do X iro aparecer. a a

Seu shell, como qualquer outro programa, tem um ambiente. Shells fornecem mtodos para examinar e modicar o ambiente diretamente. Para e mostrar o ambiente atual em seu shell, chame o programa printenv. Vrios a shells possuem diferentes sintaxes internas para a utilizao de variveis de ca a ambiente; o que mostrado adiante a sintaxe no estilo dos shells do tipo e e Bourne. 33

O shell automaticamente cria uma varivel shell para cada varivel a a de ambiente que encontrar, de forma que voc acessar valores de e variveis de ambiente usando a sintaxe $nomedevariavel. Por exema plo: % echo $USER samuel % echo $HOME /home/samuel Voc pode usar o comando export para exportar uma varivel shell e a dentro do ambiente. Por exemplo, para modicar a varivel de a ambiente EDITOR, voc pode usar o seguinte: e % EDITOR=emacs % export EDITOR Ou, de forma curta e rpida: a % export EDITOR=emacs

Em um programa, voc acessa uma varivel de ambiente com a funo e a ca getenv na <stdlib.h>. A funo getenv pega um nome de varivel e retorna ca a o valor correspondente como uma sequncia de caracteres, ou NULL se a e referida varivel no tiver sido denida no ambiente. Para modicar ou lima a par variveis de ambiente, use as funes setenv e unsetenv, respectivamente. a co Listar todas as variveis de um ambiente um pouco complicado. Para fazer a e isso, voc deve acessar uma varivel global especial chamada environ, que e a denida na biblioteca C GNU padro. Essa varivel, do tipo char**, e a a e um vetor de apontadores terminado com o caractere NULL que apontam para sequncias de caracteres. Cada sequncia de caracteres contendo uma e e varivel de ambiente, na forma VARIAVEL=valor. O programa na Listagem a 2.4, por exemplo, simplesmente mostra na tela todas as variveis de ambiente a atravs de um lao ao longo do vetor de apontadores environ. e c 34

Listagem 2.4: (print-env.c) Mostrando o Ambiente de Execuo ca


1 2 3 4 5 6 7 8 9 10 11 12 #include <s t d i o . h> / A v a r i a v e l ENVIRON c o n t e m o a m b i e n t e . extern char e n v i r o n ; i n t main ( ) { char v a r ; f o r ( v a r = e n v i r o n ; v a r != NULL ; ++v a r ) p r i n t f ( %s \n , v a r ) ; return 0 ; } /

No modique o ambiente propriamente dito; use as funes setenv e a co unsetenv para fazer as modicaes que voc precisar. Comumente, quando co e um novo programa iniciado, ele herda uma cpia do ambiente do programa e o que o chamou (o programa de shell, se o referido programa tiver sido chamado de forma interativa). Dessa forma, por exemplo, programas que voc executa e a partir de um programa de shell pode examinar os valores das variveis de a ambiente que voc escolheu no shell que o chamou. e Variveis de ambiente so comumente usadas para indicar informaes a a co de congurao a programas. Suponha, por exemplo, que voc est escreca e a vendo um programa que se conecta a um servidor Internet para obter alguma informao. Voc pode ter escrito o programa de forma que o nome do serca e vidor seja especicado na linha de comando. Todavia, suponha que o nome do servidor no alguma coisa que os usurios iro modicar muitas vezes. a e a a Voc pode usar uma varivel especial de ambiente digamos SERVER NAME e a a para especicar o nome do servidor; se SERVER NAME no existir, um valor padro usado. Parte do seu programa pode parecer como mostrado na a e Listagem 2.5. Listagem 2.5: (client.c) Parte de um Programa Cliente de Rede
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <s t d i o . h> #include < s t d l i b . h> i n t main ( ) { char s e r v e r n a m e = g e t e n v ( SERVER NAME ) ; i f ( s e r v e r n a m e == NULL) / A v a r i a v e l d e a m b i e n t e SERVER NAME nao padrao . / s e r v e r n a m e = s e r v e r . my company . com ;

foi

ajustada .

Use o

p r i n t f ( a c e s s a n d o o s e r v i d o r %s \n , s e r v e r n a m e ) ; / A c e s s e o s e r v i d r o a q u i . . . / return 0 ; }

Suponhamos que o programa acima seja chamado de client. Assumindo que voc no tenha criado ou que no tenha sido criada anteriormente a e a a varivel SERVER NAME, o valor padro para o nome do servidor usado: a a e 35

% client accessing server server.my-company.com Mas fcil especicar um servidor diferente: e a % export SERVER_NAME=backup-server.emalgumlugar.net % client accessing server backup-server.emalgumlugar.net

2.1.7

Usando Arquivos Temporrios a

Algumas vezes um programa necessita criar um arquivo temporrio, para a armazenar grandes dados por alguns instantes ou para entreg-los a outro a programa. Em sistemas GNU/Linux, arquivos temporrios so armazenados a a no diretrio /tmp. Quando zer uso de arquivos temporrios, voc deve estar o a e informado das seguintes armadilhas: Mais de uma instncia de seu programa pode estar sendo executada a simultneamente (pelo mesmo usurio ou por diferentes usurios). a a a As instncias devem usar diferentes nomes de arquivos temporrios a a de forma que eles no colidam. a As permisses dos arquivos temporrios devem ser ajustadas de tal o a forma que somente usurios autorizados possam alterar a execuo a ca do programa atravs de modicao ou substituio do arquivo e ca ca temporrio. a Nomes de arquivos temporrios devem ser gerados de forma ima previs externamente; de outra forma, um atacante pode usar a vel espera entre a vericao de que um nome de arquivo fornecido j ca a est sendo usado e abrir um novo arquivo temporrio. a a GNU/Linux fornece funes, mkstemp e tmple, que cuidam desses reco cursos para voc de forma adequada (e adicionalmente muitas funes que e co no cuidam)5 . Qual voc ir usar depende de seu planejamento de manusear a e a o arquivo temporrio para outro programa, e de se voc deseja usar E/S a e UNIX (open, write, e assim por diante) ou as funes de controle de uxos co da biblioteca C GNU padro(fopen, fprintf, e assim por diante). a
5

Nota do tradutor: no slackware tem a mktemp.

36

Usando mkstemp A funo mkstemp criar um nome de arquivo temca a porrio de forma unica a partir de um modelo de nome de arquivo, cria o a arquivo propriamente dito com permisses de forma que somente o usurio o a atual possa acess-lo, e abre o arquivo para leitura e escrita. O modelo de a nome de arquivo uma sequncia de caracteres terminando com XXXXXX e e (seis letras X maisculas); mkstemp substitui as letras X por outros caracu teres de forma que o nome de arquivo seja unico. O valor de retorno e um descritor de arquivo; use a fam de funes aparentadas com a funo lia co ca write para escrever no arquivo temporrio. Arquivos temporrios criados a a com mkstemp no so apagados automaticamente. Compete a voc remoa a e ver o arquivo temporrio quando o referido arquivo temporrio no mais a a a for necessrio. (Programadores devem ser muito cuidadosos com a limpeza a de arquivos temporrios; de outra forma, o sistema de arquivos /tmp ir a a encher eventualmente, fazendo com que o sistema que inoperante.) Se o arquivo temporrio for de uso interno somente e no for manuseado por outro a a programa, uma boa idia chamar unlink sobre o arquivo temporrio imee e a diatamente. A funo unlink remove a entrada do diretrio correspondente ca o a um arquivo, mas pelo fato de arquivos em um sistema de arquivos serem contados-referenciados, o arquivos em si mesmos no so removidos at que a a e no hajam descritores de arquivo abertos para aquele arquivo. Dessa forma, a seu programa pode continuar usando o arquivo temporrio, e o arquivo evoa lui automaticamente at que voc feche o descritor do arquivo. Pelo fato de e e GNU/Linux fechar os descritores de arquivo quando um programa termina, o arquivo temporrio ir ser removido mesmo se seu programa terminar de a a forma abrupta.

O par de funes na Listagem 2.6 demonstra mkstemp. Usadas juntas, co essas duas funes tornam fcil escrever o contedo de uma rea temporria co a u a a de armazenamento na memria para um arquivo temporrio (de forma que o a a memoria possa ser liberada ou reutilizada) e de forma que esse contedo u armazenado possa ser trazido de volta ` memria mais tarde. a o 37

Listagem 2.6: (temp le.c) Usando mkstemp


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include < s t d l i b . h> #include <u n i s t d . h> / Um m a n i p u l a d o r p a r a um a r q u i v o t e m p o r a r i o c r i a d o com w r i t e t e m p f i l e . i m p l e m e n t a c a o , o a r q u i v o t e m p o r a r i o e a p e n a s um d e s c r i t o r d e a r q u i v o . typedef i n t t e m p f i l e h a n d l e ; / E s c r e v a LENGTH b y t e s d e BUFFER p a r a um a r q u i v o arquivo temporario e imediatamente unlinked . arquivo temporario . / Nessa /

temporario . o R e t o r n a um m a n i p u l a d o r p a r a o

t e m p f i l e h a n d l e w r i t e t e m p f i l e ( char b u f f e r , s i z e t l e n g t h ) { / C r i a o f i l e n a m e e o f i l e . O XXXXXX i r a s e r s u b s t i t u i d o com c a r a c t e r e s que fazem o f i l e n a m e unico . / char t e m p f i l e n a m e [ ] = /tmp/ t e m p f i l e .XXXXXX ; i n t f d = mkstemp ( t e m p f i l e n a m e ) ; / U n l i n k o a r q u i v o i m e d i a t a m e n t e , d e f o r m a q u e o a r q u i v o i r a s e r r e m o v i d o q u a n d o o d e s c r i t o r de a r q u i v o f o r f e c h a d o . / unlink ( temp filename ) ; / E s c r e v e o numero d e b y t e s p a r a o a r q u i v o p r i m e i r a m e n t e . / w r i t e ( f d , &l e n g t h , s i z e o f ( l e n g t h ) ) ; / Agora e s c r e v e o s d a d o s p r o p r i a m e n t e d i t o s . / w r i t e ( fd , b u f f e r , l e n g t h ) ; / Use o d e s c r i t o r d e a r q u i v o como o m a n i p u l a d o r p a r a o a r q u i v o t e m p o r a r i o . / return f d ; }

/ L e i a o c o n t e u d o d e um a r q u i v o t e m p o r a r i o TEMP FILE c r i a d o com write temp file . O v a o r d e r e t o r n o e um m e i s r e c e n t e m e n t e a l o c a d o e s p a c o temporario 31 com a q u e l e c o n t e u d o , o q u a l o chamador d e v e d e s a l o c a r com f r e e . 32 LENGTH e a j u s t a d o p a r a o tamanho do c o n t e u d o , em b y t e s . O 33 aruivo temporario e removido . / 34 35 char r e a d t e m p f i l e ( t e m p f i l e h a n d l e t e m p f i l e , s i z e t l e n g t h ) 36 { 37 char b u f f e r ; 38 / O m a n i p u l a d o r TEMP FILE e um d e s c r i t o r d e a r q u i v o p a r a o a r q u i v o t e m p o r a r i o . / 39 int fd = t e m p f i l e ; 40 / V o l t e p a r a o i n i c i o do a r q u i v o . / 41 l s e e k ( f d , 0 , SEEK SET ) ; 42 / L e i a o t a m a n h o s d o s d a d o s no a r q u i v o t e m p o r a r i o . / 43 read ( fd , leng th , s i z e o f ( l e n g t h ) ) ; 44 / A l o q u e um e s p a c o t e m p o r a r i o e l e i a o s d a d o s . / 45 b u f f e r = ( char ) m a l l o c ( l e n g t h ) ; 46 read ( fd , b u f f e r , l e n g t h ) ; 47 / F e c h e o d e s c r i t o r d e a r q u i o , o q u a l i r a f a z e r com q u e o a r q u i v o t e m p o r a r i o 48 v a embora . / 49 c l o s e ( fd ) ; 50 return b u f f e r ; 51 }

Usando tmple Se voc est usando as funes de E/S da biblioteca e a co C GNU padro e no precisa passar o arquivo temporrio para outro proa a a grama, voc pode usar a funo tmple. Essa funo cria e abre um arquivo e ca ca temporrio, e retorna um apontador de arquivo para esse mesmo arquivo a temporrio. O arquivo temporrio j unlinked, como no exemplo anterior, a a ae de forma que ser apagado automaticamente quando quando o apontador de a arquivo for fechado (com fclose) ou quando o programa terminar. GNU/Linux fornece muitas outras funes para a gerao de arquivos co ca temporarios e nomes de arquivos temporrios, incluindo mktemp, tmpnam, a a e tempnam. No use essas funes, apesar disso, pelo fato de elas possu a co rem problemas de conabilidade e segurana j mencionados anteriormente. c a 38

2.2

Fazendo Cdigo Defensivamente o

Escrevendo programas que executam atualmente sob uso normal trabae lhoso; escrever programas que comportam-se de forma elegante em situaes co de falha mais trabalhoso ainda. Essa seo demonstra algumas tcnicas de e ca e codicao para encontrar erros facilmente e para detectar e recuperar-se de ca problemas durante a execuo de um programa. ca As amostras de cdigo apresentadas mais adiante nesse livro omitem erros o extensivos de vericao e recuperao de cdigo pelo fato de isso eventualca ca o mente vir a obscurecer a funcionalidade bsica que se deseja apresentar aqu a . Todavia, o exemplo nal no cap tulo 11, Um Modelo de Aplicao GNU/ca Linux retorna ` demonstrao de como usar essas tcnicas para escrever a ca e programas robustos.

2.2.1

Usando assert

Um bom objetivo para se ter em mente quando criamos um cdigo fonte o de uma aplicao que erros comuns ou mesmo erros inesperados podem ca e fazer com que o programa falhe de forma dramtica, to facilmente quanto a a poss vel. O uso de assert ir ajudar voc a encontrar erros facilmente no a e desenvolvimento e na fase de teste. Falhas que no se mostram de forma a evidente passam surpreendentemente e muitas vezes desapercebidas e no se a mostram at que a aplicao esteja nas mos do usurio nal. e ca a a Um dos mais simples mtodos de vericar condies inesperadas a macro e co e assert da biblioteca C GNU padro. O argumento para essa macro uma a e expresso Booleana. O programa terminado se a expresso Booleana avaliar a e a para false, aps mostrar uma mensagem de erro contendo o cdigo fonte e o o o nmero da linha e o texto da expresso. A macro assert muito util para u a e uma larga variedade de vericaes de consistncias internas em um dado co e programa. Por exemplo, use assert para testar a validade de argumentos de funes, para testar condies prvias e condies pstumas de chamadas a co co e co o funes (e chamadas a mtodos, em C++), e para testar valores de retorno. co e Cada utilizao de assert serve no somente como uma vericao em ca a ca tempo de execuo de uma condio, mas tambm como documentao sobre ca ca e ca a operao do programa dentro do cdigo fonte. Se seu programa contiver ca o um assert (condio) que diz a algum para ler seu cdigo fonte pelo fato de a ca e o condio obrigatriamente ter de ser verdadeira naquele ponto do programa, ca o e se a condio no verdadeira, temos a um erro no programa. Para ca a e cdigo de desempenho cr o tico, vericaes tais como a utilizao de assert co ca podem impor uma perda muito grande de desempenho. Nesses casos,voc e pode compilar seu cdigo com a macro NDEBUG denida, atravs do uso o e 39

do sinalizador -DNDEBUG na sua linha de comando de compilao. Com ca NDEBUG denida, aparies da macro assert iro ser preprocessadamente co a descartadas. O preprocessamento dessa forma uma boa idia no sentido e e de permitir fazer o uso de assert somente quando necessrio por razes de a o performace, embora que, somente com arquivos fonte de desempenho cr tico. Pelo fato de ser poss vel o descarte preprocessadamente da macro assert, garanta que qualquer expresso que voc venha a usar com assert no tenha a e a efeitos colaterais. Especicamente, voc no deve chamar funes dentro e a co de expresses assert, no deve atribuir valores a variveis e no deve usar o a a a modicadores de operao tais como ++. ca Suponhamos, por exemplo, que voc chame uma funo, fazer algumacoisa, e ca repetidamente em um lao. A funo fazer algumacoisa retorna zero em caso c ca de sucesso e no zero em caso de falha, mas voc no espera que esse compora e a tamento venha a falhar em seu programa. Voc pode ter tentado escrever: e

for (i = 0; i < 100; ++i) assert (fazer_algumacoisa () == 0); Todavia, voc pode encontrar que essa vericao em tempo de execuo e ca ca impe uma grande perda de desempenho e decide mais tarde recompilar com o NDEBUG denida. Essa recompilao com NDEBUG denida ir remover ca a a chamada a assert inteiramente, de forma que a expresso nunca ir ser a a avaliada e fazer algumacoisa nunca ir ser chamada. Voc pode, ao invs do a e e cdigo anterior escrever o seguinte: o

for (i = 0; i < 100; ++i) { int status = fazer_algumacoisa (); assert (status == 0); } Outra coisa para se ter em mente que voc no deve usar assert para e e a testar entradas invlidas de usurio. Usurios no gostam quando aplicaes a a a a co simplesmente terminam abruptamente com uma mensagem de erro criptografada, mesmo em resposta a uma entrada invlida. Voc deve sempre a e vericar entradas invlidas e produzir mensagens de erro coerentes e lgicas a o em resposta a uma tal entrada invlida. Use assert somente para vericaes a co internas em tempo de execuo. ca Alguns bons lugares para usar assert so esses: a 40

Vericao contra apontadores nulos, por exemplo, como argumenca tos vlidos a funes. A mensagem de erro gerada por assert (poina co ter != NULL), Assertion pointer != ((void *)0) failed. mais informativa que a mensgem de erro que pode resultar se seu e programa simplesmente tentar acessar um apontador nulo: Segmentation fault (core dumped) Verique condies sobre valores de parmetros passados a funes. co a co Por exemplo, se uma funo deve ser chamada somente com um ca valor positivo para o parmetro qualquercoisa, use o seguinte no a comeo do corpo da funo: c ca assert (qualquercoisa > 0); Isso ir ajudar voc a detectar uso inadequado da funo, e essa a e ca prtica tambm faz com que esteja muito claro a algum que ao ler a e e o cdigo fonte da funo ver que existe uma restrio sobre valores o ca a ca do parmetro. a Evolua; use assert de forma liberal em toda a extenso de seu cdigo. a o

2.2.2

Falhas em Chamadas de Sistema

A maioria de ns originalmente aprendeu como escrever programas que exeo cutam at o nal ao longo de um caminho bem denido. Dividimos o proe grama em tarefas e sub-tarefas, e cada funo completa uma tarefa atravs ca e de chamadas a outras funes para executar as sub-tarefas correspondentes. co Fornecendo entradas apropriadas, esperamos que uma funo produza a sa ca da correta e os efeitos corretos. As realidades das peas do computador e dos c programas de computador intromete-se nesse sonho perfeito. Computadores possuem recursos limitados; peas falham; muitos programas funcionam ao c mesmo tempo; usurios e programas cometem erros. Isso muitas vezes no a limite entre a aplicao e o sistema operacional que essas realidades exibem ca por si mesmas. Portanto, quando formos usar chamadas de sistema para acessar recursos, para realizar operaes de E/S, ou para outro propsito, co o e importante entender no somente o que ocorre quando a chamada acontece, a 41

mas tambm quando e como a chamada de sistema pode falhar. Chamadas e de sistema falham de muitas formas. Por exemplo:

O sistema pode extrapolar os recursos dispon veis de hardware (ou o programa excede os limites de recursos impostos pelo sistema para um unico programa). Por exemplo, o programa pode tentar alocar muita memria, escrever muito no disco, ou abrir muitos o arquivos ao mesmo tempo. GNU/Linux pode bloquear uma certa chamada de sistema quando um programa tenta executar uma operao para a qual no tiver ca a permisso. Por exemplo, um programa pode tentar escrever em um a arquivo marcado como somente para leitura, acessar a memria de o outro processo, ou encerrar outro programa de usurio. a Os argumentos a uma chamada de sistema podem ser invlidos, a ou devido ao usurio fornecer entradas invlidas ou devido a um a a erro no programa. Por exemplo, o programa pode passar a outro programa um endereo invlido de memria ou um descritor de c a o arquivo invlido para uma chamada de sistema. Ou, um programa a pode tentar abrir um diretrio como um arquivo, ou pode passar o o nome de um arquivo a uma chamada de sistema que espera um diretrio. o Uma chamada de sistema falha por razes externar a um programa. o Isso acontee na maioria das vezes quando uma chamada de sistema c acessa um dispositivo. O dispositivo pode estar danicado ou pode no suportar uma operao em particular, ou talvez um disco no a ca a est inserido no dispositivo de leitura e escrita em disco. a Uma chamada de sistema pode muitas vezes ser interrompida por um evento externo, tal como a entrega de um sinal. Isso no nea cessariamente indica falha externa, mas ocorrer em resposta ` chaa mada de um programa para reiniciar a chamada de sistema, se for desejvel. a

Em um programa bem escrito que faz uso extensivo de chamadas de sistema, a falha de chamada de sistema causa o aparecimento de mais cdigo o devotado a detectar e manipular erros e outras circunstncias excepcionais a que no o cdigo espec a o co dedicado ao trabalho principal do programa. 42

2.2.3

Cdigos de Erro de Chamadas de Sistema o

A maioria das chamadas de sistema retorna zero se a operao terminar corca retamente, ou um valor diferente de zero caso a operao resultar em falha. ca (Muitas outras chamadas, apesar disso, possuem diferentes convees de vaco lores de retorno; por exemplo, a chamada malloc retorna um apontador nulo para indicar falha. Sempre leia a pgina de manual cuidadosamente quando a for usar uma chamada de sistema.) Embora essa informao possar suciente ca para determinar se o programa deva continuar a execuo normalmente, a ca leitura da pgina de manual provavelmente no fornece informao suciente a a ca para um recuperao satisfatria de erros. ca o A maioria das chamadas de sistema usam uma varivel especial chamada a errno para armazenar informaes adicionais em caso de falha. 6 Quando co uma chamada vier a falhar, o sistema ajusta errno para um valor indicando o que aconteceu de errado. Pelo fato de todas as chamadas de sistema usarem a mesma varivel errno para armazenar informaes de erro, voc deve copiar a co e o valor para outra varivel imediatamente aps ocorrer a falha na chamada. a o A errno ir ter seu valor atual apagado e preenchido com outros valores da a prxima vez que voc zer uma chamada de sistema. o e Valores de erro so inteiros; os valores poss a veis so fornecidos pelas maa cros de pr-processamento, por conveno nomeadas em letras maisculas e ca u e iniciando com E, por exemplo, EACCES e EINVAL. Sempre use essas macros para referir-se a valores de errno em lugar de valores inteiros. Inclua o cabealho <errno.h> se voc for usar valores de errno. c e GNU/Linux fornece uma funo conveniente, strerror, que retorna uma ca descrio em forma de sequncia de caracteres de um cdigo de erro que se ca e o encontra armazenado em errno, adequada para usar em mensagens de erro. Inclua o arquivo de cabealho <string.h> caso voc resolva usar a funo c e ca strerror. GNU/Linux tambm fornece perror, que mostra a descrio do erro die ca retamente para o uxo stderr. Passe a perror uma sequncia de caracteres e para ser usada como prexo a ser mostrado antes da descrio de erro, que ca deve habitualmente incluir o nome da funo que falhou. Inclua o arquivo ca de cabealho <stdio.h> caso voc resolva usar a funo perror. c e ca O fragmento de cdigo adiante tenta abrir um arquivo; se a abertura o falhar, o cdigo mostra uma mensagem de erro e encerra a execuo do o ca programa. Note que a chamada open retorna um descritor de arquivo aberto se o operador open obtiver sucesso em sua tarefa, ou -1 se a operao falhar. ca
f d = open ( a r q u i v o d e e n t r a d a . t x t , O RDONLY ) ;

Atualmente, por razes de trabalhar de forma segura, errno implementada como o e uma macro, mas usada como uma varivel global. e a

43

i f ( f d == 1) { / A a b e r t u r a f a l h o u . M o s t r a uma menssagem d e e r r o e s a i . / f p r i n t f ( s t d e r r , e r r o ao a b r i r o a r q u i v o : %s \n , s t r e r r o r ( e r r n o ) ) ; exit (1); }

dependendo de seu programa e da natureza da chamada de sistema, a ao ca apropriada ao caso de falha pode ser mostrar uma mensagem de erro para cancelar uma operao, abortar o programa, tentar novamente, ou mesmo ca para ignorar o erro. A meno desse comportamento importante pelo fato ca e de ser necessrio incluir cdigo que manuseie todos os poss a o veis modos de falha de uma forma ou de outra. Um poss cdigo de erro que voc deve car de olho, especialmente com vel o e funes de E/S, EINTR. Algumas funes, tais como read, select, e sleep, co e co podem precisar de um intervalo de tempo signicativo para executar. Essas so consideradas funes de bloqueio pelo fato de a execuo do programa a co ca ser bloqueada at que a chamada seja completada. Todavia, se o programa e recebe um sinal enquanto estiver bloqueado em uma dessas chamadas, a chamada ir retornar sem completar a operao. Nesse caso, errno ajustada a ca e para EINTR. Comumente, voc ir querer chamar novamente a chamada de e a sistema que foi interrompida pelo sinal nesse caso. Adiante encontra-se um fragmento de cdigo que utiliza a chamada chown o para mudar o dono de um arquivo fornecido pela varivel path para o usurio a a especicado atravs de user id. Se a chamada vier a falhar, o programa exee cuta uma ao que depende do valor de errno. Note que quando detectamos ca o que provavelmente um erro no programa ns saimos usando abort ou e o assert, o que causa a gerao de um arquivo core. Esse arquivo pode ser util ca para depurao aps o encerramento do programa. Para outros erros irrecuca o perveis, tais como condies de tentativas de acesso a reas de memria no a co a o a alocadas pelo sistema operacional ao programa em questo, saimos usando a exit e um valor de sa no nulo em lugar de arquivo core pelo fato de que da a um arquivo core pode no vir a ser muito util. a
r v a l = chown ( path , u s e r i d , 1); i f ( r v a l != 0 ) { / Grava e r r n o p e l o f a t o d e p o d e r s e r s o b r e s c r i t o p e l a p r o x i m a chamada d e int e r r o r c o d e = errno ; / A o p e r a c a o f a l h a chown d e v e r e t o r n a r 1 em c a s o d e e r r o . / a s s e r t ( r v a l == 1); / V e r i f i c a o v a l o r d e e r r n o , e e x e c u t a a a c a o a p r o p r i a d a . / switch ( e r r o r c o d e ) { case EPERM: / P e r m i s s a o n e g a d a . / case EROFS : / PATH e s t a em um s i s t e m a d e a r q u i v o s o m e n t e l e i t u r a . / case ENAMETOOLONG: / PATH e m u i t o l o n g o . / case ENOENT: / PATH nao e x i t e . / case ENOTDIR : / Um c o m p o n e n t e d e PATH nao e h um d i r e t o r i o . / case EACCES : / Um c o m p o n e n t e d e PATH nao e s t a a c e s s i v e l . / / A l g o e s t a e r r a d o com o a r q u i v o . M o s t r e uma mensagem d e e r r o . / f p r i n t f ( s t d e r r , e r r o mudando o dono de %s : %s \n , path , s t r e r r o r ( e r r o r c o d e ) ) ; / Nao e n c e r r a o p r o g r a m a ; t a l v e z f o r n e c a o ao u s u a r i o uma c h a n c e p a r a e s c o l h e r o u t r o a r q u i v o . . . / break ; case EFAULT : / PATH contem um e n d e r e c o d e memoria s i s t e m a . /

invalido .

Isso

e h p r o v a v e l m e n t e um e r r o . /

44

abort

();

case ENOMEM: / E x e c u t o u f o r a da memoria do k e r n e l . / f p r i n t f ( s t d e r r , %s \n , s t r e r r o r ( e r r o r c o d e ) ) ; exit (1); default : / Alguma o u t r a e r r o s de c o d i g o abort ( ) ; }; }

c o i s a , i n e s p e r a d o , c o d i g o d e e r r o . Tentamos manusear t o d o s p o s s i v e i s ; s e t i v e r m o s o m i t i d o algum , i s s o e h um e r r o ! /

os

Voc pode simplesmente usar o cdigo abaixo, que comporta-se da mesma e o forma se a chamada obtiver sucesso:
r v a l = chown ( path , a s s e r t ( r v a l == 0 ) ; user id , 1);

Mas se a chamada vier a falhar, a alternativa de cdigo acima no faz o a nenhum esforo para reportar, manusear, ou para se recuperar dos erros. c Se voc usa a primeira forma, a segunda forma, ou algum meio termo entre e as duas vai depender da necessidade de seu sistema no tocante a deteco e ca recuperao de erros. ca

2.2.4

Erros e Alocao de Recursos ca

Muitas vezes, quando uma chamada de sistema falha, mais apropriado cane celar a operao atual mas no terminar o programa porque o cancelamento ca a simples pode tornar poss recuperar-se do erro. Uma forma de fazer isso vel retornar da funo em que se est no momento em que ocorreu o erro, e ca a passando um cdigo de retorno para a funo chamadora indicando o erro. o ca Caso voc decida retornar a partir do meio de uma funo, importante e ca e garantir que quaisquer recursos que tenham sido alocados com sucesso previamente na funo sejam primeiramente liberados. Esses recursos podem ca incluir memria, descritores de arquivo, apontadores para arquivo, arquivos o temporrios, objetos de sincronizao, e assim por diante. De outra forma, se a ca seu programa continuar sendo executado, os recursos alocados anteriormente a ` ocorrncia da falha iro ser perdidos. e a Considere, por exemplo, uma funo que faa a leitura de um arquivo ca c em um espao temporrio de armazenamento. A funo pode seguir esses c a ca passos: 45

1. Alocar o espao temporrio de armazenamento. c a 2. Abrir o arquivo. 3. Ler a partir do arquivo na rea temporria de armazenamento. a a 4. Fechar o arquivo. 5. Devolver o espao temporrio de armazenamento. c a Se o arquivo no existir, o Passo 2 ir falhar. Um caminho de ao a a ca pode ser retornar um apontador a partir da funo. Todavia, se o espao ca c de armazenamento temporrio j tiver sido alocado no Passo 1, existe um a a risco de perder aquela memria. Voc deve lembrar de desalocar o espao o e c temporrio de armazenamento em algum lugar com o decorrer de qualquer a uxo de controle do qual voc no venha a retornar. Se o Passo 3 vier a falhar, e a voc no somente deve desalocar o espao temporrio de armazenamento e a c a antes de retornar, mas tambm deve fechar o arquivo. e A Listagem 2.7 mostra um exemplo de como voc pode escrever essa e funo. ca Listagem 2.7: (readle.c) Liberando Recursos em Condies Inesperadas co
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 } #include #include #include #include #include < f c n t l . h> < s t d l i b . h> <s y s / s t a t . h> <s y s / t y p e s . h> <u n i s t d . h> size t length )

char r e a d f r o m f i l e ( const char f i l e n a m e , { char b u f f e r ; int fd ; s s i z e t bytes read ;

/ A l o c a o e s p a c o t e m p o r a r i o d e armazenagem . / b u f f e r = ( char ) m a l l o c ( l e n g t h ) ; i f ( b u f f e r == NULL) return NULL ; / Abre o a r q u i v o . / f d = open ( f i l e n a m e , O RDONLY) ; i f ( f d == 1) { / a b e r t u r a f a l h o u . D e s a l o q u e o e s p a c o t e m p o r a r i o d e armazenagem a n t e s d e retornar . / free ( buffer ) ; return NULL ; } / L e i a o s d a d o s . / b y t e s r e a d = read ( fd , b u f f e r , l e n g t h ) ; i f ( b y t e s r e a d != l e n g t h ) { / l e i t u r a f a l h o u . D e s a l o q u e o e s p a c o t e m p o r a r i o e f e c h e f d a n t e s de r e t o r n a r . / free ( buffer ) ; c l o s e ( fd ) ; return NULL ; } / Tudo e s t a bem . F e c h e o a r q u i v o e r e t o r n e o c o n t e u d o do e s p a c o t e m p o r a r i o d e armazenagem . / c l o s e ( fd ) ; return b u f f e r ;

Gnu/Linux limpa a memria alocada, limpa os arquivos abertos, e libera o a maioria de outros recursos quando um programa encerra, de forma que 46

no necessrio desalocar espaos temporrios de armazenamento e fechar a e a c a arquivos antes de chamar exit. Voc pode precisar liberar manualmente outros recursos compartilhados, e todavia, tais como arquivos temporrios e memria compartilhada, que poa o dem potencialmente sobreviver ao encerramento de um programa.

2.3

Escrevendo e Usando Bibliotecas

Virtualmente todos os programas so linkados usando uma ou mais bibliotea cas. Qualquer programa que usa uma funo C (tais como printf ou malloc) ca ir ser linkado incluindo a biblioteca C GNU padro de rotinas que atuam em a a tempo de execuo. Se seu programa tem uma interface grca de usurio ca a a (GUI), seu programa ser linkado incluindo bibliotecas que fazem janelas. a Se seu programa usa uma base de dados, o provedor da base de dados ir a fornecer a voc bibliotecas que voc pode usar para acessar a base de dados e e convenientemente. Em cada um desses casos, voc deve decidir se ir linkar a e a biblioteca estaticamente ou dinmicamente. Se voc escolher estaticamente, a e seu programa ir ser maior e mais pesado na hora de atualizar, mas provaa velmente fcil de desenvolver. Se voc linkar dinmicamente, seu programa a e a ir ser menor, fcil de atualizar, mas pesado para desenvolver. Essa seo a a ca explica como linkar de ambas as formas estaticamente e dinmicamente, exaa minar os reexos dessa escolha em mais detalhes, e fornecer algumas regras prticas de manuseio para decidir que tipo de linkagem melhor para voc. a e e

2.3.1

Agrupando Arquivos Objeto

Um agrupamento de arquivos objeto (ou biblioteca esttica) simplesmente a e vrios arquivos objeto armazenados como se fossem um arquivo unico. 7 a Quando voc fornece um agrupamento de arquivos objeto ao programa que e faz linkagem, ele procura no agrupamento de arquivos objeto pelo arquivo tipo objeto que ele precisa, extrai o referido arquivo, e anexa-o ao seu programa quase da mesma forma que seria se voc tivesse fornecido o referido e arquivo objeto diretamente. Voc pode criar uma biblioteca esttica usando o comando ar. Arquivos e a de biblioteca esttica tradicionalmente usam a extenso .a em lugar da exa a tenso .o usada por um arquivos objeto comuns. Aqui est como voc pode a a e combinar test1.o e test2.o em um arquivo unico libtest.a:
Um agrupamento de arquivos objeto grosseiramente o equivalente ao arquivo .LIB e do Windows.
7

47

% ar cr libtest.a test1.o test2.o Os sinalizadores cr dizem ao ar para criar a biblioteca esttica. 8 Agora a voc pode incluir essa biblioteca esttica em seu programa usando a opo e a ca -ltest com o gcc ou com o g++, como descrito na Seo 1.2.2, Linkando ca Arquivos Objeto no Cap tulo 1, Iniciando. Quando o programa de linkagem encontra uma biblioteca esttica na a linha de comando, ele procura na biblioteca esttica por todas as denies a co de s mbolo (funes ou variveis) que so referenciadas a partir dos arquivos co a a objeto que ele j tiver processado mas no ainda denido. Os arquivos objeto a a que denem aqueles s mbolos so extra a dos da biblioteca esttica e inclu a dos no executvel nal. Pelo fato de o programa linkador procurar na biblioteca a esttica ` medida que elas aparecem na linha de comando, faz sentido colocar a a a biblioteca esttica no nal da linha de comando. Por exemplo, suponhamos a que test.c contenha o cdigo na Listagem 2.8 e app.c contenha o cdigo na o o Listagem 2.9. Listagem 2.8: (test.c) Area da Biblioteca
1 int f ( ) 2 { 3 return 3 ; 4 }

Listagem 2.9: Um Programa Que Utiliza as Funes da Biblioteca Acima co


1 2 3 4 5 6 extern i n t f () ; i n t main ( ) { return f ( ) ; }

Agora suponhamos que test.o seja combinado com alguns outros arquivos objetos para produzir uma bilbioteca esttica libtest.a. A seguinte linha de a comando ir falhar: a % gcc -o app -L. -ltest app.o app.o: In function main: app.o(.text+0x4): undefined reference to f collect2: ld returned 1 exit status
Voc pode usar outros sinalizadores para remover um arquivo de uma biblioteca e esttica ou executar outras operaes em uma bilioteca esttica. Essas operaes so a co a co a raramente usadas mas esto documentadas na pgina de manual do ar. a a
8

48

A mensagem de erro indica que mesmo que libtest.a contenha uma denio de f, o programa de linkagem no a encontra. Isso ocorre pelo fato ca a de que a libtest.a foi pesquisada quando em primeiro lugar e antes de app.o, e naquele ponto o programa de linkagem no viu nenhuma referncia a f. a e Por outro lado, se usarmos a linha abaixo, nenhuma mensagem de erro e mostrada: % gcc -o app app.o -L. -ltest A razo que a referncia a f em app.o faz com que o programa de a e e linkagem inclua o arquivo objeto test.o contido na biblioteca esttica libtest.a. a

2.3.2

Bibliotecas Compartilhadas

Uma biblioteca compartilhada (tambm conhecida como um objeto compare tilhado, ou como uma biblioteca linkada dinamicamente) similar a uma e biblioteca esttica no sentido de que uma biblioteca dinmica um agrupaa a e mento de arquivos objeto. Todavia, existem muitas diferenas importantes.A c diferena mais fundamental que quando uma biblioteca compartilhada for c e linkada em um programa, o executvel nal no conter o cdigo que est prea a a o a sente na biblioteca compartilhada. Ao invs disso, o executvel meramente e a contm uma referncia ` biblioteca compartilhada. Se muitos programas no e e a sistema forem linkados usando a mesma biblioteca compartilhada, eles iro a todos referencia a referida biblioteca compartilhada, mas nenhum deles ir a conter algum cdigo da biblioteca. Dessa forma, a biblioteca compartio e lhada por todos os programas que foram linkados fazendo referncia a ela. e Uma segunda diferena que uma biblioteca compartilhada no meramente c e a e uma coleo de arquivos objeto, entre os quais objetos o programa de linkaca gem escolhe aquele que necessrio para satisfazer refercias no denidas e a e a no cdigo principal do programa que est sendo linkado. Ao invs disso, os o a e arquivos objetos que compes a biblioteca compartilhada esto combinados o a dentro de um unico arquivo objeto de forma que um programa que tiver sido linkado referenciando uma biblioteca compartilhada sempre inclua todo o cdigo presente na biblioteca, em lugar de apenas aquelas pores que forem o co necessrias. Para criar uma bibioteca compartilhada, voc deve compilar os a e objetos que iro compor a biblioteca usando a opo -fPIC no compilador, a ca da seguinte forma: % gcc -c -fPIC test1.c A opo -fPIC 9 diz ao compilador que voc estar usando test1.o como ca e a parte de um objeto compartilhado.
9

Position-Independent Code.

49

Cdigo Independente da Posio - (PIC) o ca PIC habilita o suporte a cdigo independente da posio. As funes em o ca co uma biblioteca compartilhada podem ser chamadas em diferentes endereos c em diferentes programas, de forma que o cdigo no objeto compartilhado no o a ca dependente do endereo (ou posio) a partir do qual chamado. Essa c ca e considerao no tem impacto sobre voc, como programador, exceto que voc ca a e e deve lembrar-se de usar o sinalizador -fPIC quando estiver compilando algum cdigo que ir ser usado em uma biblioteca compartilhada. o a

Ento voc combina os arquivos objetos dentro de uma biblioteca coma e partilhada, como segue: % gcc -shared -fPIC -o libtest.so test1.o test2.o A opo -shared diz ao programa de linkagem produzir uma biblioteca ca compartilhada em lugar de um arquivo executvel comum. As bibliotecas a compartilhadas usam a extenso .so, que usada para objeto compartilhado. a e Da mesma forma que nas bibliotecas estticas, o nome sempre comea com a c lib para indicar que o arquivo uma biblioteca. e A linkagem fazendo referncia a uma biblioteca compartilhada da mesma e e forma que a linkagem referenciando uma biblioteca esttica. Por exemplo, a a linha abaixo ir fazer a linkagem referenciando libtest.so se libtest.so esa tiver no diretrio atual, ou em um dos diretrios de busca de bibliotecas o o padronizados do sistema: % gcc -o app app.o -L. -ltest Suponhamos agora que ambas as biblioteca libtest.a e libtest.so estejam dispon veis. Ento o programa de linkagem deve uma das bibliotecas e no a a outras. O programa de linkagem busca cada diretrio (primeiramente aqueles o especicados com a opo -L, e ento aqueles nos diretrios pardronizados ca a o de bibliotecas do sistema). Quando o programa de linkagem encontra um diretrio que contenha qualquer uma ou libtest.a ou libtest.so, o programa o de linkagem para a busca nos diretrios. Se somente uma das duas variantes o estiver presente no diretrio, o programa de linkagem escolhe aquela vario ante que foi encontrada em primeiro lugar. De outra forma, o programa de linkagem escolhe a verso compartilhada, a menos que voc explicitamente a e instrua ao programa de linkagem para proceder de outra forma. Voc pode e usar a opo -static para exigir bibliotecas estticas. Por exemplo, a linha de ca a comando adiante ir usar a biblioteca esttica libtest.a, mesmo se a biblioteca a a compartilhada libtest.so estiver tambm presente: e % gcc -static -o app app.o -L. -ltest 50

O comando ldd mostra as bibliotecas compartilhadas que so referencia adas dentro de um executvel. Essas bibliotecas precisam estar dispon a veis quando o executvel for chamado. Note que o comando ldd ir listar uma a a biblioteca adicional chamada ld-linux.so, que uma parte do mecanismo de e linkagem dinmica do GNU/Linux. a Usando a Varivel de Ambiente LD LIBRARY PATH Quando voc a e zer a linkagem de um programa referenciando uma biblioteca compartilhada, o programa de linkagem no coloca o caminho completo da locaa lizao da biblioteca compartilhada no executvel resultante. Ao invs disso, ca a e o programa de linkagem coloca apenas o nome da biblioteca compartilhada. Quando o programa for executado, o sistema busca pela biblioteca compartilhada e a torna dispon para ser usada pelo programa que precisa dela. vel O sistema busca somente no /lib e no /usr/lib por padro. Se uma biblioa teca compartilhada que for referenciada por seu programa executvel estiver a instalada fora daqueles diretrios, essa biblioteca compartilhada no ir ser o a a encontrada, e o sistema ir se recusar a executar o programa. a Uma soluo para esse problema usar a opo -Wl,-rpath ao usar o ca e ca programa de linkagem. Suponhamos que voc use o seguinte: e % gcc -o app app.o -L. -ltest -Wl,-rpath,/usr/local/lib Ento, quando o programa app estiver executando, o sistema ir buscar a a em /usr/local/lib por qualquer biblioteca compartilhada requerida. Outra soluo para esse problema ajustar a varivel de ambiente LD LIca e a ca BRARY PATH na hora da execuo do programa de linkagem. Da mesma forma que a varivel de ambiente PATH, LD LIBRARY PATH uma lista de a e diretrios separados por ponto e v o rgula. Por exemplo, se LD LIBRARY PATH for /usr/local/lib:/opt/lib, ento /usr/local/lib e /opt/lib sero buscaa a dos antes dos diretrios padro /lib e /usr/lib. Voc deve tambm notar que o a e e se voc tiver LD LIBRARY PATH, o programa de linkagem ir buscar os e a diretrios fornecidos l adicionalmente aos diretrios fornecidos com a opo o a o ca 10 -L quando estiver construindo um executvel. a

2.3.3

Bibliotecas Padronizadas

Mesmo se voc no especicar qualquer bibliotecas durante a fase de line a kagem, o seu programa certamente usa uma biblioteca compartilhada. Isso
Voc pode ver uma referncia a LD RUN PATH em alguma documentao na Intere e ca net . No acredite no que voc l; essa varivel atualmente no faz nada em GNU/Linux. a e e a a
10

51

acontece pelo fato de GCC automaticamente fazer a linkagem usando a biblioteca C padro, a libc, mesmo sem voc pedir. As funes matemticas a e co a da biblioteca C GNU padro no esto inclu a a a das na libc; ao invs disso, as e funes matemticas constituem uma biblioteca separada, a libm, a qual voc co a e precisa especicar explicitamente. Por exemplo, para compilar e fazer a linkagem do programa compute.c que utiliza funes trigonomtricas tais como co e sin e cos, voc deve chamar o seguinte cdigo: e o % gcc -o compute compute.c -lm Se escrever um programa em C++ e zer a linkagem dele usando os comandos c++ ou g++, voc ir tambm usar a biblioteca padro GNU e a e a C++, libstdc++, automaticamente.

2.3.4

Dependncia de uma Biblioteca e

Uma biblioteca ir muitas vezes depender de outra biblioteca . Por exemplo, a muitos sistemas GNU/Linux incluem a libti, uma biblioteca que contm e funes para leitura e escrita de arquivos de imagem no formato TIFF. Essa co biblioteca, por sua vez, utiliza as bibliotecas libjpeg (rotinas de imagens no formato JPEG) e libz (rotinas de compresso). A Listagem 2.10 mostra a um pequeno programa que usa a biblioteca libti para abrir um arquivo de imagem no formato TIFF. Listagem 2.10: (titest.c) Usando a libti
1 2 3 4 5 6 7 8 9 10 #include <s t d i o . h> #include < t i f f i o . h> i n t main ( i n t a r g c , char a r g v ) { TIFF t i f f ; t i f f = TIFFOpen ( a r g v [ 1 ] , r ) ; TIFFClose ( t i f f ) ; return 0 ; }

Grave esse arquivo fonte como titest.c. Para compilar esse programa e fazer a linkagem referenciando a libti, especique a opo -lti na sua linha ca de linkagem: % gcc -o tifftest tifftest.c -ltiff Por padro, o comando acima ir selecionar a biblioteca compartilhada a a pela verso da libti, encontrada em /usr/lib/libti.so. Pelo fato de libti a utilizar libjpeg e libz, uma verso de biblioteca compartilhada dessas duas a e tambm puxada (uma biblioteca compartilhada pode tambm apontar para e e outra biblioteca compartilhada da qual depende). Para vericar isso, use o comando ldd : 52

% ldd tifftest linux-gate.so.1 => (0xffffe000) /lib/libsafe.so.2 (0xb7f58000) libtiff.so.3 => /usr/lib/libtiff.so.3 (0xb7ee6000) libc.so.6 => /lib/libc.so.6 (0xb7d9a000) libdl.so.2 => /lib/libdl.so.2 (0xb7d96000) libjpeg.so.62 => /usr/lib/libjpeg.so.62 (0xb7d76000) libz.so.1 => /usr/lib/libz.so.1 (0xb7d62000) libm.so.6 => /lib/libm.so.6 (0xb7d3c000) /lib/ld-linux.so.2 (0xb7f5f000) Bibliotecas estticas, por outro lado, no podem apontar para outras a a biblioteca. Se voc decidir fazer a linkagem com a verso esttica da libti e a a especicando a opo -static na sua linha de comando, voc ir encontrar ca e a s mbolos no resolvidos: a
% gcc -static -o tifftest tifftest.c -ltiff /usr/lib/.../libtiff.a(tif_aux.o): In function TIFFVGetFieldDefaulted: (.text+0x621): undefined reference to pow /usr/lib/.../libtiff.a(tif_jpeg.o): In function TIFFjpeg_data_src: (.text+0x189): undefined reference to jpeg_resync_to_restart /usr/lib/.../libtiff.a(tif_jpeg.o): In function TIFFjpeg_destroy: ...

Para fazer a linkagem desse programa estaticamente, voc deve especicar e as outras duas bibliotecas explicitamente: % gcc -static -o tifftest tifftest.c -ltiff -ljpeg -lz Ocasionalmente, duas bibliotecas iro ser mutuamente dependentes. Em a outras palavras, a primeira biblioteca esttica ir referenciar s a a mbolos na segunda biblioteca esttica, e vice versa. Essa situao geralmente provea ca e niente de um planejamento falho, mas aparece ocasionalmente. Nesses casos, voc pode repetir uma biblioteca multiplas vezes na linha de comando. O e programa de linkagem ir refazer a procura na biblioteca cada vez que isso a ocorrer. Por exemplo, a linha adiante ir fazer com que libqqcoisa.a seja a procurada multiplas vezes: % gcc -o app app.o -lqqcoisa -loutracoisa -lqqcoisa De forma que, mesmo se libqqcoisa.a referencie s mbolos em liboutracoisa.a, e vice versa, o programa ir ser linkado com sucesso. a 53

2.3.5

Prs e Contras o

Agora que voc sabe tudo sobre bibliotecas estticas e bibliotecas compare a tilhadas, voc est provavelmente se perguntando qual usar. Existe umas e e poucas consideraoes maiores para ter em mente. c Uma grande vantagem de uma biblioteca compartilhada que essa biblie oteca compartilhada economiza espao no sistema onde o programa estiver c instalado. Se voc estiver instalando 10 programas, e eles todos fazem uso e da mesma biblioteca compartilhada, ento voc libera uma grande quantia e dade de espao usando uma biblioteca compartilhada. Se voc tiver usado c e biblioteca esttica em substituio ` compatilhada, a biblioteca est inclu a ca a a da em todos os 10 programas repetidamente. Ento, usando bibliotecas coma partilhadas libera espao em disco. As bibliotecas compartilhadas tambm c e reduzem tempos cpia e libera recursos de coneco se seu programa est o ca a sendo copiado a partir da web. Uma vantagem relacionada `s bibliotecas a compartilhadas que o usurios podem escolher entre atualizar as biblioe a tecas com ou sem atualizar todos os programas que dependem delas. Por exemplo, suponha que voc produza uma biblioteca compartilhada que gee rencia coneces HTTP. Muitos programas podem depender dessa biblioteca. co Se voc encontrar um erro nessa biblioteca, voc pode atualizar a biblioteca. e e instantaneamente, todos os programas que dependerem da biblioteca iro ser a corrigidos; voc no ter que refazer a linkagem de todos os programas que e a a seria o caminho adotado caso se estivesse usando a linkagem esttica. As vana tagem acima fariam voc pensar em usar sempre a biblioteca compartilhada. e Todavia, razes substanciais existem para o uso da biblioteca esttica em o a lugar da compartilhada. O fato que uma atualizao com o uso de uma bica blioteca compartilhada afeta todos os programas que dependem dela pode ser uma desvantagem. Por exemplo, se voc estiver desenvolvendo um programa e de alta disponibilidade, voc pode preferir fazer a linkagem referenciando e uma biblioteca esttica de forma que uma atualizao de bibliotecas coma ca partilhadas no sistema no afete seu programa. (De outra forma, usurios a a podem atualizar a biblioteca compartilhada, afetando seu programa que foi compilado referenciando bibliotecas compartilhadas e causarem uma parada no programa, e ento chamar sua linha de suporte ao usurio, censurando a a voc!) Se voc est indo pelo caminho de no instalar suas biblioteca no /lib e e a a ou no /usr/lib, voc deve denitivamente pensar duas vezes sobre usar uma e biblioteca compartilhada. (Voc no espera instalar suas bibliotecas naquee a les diretrios se voc no esperar que usurios que iro instalar seu software o e a a a possuam privilgio de administrador.) Particularmente, a opo/artif de e ca cio compilao -Wl,-rpath no ir servir de nada se voc no sabe onde as biblica a a e a otecas esto indo parar. E pedindo a seus usurios para ajustar a varivel a a a 54

de ambiente LD LIBRARY PATH signica uma tarefa extra para eles. Pelo fato de cada usurio ter de fazer isso individualmente, isso uma substancial a e e adicional carga de responsabilidade. Voc ir ter que pesar essas vantagens e a e desvantagens para cada programa que voc vier a distribuir. e

2.3.6

Carregamento e Descarregamento Dinmico a

Algumas vezes voc pode desejar carregar algum cdigo em tempo de execue o ca o sem explicitamente fazer a linkagem daquele cdigo. Por exemplo, cono sidere uma aplicao que suporta mdulos do tipo plug-in, tal como um ca o navegador Internet . O navegador permite a desenvolvedores externos ao projeto criar acessrios para fornecer ao navegador funcionalidades adicio onais. Os desenvolvedores externos criam bibliotecas compartilhadas e as colocam em uma localizao conhecida pelo navegador. O navegador ento ca a automaticamente carrega o cdigo nessas bibliotecas. Essa funcionalidade o est dispon em ambiente GNU/Linux atravs do uso da funo dlopen. a vel e ca Voc j pode ter aberto uma biblioteca compartilhada chamada libtest.so e a chamando a funo dlopen da forma abaixo: ca dlopen ("libtest.so", RTLD_LAZY) (O segundo parmetro um sinalizador que indica como associar s a e mbolos na biblioteca compartilhada. Voc pode consultar as pginas de manual e a instaladas no seu sistema sobre dlopen se voc desejar mais informao, mas e ca RTLD LAZY comumente a opo que voc deseja.) Para usar funes de e ca e co carregamento dinmico, inclua o arquivo de cabealho <dlfcn.h> e faa a a c c linkagem com a opo -ldl para selecionar a biblioteca libdl. ca O valor de retorno dessa funo um void * que usado como um manica e e pulador para a biblioteca compartilhada. Voc pode passar esse valor para a e funo dlsym para obter o endereo de uma funo que tiver sido chamada ca c ca com a biblioteca compartilhada. Por exemplo, se libtest.so dene uma funo ca chamada minha funcao, voc pode ter chamado a minha funcao como segue: e void* manipulador = dlopen ("libtest.so", RTLD_LAZY); void (*test)() = dlsym (manipulador, "minha_funcao"); (*test)(); dlclose (manipulador); A funo dlsym pode tambm ser usada para obter um apontador para ca e uma varivel esttica na biblioteca compartilhada. a a Ambas as funes dlopen e dlsym retornam NULL se no obtiverem suco a cesso. no evento descrito acima, voc pode chamar a funo dlerror (sem e ca 55

parmetros) para obter uma mensagem de erro em formato leg aos hua vel manos descrevendo o problema. A funo dlclose descarrega a biblioteca compartilhada. Tecnicamente, ca a funo dlopen carrega a biblioteca somente se a referida biblioteca j no ca a a tiver sido chamada anteriormente. Se a biblioteca j tiver sido chamada, a dlopen simplesmente incrementa o contador de referncia da biblioteca. Sie milarmente, a funo dlclose decrementa o contador de referncia e ento ca e a descarrega a biblioteca somente se o contador de referncia tiver alcanado e c o valor zero. Se voc est escrevendo um cdigo em sua biblioteca compartilhada em e a o C++, voc ir provavelmente desejar declarar aquelas funes e variveis que e a co a voc planeja acessar a partir de algum lugar com o especicador de linkagem e extern C. Por exemplos, se a funo C++ minha funcao estiver em uma ca biblioteca compartilhada e voc desejar acessar essa funo com a funo e ca ca dlsym, voc deve declarar a minha funcao como segue: e extern "C" void minha_funcao (); Isso evita que o compilador C++ desgure o nome da funo, pelo fato ca de o compilador C++ poder mudar o nome da funo de minha funo para ca ca um diferente, um nome mais engraado ao olhar que expresse informaes c co extras sobre a funo. Um compilador C no ir desgurar nomes; os nomes ca a a iro ser usados qualquer que seja o nome que voc fornea para sua funo a e c ca ou varivel. a

56

Cap tulo 3 Processos


UMA INSTANCIA EXECUTANDO UM PROGRAMA CHAMA-SE UM PROCESSO. Se voc tem duas janelas de terminal exibindo informaes em e co sua tela, ento voc est provavelmente executando o mesmo programa de a e a terminal duas vezes voc tem dois processos de terminal. Cada janela de e terminal est provavelmente executando um shell ; cada shell sendo executado a um outro processo. Quando voc chama um comando em um shell, o e e programa correspondente executado em um novo processo; o processo de e shell continua quando o processo do comando chamado se completar. Programadores avanados muitas vezes utilizam muitos processos em coc operao em uma unica aplicao para habilitar a capacidade da aplicao ca ca ca de executar mais de uma coisa ao mesmo tempo, para incrementar robustez da aplicao, e para fazer uso dos programas j existentes. ca a A maioria das funes de manipulao de processos descritas nesse cap co ca tulo so similares a aquelas em outros sistemas UNIX. A maioria declarada no a e arquivo de cabealho <unistd.h>; verique a pgina de manual de cada c a funo para ter certeza. ca

3.1

Visualizando Processos

Sempre que voc senta em seu computador para us-lo, exitem processos em e a atividade. Todos os programas sendo executados usam um ou mais processos. Vamos iniciar dando uma olhada nos processos j existentes em seu a computador. 57

3.1.1

Identicadores de Processos

Cada processo em um sistema GNU/Linux identicado por seu unico e nmero de identicao, algumas vezes referenciado como pid. Identicadou ca res de Processos so nmeros inteiros de 16-bit que so atribuidos sequnciala u a e mente pelo kernel GNU/Linux a cada vez que um novo processo criado. e Todo processo tem um processo pai (exceto o processo init, descrito na Seo 3.3.4, Processos do Tipo Zumbi). Dessa forma, voc pode pensar de ca e processos em um sistema GNU/Linux como organizados em uma rvore, com a o processo init sendo a ra principal que originou toda a rvore. A identiz a cao do processo pai, ou ppid, simplesmente o nmero de identicao ca e u ca do processo pai. Quando zermos referncia ao nmero de identicao de e u ca um processo em um programa em C ou em C++, sempre usa-se a denio ca de tipo pid t, que feita em <sys/types.h>. Um programa pode obter o e nmero de identicao do processo que o est executando com a chamada u ca a de sistema getpid(), e o programa tambm pode obter o nmero de identie u cao de processo do processo que o originou com a chamada de sistema ca getppid(). Por exemplo, o programa na Listagem 3.1 mostra o o nmero de u identicao do processo que o est executando e o nmero de identicao ca a u ca do processo que o originou. Listagem 3.1: ( print-pid.c) Mostrando o ID do Processo
1 2 3 4 5 6 7 8 9 #include <s t d i o . h> #include <u n i s t d . h> i n t main { printf printf return } () ( O i d do p r o c e s s o e %d\n , ( i n t ) g e t p i d ( ) ) ; ( O i d do p r o c e s s o p a i e %d\n , ( i n t ) g e t p p i d 0;

() ) ;

Observe que se voc chamar esse programa muitas vezes, um ID diferente e de processo ser reportado a cada vez que voc chamar o programa pelo a e fato de cada chamada estar em um novo processo. Todavia, se voc chamar e o programa vrias vezes a partir da mesma janela de shell, o nmero de a u identicao do processo que o originou (isto , a nmero de identicao do ca e u ca processo do shell ) o mesmo. e

3.1.2

Visualizando os Processos Ativos

O comando ps mostra os processos que estiverem sendo executados sobre seu sistema. A verso GNU/Linux do ps tem muitas opes pelo fato de tentar a co ser compat com as verses do ps de muitas outras variantes UNIXs. Essas vel o 58

opes controlam quais processos so listados e qual informao sobre cada co a ca processo dever ser mostrada. a Por padro, chamando ps mostra os processos controlados pelo terminal a ou janela de terminal na qual o comando ps for chamado. Por exemplo: % ps PID TTY 21693 pts/8 21694 pts/8

TIME CMD 00:00:00 bash 00:00:00 ps

Essa chamada de ps mostra dois processos. O primeiro, o bash, um shell e executando sobre o referido terminal. O segundo a instncia de execuo e a ca do programa ps propriamente dito. A primeira coluna, rotulada PID, mostra o nmero de identicao de cada processo listado na sa do comando. u ca da Para uma olhada mais detalhada no que est sendo executado no seu a sistema GNU/Linux, use o seguinte: % ps -e -o pid,ppid,command A opo -e instrui o ps a mostrar todos os processos sendo executados no ca sistema. A opo -o pid,ppid,command diz ao ps qual informao mostrar ca ca sobre cada processo no caso acima, o ID do processo, o ID do processo pai, e o comando sendo executado no referido processo.
Formatos de Sa do ps da Com a opo -o fornecida ao comando ps, voc especica a informao soca e ca bre o processo que voc deseja na sa no formato de uma lista separada e da por v rgulas. por exemplo, ps -o pid,user, start time,command mostra o ID do processo, o nome do usurio dono do processo, o tempo decorrido desde a quando o processo comeou, e o comando que est executando o processo. c a Veja a pgina de manual do comando ps para a lista completa dos cdigos a o de campo. Voc pode usar as opes -f (lista completa), -l (lista longa), ou e co -j (lista de tarefas) ao invs da opo -o acima e usar esses trs diferentes e ca e formatos predenidos de listagem (completa, longa ou de tarefas).

Aqui est algumas linhas iniciais e nais de sa do comando ps em meu a da sistema. Voc pode ver diferentes sa e das, dependendo do que estiver sendo executado em seu sistema. % ps -e -o pid,ppid,command PID PPID COMMAND 1 0 init [5] 2 1 [kflushd] 59

1 [kupdate]

... 21725 21693 xterm 21727 21725 bash 21728 21727 ps -e -o pid,ppid,command Note que o ID do processo pai do comando ps, 21727, o ID do bash, o e shell a partir do qual chamou-se o ps. O processo pai do bash por sua vez o e de nmero 21725, o ID do processo do programa xterm no qual o shell est u a sendo executado.

3.1.3

Encerrando um Processo

Voc pode encerrar um processo que est sendo executado com o comando e a kill. Simplesmente especicando na linha de comando o ID do processo a ser encerrado. O comando kill trabalha enviando ao processo um SIGTERM, ou sinal de encerramento.1 Isso faz com que o processo encerre, a menos que o programa em execuo explicitamente manipule ou mascare o sinal SIGTERM. Sinais ca so descritos na Seo 3.3, Sinais. a ca

3.2

Criando Processos

Duas tcnicas so usadas para criar um novo processo. A primeira relae a e tivamente simples mas deve ser usada de forma bem comedida e econmica o pelo fato de ser ineciente e de ter considerveis riscos de segurana. A sea c gunda tcnica mais complexa mas fornece grande exibilidade, rapidez, e e e segurana. c

3.2.1

Usando system

A funo system na biblioteca C GNU padro fornece um caminho fcil ca a a para executar um comando dentro de um programa, principalmente se o comando tiver sido digitado dentro de um shell. De fato, a funo system ca cria um sub-processo que executa o shell Bourne padro (/bin/sh) e repassa o a comando `quele shell para execuo. Por exemplo, o programa na Listagem a ca 3.2 chama o comando ls para mostrar o contedo do diretrio ra como se u o z, voc digitasse ls -l / dentro de um shell. e
Voc pode tambm usar o comando kill para enviar outros sinais a um processo. Isso e e descrito na Seo 3.3.1, Encerramento de Processos. e ca
1

60

Listagem 3.2: (system.c) Usando uma chamada ` funo system a ca


1 2 3 4 5 6 7 8 #include < s t d l i b . h> i n t main ( ) { int r e t u r n v a l u e ; r e t u r n v a l u e = system ( l s l / ) ; return r e t u r n v a l u e ; }

A funo system retorna a condio de sa do comando do shell. Se o ca ca da shell propriamente dito no puder ser executado, a funo system retorna o a ca cdigo 127; se outro erro ocorrer, a funo system retorna -1. o ca Pelo fato de a funo system usar um shell para chamar seu comando, ela ca d margens a recursos, limitaes, e a falhas de segurana do shell de seu sisa co c tema. Voc no pode saber seguramente sobre a disponibilidade de qualquer e a verso em particular do shell Bourne. Em muitos sistemas UNIX, /bin/sh a e uma ligao simblica para outro shell. Por exemplo, na maioria dos sisteca o mas GNU/Linux, o /bin/sh aponta para o bash (o Bourne-Again SHell ), e diferentes distribuies GNU/Linux utilizam diferentes verses do bash. Chaco o mando um programa com privilgios de administrador com a funo system, e ca pode exemplo, pode ter diferentes resultados sob diferentes sistemas GNU/Linux. Devido ao que foi aqui exposto, prefer usar o mtodo fork and e vel e exec (bifurcar e executar) para criar processos.

3.2.2

Usando bifurcar e executar

A API 2 do DOS e do Windows possuem a fam spawn de funes. Essas lia co funes recebem como argumento o nome de um programa para executar e co criam uma nova intncia de processo daquele programa. O GNU/Linux no a a contm uma funo que faz tudo isso de uma vez s. Ao invs disso, fornece e ca o e uma funo, a funo fork, que cria um processo lho que uma cpia exata ca ca e o de seu processo pai. GNU/Linux fornece outro conjunto de funes, a fam co lia das funes exec, que faz com que um processo em particular no mais seja co a uma instncia de um programa e ao invs disso torne-se uma instncia de a e a outro programa. Para criar um novo processo, voc primeiramente deve usar e a funo fork para fazer uma cpia do processo atual que est executando ca o a seu programa. A seguir voc usa a funo exec para transformar um desses e ca dois processos iguais em uma instncia do programa que voc deseja criar. a e Chamando a funo fork Quando um programa chama a funo fork, ca ca um processo clone do processo que fez a chamada, chamado processo lho, criado. O processo pai continua executando o programa na instruo e ca
2

Nota do tradutor: Application Programming Interface.

61

imediatamente aps a instruo que chamou a funo fork. O processo lho, o ca ca tambm, executa o mesmo programa a partir da mesma posio de instruo. e ca ca Como fazer para os dois processos diferirem? Primeiramente, o processo lho um novo processo e portanto tem um novo ID de processo, distinto e do ID de seu processo pai. Um caminho para um programa distinguir se ele mesmo est em um processo pai ou em um processo lho chamar a a e funo getpid da biblioteca C GNU padro. Todavia, a funo fork fornece ca a ca diferentes valores de retorno quando chamada a partir de um processo pai ou a partir de um processo lho um processo entra na chamada a fork, dois processos saem com diferentes valores de retorno. O valor de retorno no processo pai o ID de processo do processo lho. O valor de retorno no e processo lho zero. Pelo fato de nenhum processo mesmo ter um ID de e processo com o valor zero, isso torna fcil para o programa distinguir se est a a sendo executado como o processo pai ou processo lho. A Listagem 3.3 um exemplo de utilizao da funo fork para duplicar e ca ca o processo de um programa. Note que o primeiro bloco da declarao if ca e executado somente no processo pai, enquando a clusula else executada no a e processo lho. Listagem 3.3: ( fork.c) Usando fork para Duplicar o Processo de um Programa
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <s t d i o . h> #include <s y s / t y p e s . h> #include <u n i s t d . h> i n t main ( ) { pid t child pid ; printf ( o i d do p r o c e s s o do programa principal e %d\n , ( i n t ) getpid () ) ;

child pid = fork () ; i f ( c h i l d p i d != 0 ) { p r i n t f ( e s s e e o p r o c e s s o p a i , com i d %d\n , ( i n t ) g e t p i d ( ) ) ; p r i n t f ( o i d do p r o c e s s o f i l h o e %d\n , ( i n t ) c h i l d p i d ) ; } else p r i n t f ( e s s e e o p r o c e s s o f i l h o , com i d %d\n , ( i n t ) g e t p i d ( ) ) ; return 0 ; }

Usando a Fam exec As funes exec substituem o programa que est lia co a sendo executado em um processo por outro programa. Quando um programa chama uma funo exec, o processo que abriga a chamada feita ` funo exec ca a ca imediatamente cessa de executar o programa atual e inicia a execuo de um ca novo programa a partir do in cio desse mesmo novo programa, assumindo que a chamada ` funo exec tenha sido executada com sucesso. a ca Dentro da fam de funes exec, existem funes que variam de forma lia co co muito pequena na parte que se refere a compatibilidade e no que se refere ` a 62

maneira de serem chamadas. Funes que possuem a letra p em seus nomes (execvp e execlp) co aceitam um nome de programa e procuram por um programa que tenha o nome recebido no atual caminho de execuo; funes que ca co no contiverem o p no nome devem receber o caminho completo a de localizao do programa a ser executado. ca Funes que possuem a letra v em seus nome (execv, execvp, e co execve) aceitam a lista de argumentos para o novo programa como um vetor terminado pelo caractere NULL de apontadores para sequncias de caractere. Funes que contiverem a letra l(execl, e co execlp, e execle) aceitam a lista de argumentos usando o mecanismo varargs da linguagem C. a As funes que possuem a letra e em seus nomes (execve e co execle) aceitam um argumento adicional, um vetor de variveis a de ambiente. O argumento deve ser um vetor de apontadores para sequncia de caracteres terminado pelo caractere NULL. Cada e sequncias de caractere deve ser da forma VARIAVEL=valor. e
Nota do tradutor: Veja http://www.cs.utah.edu/dept/old/texinfo/glibcmanual-0.02/library toc.html #SEC472 e tambm http://gcc.gnu.org/onlinedocs/gccint/Varargs.html. e
a

Pelo fato de a funo exec substituir o programa chamado por outro, ela ca nunca retorna a menos que um erro ocorra. A lista de argumentos passada ao programa anloga aos argumentos de e a linha comando que voc especica a um programa quando voc o executa e e a partir de um shell. Eles esto disponiveis atravs dos parmetros argc a e a e de argv passados ` funo main. Lembre-se, quando um programa for a ca chamado a partir de um shell, o shell ajusta o primeiro elemento da lista de argumentos (argv[0] ) para o nome do programa, o segundo elemento da lista de argumentos (argv[1] ) para o primeiro argumento da linha de comando, e assim por diante. Quando voc usar uma funo exec em seu programa, e ca voc, tambm, deve passar o nome da funo como o primeiro elemento da e e ca lista de argumentos. Usando fork e exec Juntas Um modelo comum para executar um subprograma dentro de um programa primeiramente bifurcar o processo e ento e a executar o sub-programa. Isso permite que o programa que fez a chamada continue a execuo no processo pai enquanto o mesmo programa que fez a ca chamada substitu pelo subprograma no processo lho. e do 63

O programa na Listagem 3.4, da mesma forma que a Listagem 3.2, mostra o contedo do diretrio ra usando o comando ls. Diferindo do exemplo u o z anterior, de outra forma, a Listagem 3.4 chama o comando ls diretamente, passando ao ls os argumentos de linha de comando -l e / ao invs de e chamar o ls a partir de um shell. Listagem 3.4: ( fork-exec.c) Usando fork e exec Juntas
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #include #include #include #include <s t d i o . h> < s t d l i b . h> <s y s / t y p e s . h> <u n i s t d . h>

/ Gera um p r o c e s s o f i l h o e x e c u t a n d o um p r o g r a m a n o v o . PROGRAM e o nome do p r o g r a m a a s e r e x e c u t a d o ; o caminho i r a s e r p r o c u r a n d o p o r e s s e p r o g r a m a . ARG LIST e um NULL e r m i n a d a l i s t a d e s t r i n g s c a r a c t e r e a s e r e m t i n f o r m a d a como a l i s t a d e a r g u m e n t o s do p r o g r a m a . R e t o r n a o i d d e p r o c e s s o do processo gerado . / i n t spawn ( char program , char { pid t child pid ; arg list )

/ D u p l i c a o p r o c e s s o a t u a l . / child pid = fork () ; i f ( c h i l d p i d != 0 ) / E s s e e o p r o c e s s o p a i . / return c h i l d p i d ; else { / Agora e x e c u t e PROGRAM, b u s c a n d o p o r e l e no caminho . e x e c v p ( program , a r g l i s t ) ; / A f u n c a o e x e c v p r e t o r n a s o m e n t e s e um e r r o o c o r r e r . f p r i n t f ( s t d e r r , um e r r o o c o r r e u em e x e c v p \n ) ; abort () ; } }

/ /

i n t main ( ) { / A l i s t a d e a r g u m e n t o s i n f o r m a d a ao comando l s . / char a r g l i s t [ ] = { ls , / a r g v [ 0 ] , o nome do p r o g r a m a . / l , / , NULL / A l i s t a d e a r g u m e n t o s d e v e t e r m i n a r com um NULL . }; / Gera um p r o c e s s o f i l h o r o d a n d o o comando l s . i d de p r o c e s s o f i l h o r e t o r n a d o . / spawn ( l s , a r g l i s t ) ; printf ( t e r m i n e i com o programa p r i n c i p a l \n ) ; Ignora o

return 0 ; }

3.2.3

Agendamento de Processo

GNU/Linux faz o agendamento dos processos pai e processos lho independentemente; no existe garantias de qual dos dois ir ser executado em pria a meiro lugar, ou quanto tempo de execuo previamente ir decorrer antes de ca a GNU/Linux interromp-lo e liberar o ciclo de processamento para o outro e processo (ou para algum outro processo do sistema que no os processos pai a e lho aqui citados) ser executado. Em particular, nenhuma parte, alguma parte, ou todo o processo do comando ls pode executar em um processo lho 64

antes de o processo pai que o criou ser encerrado.3 GNU/Linux promete que cada processo ir ser executado em algum momento nenhum processo ir a a ser totalmente discriminado na distribuio dos recursos de execuo.4 ca ca Voc pode especicar que um processo menos importante e deve ree e ceber uma prioridades mais baixa atribuindo a esse processo um valor alto de gentileza. Por padro, todo processo recebe um valor de gentileza zero. a Um valor de gentileza mais alto signica que o processo recebe uma menor prioridade de execuo; de modo contrrio, um processo com um baixo (isto ca a , negativo) valor de gentileza recebe mais tempo de execuo. e ca Para executar um programa com um valor de gentileza no nulo, use o a comando nice, especicando o valor de gentileza com a opo -n. Por exemca plo, adiante mostra-se como voc pode chamar o comando sort entrada.txt e > saida.txt, que corresponde a uma longa operao de ordenao, como ca ca reduzida prioridade de forma que essa operao de ordenao no torne o ca ca a sistema muito lento: % nice -n 10 sort input.txt > output.txt Voc pode usar o comando renice para modicar o n de gentileza de e vel um processo sendo executado a partir da linha de comando. Para modicar o n de gentileza de um processo que est em execuo a vel a ca partir de outro programa, use a funo nice. O argumento dessa funo um ca ca e valor de incremento, que adicionado ao n de gentileza do processo est e vel a executando o programa cujo n de gentileza se deseja mudar. Lembre-se vel que um valor positivo aumenta o valor de gentileza e dessa forma reduz a prioridade de execuo de um processo. ca Note que somente um processo com privilgios de usurio root pode exee a cutar um ou outro processo com um valor de gentileza negativo ou reduzir o valor de gentileza de um processo que est sendo executado. Isso signica a que voc pode especicar valores negativos para os comando nice e renice e somente quando est acessando o computador como superusurio, e somente a a um processo executando com privilgios de superusurio pode enviar um vae a lor negativo para a funo nice da glibc. Esse comportamento previne que ca usurios comuns consigam prioriade de execuo em nome de outros usurios a ca a que no o seu prprio usando o sistema. a o
Um mtodo para denir a ordem de execuo de dois processos apresentado na e ca e seo 3.3.2, Esperando pelo Encerramento de um Processo. ca 4 Nota do tradutor:O autor refere-se aos algor tmos de escalonamento. Veja tambm e http://www.kernel.org/doc/#5.1.
3

65

3.3

Sinais

Sinais so mecanismos usados como forma de comunicao e manipulao a ca ca de processos em GNU/Linux. O tpico que fala de sinais muito extenso; o e aqui falaremos sobre alguns sinais mais importantes e tcnicas que so usadas e a para controlar processos. Um sinal uma mensagem especial enviada a um processo. Sinais so e a ass ncronos; quando um processo recebe um sinal, o referido processo manipula o sinal imediatamente, sem encerrar a funo que est processando no ca a momento ou mesmo sem encerrar a linha de cdigo que ele est executando o a no momento. Existem muitas dzias de diferentes sinais, cada um com um u signicado diferente. Cada tipo de sinal especicado atravs de seu nmero e e u de sinal, mas em programas, voc comumente se refere a um sinal atravs de e e seu nome. Em GNU/Linux, os sinais so denidos em /usr/include/bits/a signum.h. (Voc no deve incluir esse arquivo de cabealho diretamente em e a c seu programa; ao invs disso, use <signal.h>.) e Quando um processo recebe um sinal, esse mesmo processo pode ter uma entre muitas respostas/comportamentos, dependendo do comportamento do sinal recebido. Para cada sinal, existe um comportamento padro, que detera mina o que acontece ao processo se o programa executado no processo no a especica algum outro comportamento. Para a maioria dos tipos de sinal, um programa especica algum comportamento ou ignora o sinal ou chama uma funo especial manipuladora de sinal para responder ao sinal. Se uma ca funo manipuladora de sinal for usada, o programa atualmente em execuo ca ca colocado em estado de espera, a funo manipuladora de sinal executada, e ca e e, quando a funo manipuladora de sinal retornar, o programa que estava ca sendo executado na hora da chegada do sinal retomado pelo processo e e continua do ponto onde parou. O sistema GNU/Linux envia sinais a processos em resposta a condies co espec cas. Por exemplo, os sinais SIGBUS (erro de bus), SIGSEGV (violao de segmento de memria), e SIGFPE (exceo de ponto utuante) ca o ca podem ser enviados a um processo que tenta executar uma operao ilegal. ca O comportamento padro para esses sinais encerrar o processo e produzir a e um arquivo core. Um processo pode tambm enviar um sinal a outro processo. Um uso e comum desse mecanismo encerrar outro processo enviando um sinal SIGe TERM ou um sinal SIGKILL. 5
Qual a diferena? O sinal SIGTERM pergunta a um processo se ele pode terminar; o c processo pode ignorar a requisio por mascaramento ou ignorar o sinal. O sinal SIGKILL ca sempre encerra o processo imediatamente pelo fato de o processo no poder mascarar ou a ignorar o sinal SIGKILL.
5

66

Outro uso comum enviar um comando a um programa que est sendo e a executado. Dois sinais denidos pelo usurio so reservados com esse oba a jetivo: SIGUSR1 e SIGUSR2. O sinal SIGHUP algumas vezes usado para e esse propsito tambm, comumente para acordar um programa que est coo e a chilando ou fazer com que um programa releia seus arquivos de congurao. ca A funo sigaction pode ser usada para congurar um comportamento ca de sinal. O primeiro parmetro o nmero do sinal. Os dois parmetros a e u a imediatamente a seguir so apontadores para estruturas da funo sigaction; a ca o primeiro dos dois contm o comportamento desejado para aquele nmero e u de sinal, enquanto o segundo recebe o comportamento atualmente existente. O campo mais importante tanto na primeira como na segunda estrutura apontadas da funo sigaction sa handler. O sa handler pode receber um ca e dos trs valores abaixo: e SIG DFL, que especica o comportamento padro para o sinal. a SIG IGN, que especica a possibilidade de o sinal pode ser ignorado. Um apontador para uma funo manipuladora de sinal. A funo ca ca deve receber um parmetro, o nmero do sinal, e retornar void a . a u
a

Nota do tradutor:Vazio.

Pelo fato de sinais serem ass ncronos, o programa principal pode estar em um estado muito frgil quando um sinal processado e dessa forma a e tambm enquanto uma funo manipuladora de sinal est sendo executada. e ca a Portanto, voc deve evitar executar quaisquer operaes de E/S ou chamar a e co maior parte das funes de biblioteca e de sistema a partir de manipuladores co de sinal. Um manipulador de sinal executa o trabalho m nimo necessrio para resa ponder ao sinal, e ento retornar o controle ao programa principal (ou ena cerrar o programa). Na maioria dos casos, a tarefa do manipulador de sinal consiste simplesmente em gravar o fato de que um sinal ocorreu. O programa principal ento verica periodicamente se um sinal ocorreu e reage conforme a o sinal ocorrido ou no ocorrido. a poss que uma funo manipuladora de sinal seja interrompida por E vel ca meio da entrega de outro sinal. Embora isso seja uma ocorrncia rara, se e vier a ocorrer, ir ser muito dif diagnosticar e depurar o problema. (Isso a cil um exemplo de uma condio de corrida, discutida no Cap e ca tulo 4, Linhas de Execuo Seo 4.4, Sincronizao e Sees Cr ca ca ca co ticas.) Portanto, voc deve ser muito cuidadoso sobre o que seu programa faz em uma funo e ca manipuladora de sinal. 67

Mesmo a atribuio de um valor a uma varivel global pode ser perigosa ca a pelo fato de que a atribuio poder ser atualmente realizada em duas ou mais ca instrues de mquina, e um segundo sinal pode ocorrer entre essas duas co a instrues de mquina, abandonando a varivel em um estado corrompido. co a a Se voc vier a usar uma varivel global para marcar um sinal a partir de e a uma funo manipuladora de sinal, essa varivel deve ser do tipo especial ca a sig atomic t. GNU/Linux garante que atribuies a variveis desse tipo so co a a realizadas em uma unica instruo e portanto no pode ser interrompida no ca a meio do caminho. Em GNU/Linux, sig atomic t um int comum; de fato, e atribuies a tipos inteiros do tamanho de int ou de menor tamanho, ou para co apontadores, so atmicos. Se voc deseja escrever um programa que seja a o e portvel para qualquer sistema UNIX padronizado, apesar do que foi aqui a escrito, use o tipo sig atomic t para variveis globais. a O esqueleto de programa na Listagem 3.5 por exemplo, utiliza uma funo ca manipuladora de sinal para contar o nmero de vezes que o programa recebe u SIGUSR1, um dos sinais reservados para uso por aplicao. ca Listagem 3.5: (sigusr1.c) Usando um Manipulador de Sinal
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include #include #include #include #include < s i g n a l . h> <s t d i o . h> < s t r i n g . h> <s y s / t y p e s . h> <u n i s t d . h> sigusr1 count = 0;

sig atomic t

void h a n d l e r ( i n t s i g n a l n u m b e r ) { ++s i g u s r 1 c o u n t ; } i n t main ( ) { struct s i g a c t i o n sa ; memset (& sa , 0 , s i z e o f ( s a ) ) ; s a . s a h a n d l e r = &h a n d l e r ; s i g a c t i o n ( SIGUSR1 , &sa , NULL) ; / Faz / . . . coisas / demoradas e trabalhosas aqui . /

p r i n t f ( SIGUSR1 f o i return 0 ; }

i n c r e m e n t a d a %d v e z e s \n ,

sigusr1 count ) ;

3.3.1

Encerramento de Processos

Normalmente, um processo encerra atravs de um entre dois caminhos. Ou e o programa que est sendo executado chama a funo exit, ou a fuo main a ca ca do programa retorna. Cada processo tem um cdigo de sa o da: um nmero u que o processo retorna a seu processo pai. O cdigo de sa o argumento o da e passado ` funo exit, ou o valor retornado a partir da funo main. a ca ca Um processo pode tambm terminar de forma abrupta, em resposta a um e sinal. Por exemplo, os sinais SIGBUS, SIGSEGV, e SIGFPE mencionados 68

anteriormente fazem com que o processo encerre. Outros sinais so usados a para encerrar um processo explicitamente. O sinal SIGINT enviado a e um processo quando o usurio tenta encerr-lo digitando Ctrl+C em seu a a terminal. O sinal SIGTERM enviado pelo comando kill. A disposio e ca padro em ambos os casos encerrar o processo. Por meio de chamada ` a e a funo abort, um processo envia a si mesmo o sinal SIGABRT, que encerra o ca processo e produz um arquivo core. O mais poderoso sinal para encerrar um processo SIGKILL, que encerra um processo imediatamente e no pode ser e a bloqueado ou manuseado por um programa. Qualquer desses sinais pode ser enviado usando o comando kill por meio da especicao de um sinalizador extra de linha de comando; por exemplo, ca para encerrar um processo perturbador por meio do envio de a esse processo de um SIGKILL, use o seguinte comando, onde pid o nmero de identie u cao do seu processo perturbador: ca % kill -KILL pid Para enviar um sinal a partir de um programa, use a funo kill. O ca primeiro parmetro o ID do processo alvo. O segundo parmetro o nmero a e a e u do sinal; use SIGTERM para simular o comportamento padro do comando a kill. Por exemplo, sendo child pid o ID de processo do processo lho, voc e pode usar a funo kill para encerrar um processo lho a partir do processo ca pai por meio de um chamado ` funo kill como o seguinte: a ca kill (child_pid, SIGTERM); Inclua cabealhos <sys/types.h> e <signal.h> caso voc resolva usar a c e funo kill. ca Por conveno, o cdigo de sa usado para indicar se o programa foi ca o da e executado corretamente. Um cdigo de sa com valor zero indica execuo o da ca correta, enquanto um cdigo de sa no nulo indica que um erro ocorreu. o da a No caso de ocorrncia de erro, o valor particular retornado pode fornecer e alguma indicao da natureza do erro. E uma boa idia apegar-se a essa ca e conveno em seus programas pelo fato de outros componentes do sistema ca GNU/Linux assumirem esse comportamento. Por exemplo, programas de shells assumem essa conveno quando voc conecta multiplos programas ca e com os operadores && (sinal lgico e) e || (sinal lgico para ou). o o Portanto, voc deve explicitamente retornar zero a partir de sua funo main, e ca a menos que um erro acontea. c Com a maioria dos shells, poss obter o cdigo de sa da maioria dos e vel o da programas para o mais recentemente programa executado usando a varivel a 69

especial $?. Segue um exemplo no qual o comando ls chamado duas vezes e e seu cdigo de sa mostrado aps cada chamada. no primeiro caso, o da e o o comando ls executa corretamente e retorna o cdigo de sa zero. No o da segundo caso, ls encontra um erro (pelo fato de o nomedearquivo especicado na linha de comando no existir) e dessa forma retorna um cdigo de sa a o da no nulo. a
% ls / bin coda etc lib misc nfs proc sbin usr boot dev home lost+found mnt opt root tmp var % echo $? 0 % ls nomedearquivo ls: impossivel acessar nomedearquivo: Arquivo ou diretorio nao encontrado % echo $? 1

Note que apesar de o tipo de dado do parmetro da funo exit ser int a ca e a funo main retornar um tipo de dado int, GNU/Linux no preserva ca a os 32 bits completos do cdigo de retorno. De fato, voc deve usar cdigos o e o de sa somente entre zero e 127. Cdigos de sa acima de 128 possuem da o da um signicado especial quando um processo for encerrado por meio de um sinal, seus cdigos de sa so 128 mais o nmero do sinal. o da a u

3.3.2

Esperando pelo Encerramento de um Processo

Se voc tiver digitado e executado o exemplo de fork e exec na Listagem e 3.4, voc pode ter notado que a sa fornecida pelo programa ls muitas e da vezes aparece aps o programa principal ter sido completado. Isso ocorre o pelo fato de o processo lho, no qual ls estava sendo executado, agendado e independentemente do processo pai. Pelo fato de GNU/Linux ser um sistema operacional multi-tarefa, ambos os processos parecem ser executados simultneamente, e voc no pode prever se o programa ls ir ter uma chance a e a a de ser executado antes ou depois de o seu processo pai ser executado. Em algumas situaes, apesar disso, desejvel que o processo pai espere co e a at que um ou mais prodessos lhos se completem. Isso pode ser realizado e com a fam wait de chamadas de sistema. Essas funes permitem a voc lia co e esperar que um processo termine sua execuo, e habilite o processo pai ca recuperar informao sobre o encerramento de seu processo lho. Existem ca quatro diferentes chamadas de sistema na fam wait; voc pode escolher lia e pegar pouca ou muita informao sobre o processo encerrado, e voc pode ca e escolher se preocupar acerca de qual processo lho encerrou.

3.3.3

As Chamadas de Sistema da Fam wait lia

A funo mais simples da fam chamada apenas wait. Essa funo bloca lia e ca queia o processo que est fazendo a chamada at que um de seus processos a e 70

lhos encerre (ou ocorra um erro). A funo wait retorna um cdigo que ca o reete a situao atual por meio de um argumento apontador inteiro, do ca qual voc pode extrair informao sobre como o porcesso lho terminou. Por e ca exemplo, a macro WEXITSTATUS extrai o cdigo de sa do processo lho. o da Voc pode usar a macro WIFEXITED para determinar a partir da situao e ca de sa de um processo lho se o referido processo terminou normalmente da (por meio da funo exit ou retornando a partir da funo main) ou foi enca ca cerrado por meio de um sinal que no pode ser manipulado. Nesse ultimo a caso, use a macro WTERMSIG para extrair a partir de sua situao de sa ca da o nmero do sinal atravs do qual o processo em questo foi encerrado. Aqui u e a est a funo main de um exemplo com fork e com exec novamente. Dessa a ca vez, o processo pai chama wait para esperar at que o processo lho, no qual e o comando ls est sendo executado, termine. a
i n t main ( ) { int c h i l d s t a t u s ; / The a r g u m e n t l i s t t o p a s s t o t h e l s command . / char a r g l i s t [ ] = { ls , / a r g v [ 0 ] , t h e name o f t h e p r o g r a m . / l , / , NULL / The a r g u m e n t l i s t must end w i t h a NULL . }; / Spawn a c h i l d p r o c e s s r u n n i n g t h e l s command . r e t u r n e d c h i l d p r o c e s s ID . / spawn ( l s , a r g l i s t ) ;

Ignore

the

/ Wait f o r t h e c h i l d p r o c e s s t o c o m p l e t e . / w a i t (& c h i l d s t a t u s ) ; i f (WIFEXITED ( c h i l d s t a t u s ) ) p r i n t f ( the c h i l d p r o c e s s e x i t e d normally , with e x i t WEXITSTATUS ( c h i l d s t a t u s ) ) ; else p r i n t f ( t h e c h i l d p r o c e s s e x i t e d a b n o r m a l l y \n ) ; return 0 ; }

c o d e %d\n ,

Muitas chamadas de sistema similares esto dispon a veis em GNU/Linux, que so mais ex a veis ou fornecem mais informao sobre a sa de um ca da processo lho. A funo waitpid pode ser usada para esperar pela sa ca da de um processo lho espec co em lugar de esperar pelo trmino de algum e processo no espec a co. A funo wait3 retorna estat ca sticas de uso de CPU sobre o processo lho que est encerrando, e a funo wait4 permite a voc a ca e especicar opes adicionais sobre quais processos aguardar. co

3.3.4

Processos do Tipo Zumbi

Se um processo lho termina enquanto seu pai est chamando uma funo a ca wait, o processo lho desaparece e sua situao de encerramento informada ca e a seu processo pai por meio da chamada wait. Mas o que acontece quando um processo lho termina e o processo pai no est chamando a funo wait? a a ca 71

O processo lho simplesmente desaparece? No, porque a informao sobre a ca seu encerramento - informao tal como se ele terminou normalmente ou no, ca a e se tiver terminado normalmente, o que sua situao de sa mostra agora ca da - pode ser perdida. Quando um processo lho termina e o processo pai no a est chamando a funo wait, ele torna-se um processo zumbi. a ca Um processo zumbi um processo que tenha terminado mas no tenha e a da responsabilidade do processo pai limpar o sistema sido limpo ainda. E de sua criana zumbi. As funes wait fazem isso, tambm, de forma que c co e no seja necessrio rastrear se seu processo lho est ainda executando antes a a a de esperar por ele. Suponhamos, por exemplo, que um programa faa um c fork criando um processo lho, execute alguma outra computao, e ento ca a chame a funo wait. Se o processo lho no tiver terminado nesse ponto, o ca a processo pai ir bloquear na chamada a wait at que o processo lho encerre. a e Se o processo lho encerrar antes que o processo pai chame wait, o processo lho torna-se um zumbi. Quando o processo pai chama wait, a situao atual ca de encerramento do lho zumbi extra e da, o processo lho apagado, e a e chamada a wait retorna imediatamente. O que acontece se o processo pai no limpa seus lhos? Eles permanecem a soltos no sistemas, como processos zumbis. O programa na Listagem 3.6 cria um processo lho atravs de fork, que se encerra imediatamente e ento o e a mesmo programa que criou o processo lho vai cochilar por um minuto, sem mesmo limpar o processo lho. Listagem 3.6: (zombie.c) Fazendo um Processo Zumbi
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include < s t d l i b . h> #include <s y s / t y p e s . h> #include <u n i s t d . h> i n t main ( ) { pid t child pid ; / C r i a um p r o c e s s o f i l h o . / child pid = fork () ; i f ( c h i l d p i d > 0) { / E s s e e o p r o c e s s o p a i . Durma p o r um m i n u t o . sleep (60) ; } else { / E s s e e o p r o c e s s o f i l h o . Sai imediatamente . exit (0) ; } return 0 ; }

Tente compilar esse arquivo em um executvel chamado fazer-zumbi. a Rode esse executvel, e enquanto ele ainda estiver sendo executado, liste a os processos no sistema usando o seguinte comando em outra janela: % ps -e -o pid,ppid,stat,cmd 72

O comando acima lista o ID de processo, ID do processo pai, situao ca atual do processo, e linha de comando do processo. Observe que, adicionalmente ao processo pai do processo fazer-zumbi, existe outro processo fazerzumbi listado. Esse o processo lho; note que seu ID de processo pai est ao e a lado do ID de processo do processo fazer-zumbi principal. O processo lho e marcado como <defunct>, e seu cdigo de situao atual Z, de zumbi.6 o ca e O que acontece quando o programa principal fazer-zumbi termina quando o processo pai sai, sem ter chamado a funo wait? Fica o processo zumbi ca continua vagando por a No tente executar o comando ps novamente, e ? a notar que ambos os processos pai e lho fazer-zumbi se foram. Quando um programa sai, seus lhos so herdados por um processo especial, o programa a init, o qual sempre executa com o ID de processo como sendo 1 ( o primeiro e processo iniciado quando GNU/Linux passa pelo processo de inicializao). ca O processo init automaticamente limpa qualquer processo lho zumbi que ele herda.

3.3.5

Limpando Filhos de Forma No Sincronizada a

Caso voc esteja usando um processo lho simplesmente para executar outro e programa, funciona de forma satisfatria chamar a funo wait imediatao ca mente no processo pai, que ir bloquear at que o processo lho seja complea e tado. Mas muitas vezes, voc ir desejar que o processo pai continue sendo e a executado, como um ou mais processos lhos executando de forma sincronizada. Como pode voc garantir que limpou processos lhos que j tenham e a completado sua tarefa de forma que voc no esquea por a pelo sistema e a c processo zumbis, os quais consomem recursos de sistema, com informaes co falsas por a ? Uma abordagem pode ser a chamada pelo processo pai das funes wait3 co ou wait4 periodicamente, para limpar lhos zumbis. Chamando a funo ca wait com esse objetivo no funciona bem pelo fato de que, se nenhum proa cesso lho terminar, a chamada a wait ir bloquear o processo pai at que a e algum processo lho encerre. Todavia, as funes wait3 e wait4 recebem co um parmetro sinalizador adicional, para o qual voc pode passar o valor a e sinalizador WNOHANG. Com esse sinalizador, a funo chamada executa ca em modo no bloqueador de processo pai ir limpar um processo lho que a a terminou se existir algum, ou simplesmente retornar se no houver nenhum a
6 Nota do tradutor: em um slackware 12.2 a sa da, mostrando somente as duas linhas que interessam, foi a seguinte: PID PPID STAT CMD 9152 9133 S+ ./fazer-zumbi 9153 9152 Z+ [fazer-zumbi] <defunct>

73

processo lho executando. O valor de retorno da chamada o ID do proe cesso do lho encerrado, ou zero no caso de no haver nenhum processo sendo a executado. Uma soluo mais elegante noticar o processo pai quando um lho conca e clui seu trabalho. Existem muitas formas de fazer isso usando os mtodos e discutidos no Cap tulo 5, Comunicao Entre Processosmas afortunadaca mente GNU/Linux faz isso para voc, usando sinais. Quando um processo e lho cumpre sua tarefa, GNU/Linux envia ao processo pai o sinal SIGCHLD. A disposio padro desse sinal no fazer nada, coisa que talvez voc possa ca a e a e no ter notado antes. a Dessa forma, um caminho fcil para limpar processos lhos pelo maa e nuseio de SIGCHLD. Certamente, durante a limpeza de processos lhos, e importante guardar sua situao atual de encerramento se essa informao ca ca for necessria, pelo fato de uma vez que o processo for limpo usando wait, a a sua informao de encerramento no mais estar dispon ca a a vel. A Listagem 3.7 mostra um exemplo de programa que usa uma funo manipuladora de ca SIGCHLD para limpar seus processos lhos. 7 Listagem 3.7: (sigchld.c) Limpando Processos lhos pelo manuseio de SIGCHLD
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include #include #include #include < s i g n a l . h> < s t r i n g . h> <s y s / t y p e s . h> <s y s / w a i t . h> child exit status ;

sig atomic t

void c l e a n u p c h i l d p r o c e s s ( i n t s i g n a l n u m b e r ) { / Limpa o p r o c e s s o f i l h o . / int s t a t u s ; w a i t (& s t a t u s ) ; / Armazena s u a s i t u a c a o d e s a i d a em uma v a r i a v e l child exit status = status ; } i n t main ( ) { / M a n i p u l a SIGCHLD p e l a chamada a struct s i g a c t i o n s i g c h l d a c t i o n ; memset (& s i g c h l d a c t i o n , 0 , s i z e o f s i g c h l d a c t i o n . s a h a n d l e r = &c l e a n s i g a c t i o n (SIGCHLD , &s i g c h l d a c t i o n / Agora f a z / . . . / return 0 ; } coisas , incluindo fork

global .

clean up child process . ( sigchld action ) ) ; up child process ; , NULL) ; s o b r e um p r o c e s s o filho .

O cdigo em clean up child process pode no trabalhar corretamente se houver mais o a que um processo lho. O kernel do GNU/Linux ir somente chamar o manipulador de sinal a uma vez se dois ou mais processos lhos encerrarem quase ao mesmo tempo. Portanto, caso haja mais de um processo lho, o manipulador de sinal deve repetidamente chamar por waitpid (ou uma das outras funes relacionada) com a opo WNOHANG at que co ca e waitpid retorne.

74

Note como o manipulador de sinal armazena a situao de sa do proca da cesso lho em uma varivel global, da qual o programa principal pode acessa a la. Pelo fato de a varivel se atribu em um manipulador de sinal, ela (a a da varivel global) do tipo sig atomic t. a e

75

76

Cap tulo 4 Linhas de Execuo ca


LINHAS DE EXECUCAO1 ,COMO PROCESSOS, SAO UM MECANISMO PARA PERMITIR A UM PROGRAMA fazer mais de uma coisa ao mesmo tempo. Da mesma forma que acontece com processos, linhas de execuo paca recem executar concorrentemente; o kernel GNU/Linux agenda-as de forma no sincronizada, interrompendo cada uma dessas linhas de execuo de tema ca pos em tempos para fornecer a outros uma chance para executar. Conceitualmente, uma linha de execuo existe dentro de um processo. ca Linhas de execuo so menores unidades de execuo que processos. Quando ca a ca voc chama um programa, GNU/Linux cria um novo processo e esse processo e cria uma linha de execuo simples, que executa o programa sequencialmente. ca Essa linha de execuo pode criar linhas de execuo adicionais; todas esca ca sas linhas de execuo executam o mesmo programa no mesmo processo, ca mas cada linha de execuo pode estar executando uma parte diferente do ca programa em qualquer tempo fornecido. Ns vimos como um programa pode atravs de um fork criar um processo o e lho. O processo lho inicialmente executa seu programa pai, na memria o virtual do processo pai, com descritores de arquivo do processo pai e assim por diante copiado tudo do processo pai. O processo lho pode modicar sua memria fechar descritores de arquivo, e coisas parecidas sem afetar seu o processo pai, e vice-versa.2 Quando um programa no processo lho cria outra linha de execuo, apesar disso, nada copiado. A linha de execuo criadora ca e ca e a linha de execuo criatura compartilham o mesmo espao de memria, os ca c o mesmos descritores de arquivo, e outros recursos de sistema como o original. Se uma linha de execuo muda o valor de uma varivel, por exemplo, a outra ca a linha de execuo sequencialmente ir ver o valor modicado. Similarmente, ca a
1 2

Nota do tradutor: Threads. Nota do tradutor: o processo pai pode fazer vrios procedimentos sem afetar o lho. a

77

se uma linha de execuo fecha um descritor de arquivo, outra linha de ca execuo pode no ler aquele descritor ou no escrever para aquele descritor. ca a a Pelo fato de um processo e todas as suas linhas de execuo poderem executar ca somente um programa de cada vez, se alguma linha de execuo dentro de um ca 3 processo chama uma das funes exec , todas as outras linhas de execuo co ca so nalizadas (o novo programa pode, certamente, criar novas linhas de a execuo). ca GNU/Linux implementa o padro POSIX para Interface de Programao a ca 4 de Aplicao (API) de linha de execuo (conhecido como pthreads) . Todas ca ca funes de linha de execuo e tipos de dado so declarados no arquivo co ca a de cabealho <pthread.h>. As funes POSIX de linha de execuo no c co ca a esto inclu a das na biblioteca C GNU padro. Ao invs disso, elas esto na a e a libpthread, ento voc deve adicionar -lpthread ` linha de comando quando a e a voc zer a linkagem de seu programa. e

4.1

Criao de Linhas de Execuo ca ca

Cada linha de execuo identicada por um ID (identicador) de linha de ca e execuo. Quando for se referir a IDs de linha de execuo em programas ca ca feitos em C ou em C++, use o tipo pthread t. Sobre criao, cada linha de execuo executa uma funo de linha de ca ca ca execuo. Essa funo de linha de execuo apenas uma funo comum e ca ca ca e ca contm o cdigo que a linha de execuo deve executar. Quando a funo e o ca ca retorna, a linha de execuo encerra. Em ambiente GNU/Linux, funes de ca co linha de execuo recebem um parmetro unico, do tipo void*, e possuem o ca a tipo de dado retornado tambm void*. O parmetro o argumento da linha e a e de execuo: GNU/Linux passa o valor conforme a linha de execuo sem ca ca olhar para o contedo. Seu programa pode usar esse parmetro para passar u a dados para uma nova linha de execuo. Reciprocamente, seu programa pode ca usar o valor de retorno para passar dados a partir de uma linha de execuo ca existente de volta ao criador da linha de execuo. ca ca e A funo pthread create cria uma nova linha de execuo. Voc alimenta ca a pthread create com o seguinte:
Nota do tradutor: relembrando que a fam de funes exec substituem o programa lia co que est sendo executado por outro. a 4 Nota do tradutor: p-threads ou POSIX-threads ou ainda threads POSIX.
3

78

1. Um apontador para uma varivel do tipo pthread t, na qual o ID a de linha de execuo da nova linha de execuo est armazenado. ca ca a 2. Um apontador para um objeto de atributo de linha de execuo. ca Esse apontador controla detalhes de como a linha de execuo inca terage com o restante do programa. Se voc passa um dado NULL e como atributo de linha de execuo, uma linha de execuo ir ser ca ca a criada com os atributos padronizados de linha de execuo. Atribuca tos de linha de execuo so discutidos na Seo 4.1.5, Atributos ca a ca de Linhas de Execuo. ca 3. Um apontador para a funo de linha de execuo. Esse apontador ca ca um apontador de funo comum, do seguinte tipo: e ca void* (*) (void*) 4. Um valor de argumento de linha de execuo do tipo void*. Todo ca o resto que voc enviar simplesmente passado como argumento e e para a funo de linha de execuo quando a linha de execuo ca ca ca inicia sua execuo. ca

Uma chamada a pthread create retorna imediatamente, e a linha de execuca o original continua executando as instrues imediatamente aps a chaco o mada. Enquanto isso, a nova linha de execuo inicia-se executando a funo ca ca de linha de execuo. GNU/Linux agenda ambas as linhas de execuo de ca ca forma no sincronizada, e seu programa continua independentemente da ora dem relativa na qual instrues so executadas em duas linhas de execuo. co a ca O programa na Listagem 4.1 cria uma linha de execuo que imprime xs ca continuamente para a sa de erro. Aps chamar pthread create, a linha de da o execuo principal imprime os continuamente para a sa de erro. ca da 79

Listagem 4.1: ( thread-create.c) Criando uma Linha de Execuo ca


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <p t h r e a d . h> #include <s t d i o . h> / Imprime x s p a r a stderr . O p a r a m e t r o nao e u s a d o . Nao r e t o r n a . /

void p r i n t x s ( void unused ) { while ( 1 ) fputc ( x , stderr ) ; return NULL ; } / O p r o g r a m a principal . /

i n t main ( ) { pthread t thread id ; / C r i a uma n o v a l i n h a d e e x e c u c a o . A nova l i n h a de e x e c u c a o funcao print xs . / p t h r e a d c r e a t e (& t h r e a d i d , NULL, &p r i n t x s , NULL) ; / Imprime o s c o n t i n u a m e n t e p a r a s t d e r r . / while ( 1 ) fputc ( o , stderr ) ; return 0 ; }

ira

executar

Compile e faa a linkagem desse programa usando o seguinte cdigo: c o \% cc -o thread-create thread-create.c -lpthread Tente execut-lo para ver o que ocorre. Preste atenao ao padro ima c a previs de xs e os devido ` alternncia de agendamentos do Linux com vel a a relao `s duas linhas de execuo. ca a ca Sob circunstncias normais, uma linha de execuo encerra-se por meio a ca de uma entre duas formas. Uma forma, como ilustrado previamente, por e meio do retorno da funo de linha de execuo. O valor de retorno da ca ca funo de linha de execuo usado para ser o valor de retorno da linha de ca ca e execuo. Alternativamente, uma linha de execuo pode sair explicitamente ca ca por meio de uma chamada a pthread exit. Essa funo pode ser chamada de ca dentro da funo de linha de execuo ou a partir de alguma outra funo ca ca ca chamada diretamente ou indiretamente pela funo de linha de execuo. O ca ca e ca argumento para pthread exit o valor de retorno da linha de execuo.

4.1.1

Enviando Dados a uma Linha de Execuo ca

O argumento de linha de execuo fornece um mtodo conveniente de enviar ca e dados a linhas de execuo. Pelo fato de o tipo de dado do argumento ca ser void*, apesar disso, voc no pode enviar grande quantidade de dados e a diretamente atravs do argumento. Ao invs disso, use o argumento de linha e e de execuo para enviar um apontador para alguma estrutura ou vetor de ca dados. Uma tcnica comumente usada denir uma estrutura para cada e e 80

funo de linha de execuo, a qual contm os parmetros esperados pela ca ca e a funo de linha de execuo. ca ca Usando o argumento de linha de execuo, torna-se fcil reutilizar a ca a mesma funo de linha de execuo para muitas linhas de execuo. Toca ca ca das essas linhas de execuo executam o mesmo cdigo, mas sobre diferentes ca o dados. O programa na Listagem 4.2 similar ao exemplo anterior. O referido proe grama cria duas novas linhas de execuo, um para imprimir xs e o outro para ca imprimir os. Ao invs de imprimir innitamente, apesar disso, cada linha e de execuo imprime um nmero xo de caracteres e ento encerra-se retorca u a nando ` funo de linha de execuo. A mesma funo de linha de execuo, a ca ca ca ca char print, usada em ambas as linhas de execuo, mas cada linha de e ca execuo congurada diferentemente usando a estrutura char print parms. ca e Listagem 4.2: ( thread-create2) Cria Duas Linhas de Execuo ca
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #include <p t h r e a d . h> #include <s t d i o . h> / P a r a m e t r o s a print function . /

struct c h a r p r i n t p a r m s { / O c a r a c t e r e a i m p r i m i r . / char c h a r a c t e r ; / O numero d e v e z e s a i m p r i m i r o c a r a c t e r e int count ; }; / Imprima um c e r t o numero d e c a r a c t e r e s o q u a l e um a p o n t a d o r p a r a um s t r u c t

acima .

p a r a s t d e r r , como f o r n e c i d o c h a r p r i n t p a r m s . /

p o r PARAMETERS,

void c h a r p r i n t ( void p a r a m e t e r s ) { / C o n v e r t e o c o o k i e p o i n t e r p a r a o t i p o c o r r e t o . / struct c h a r p r i n t p a r m s p = ( struct c h a r p r i n t p a r m s ) parameters ; int i ; f o r ( i = 0 ; i < p o u n t ; ++i ) >c f p u t c ( p h a r a c t e r , s t d e r r ) ; >c return NULL ; } / O p r o g r a m a principal . /

i n t main ( ) { pthread t thread1 id ; pthread t thread2 id ; struct c h a r p r i n t p a r m s struct c h a r p r i n t p a r m s / C r i a thread1 thread1 pthread / C r i a thread2 thread2 pthread

thread1 args ; thread2 args ;

uma n o v a l i n h a d e e x e c u c a o p a r a i m p r i m i r 3 0 , 0 0 0 x s . / args . character = x ; a r g s . count = 30000; c r e a t e (& t h r e a d 1 i d , NULL, &c h a r p r i n t , &t h r e a d 1 a r g s ) ; uma n o v a l i n h a d e e x e c u c a o p a r a i m p r i m i r 2 0 , 0 0 0 o s . / args . character = o ; a r g s . count = 20000; c r e a t e (& t h r e a d 2 i d , NULL, &c h a r p r i n t , &t h r e a d 2 a r g s ) ;

return 0 ; }

Mas Espere! O programa na Listagem 4.2 tem um erro srio nele. A lie 81

nha de execuo principal (que executa a funo main) cria as estruturas do ca ca parmetro de linha de execuo (thread1 args e thread2 args) como variveis a ca a locais, e ento passa apontadores para essas estruturas destinados `s linhas a a de execuo que cria. O que fazer para prevenir o Linux do agendamento das ca trs linhas de execuo de tal forma que a linha de execuo principal tere ca ca mine antes de qualquer das duas outras linhas de execuo terem terminado? ca Nada! Mas caso isso ocorra, a memria contendo as estruturas do parmetro o a da linha de execuo ter sido desalocada enquanto as outras duas linhas de ca a execuo estiverem ainda acessando-a. ca

4.1.2

Vinculando Linhas de Execuo ca

Uma soluo forar main a esperar at que as outras duas linhas de execuo ca e c e ca tenham terminado. O que precisamos de uma funo similar ` funo wait e ca a ca que espere pelo m de uma linha de execuo ao invs de esperar pelo m de ca e um processo. A funo desejada pthread join, que recebe dois argumentos: ca e o ID de linha de execuo da linha de execuo pelo qual vai esperar, e um ca ca apontador para uma var avel do tipo void* que ir receber o valor de retorno a da linha de execuo terminada. Se voc no quiser preocupar-se com o valor ca e a de retorno, informe NULL como o segundo argumento.

A Listagem 4.3 mostra a funo main corrigida para o exemplo de falha ca na listagem 4.2. Nessa verso, main no encerra at que ambas as linhas de a a e execuo imprimindo xs e os tenham sido completadas, ento elas no mais ca a a utilizam as estruturas de argumento. 82

Listagem 4.3: Funo main revisada para thread-create2.c ca


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #include <p t h r e a d . h> #include <s t d i o . h> / P a r a m e t r o s p a r a print function . /

struct c h a r p r i n t p a r m s { / O c a r a c t e r e a i m p r i m i r . / char c h a r a c t e r ; / O numero d e v e z e s a i m p r i m i r . int count ; };

/ M o s t r a um numero d e c a r a c t e r e s a s t d e r r , como f o r n e c i d o o q u a l e um a p o n t a d o r p a r a um s t r u c t c h a r p r i n t p a r m s .

p o r PARAMETERS, /

void c h a r p r i n t ( void p a r a m e t e r s ) { / C o n v e r t e o p o n t e i r o c o o k i e p a r a o t i p o c e r t o . / struct c h a r p r i n t p a r m s p = ( struct c h a r p r i n t p a r m s ) parameters ; int i ; f o r ( i = 0 ; i < p o u n t ; ++i ) >c f p u t c ( p h a r a c t e r , s t d e r r ) ; >c return NULL ; } / O p r o g r a m a principal . /

i n t main ( ) { pthread t thread1 id ; pthread t thread2 id ; struct c h a r p r i n t p a r m s struct c h a r p r i n t p a r m s / C r i a thread1 thread1 pthread / C r i a thread2 thread2 pthread

thread1 args ; thread2 args ;

uma n o v a l i n h a d e e x e c u c a o p a r a m o s t r a r 3 0 0 0 0 x s . / args . character = x ; a r g s . count = 30000; c r e a t e (& t h r e a d 1 i d , NULL, &c h a r p r i n t , &t h r e a d 1 a r g s ) ; uma n o v a l i n h a d e e x e c u c a o p a r a m o s t r a r 2 0 0 0 0 o s . / args . character = o ; a r g s . count = 20000; c r e a t e (& t h r e a d 2 i d , NULL, &c h a r p r i n t , &t h r e a d 2 a r g s ) ;

/ G a r a n t e q u e a p r i m e i r a l i n h a d e e x e c u c a o t e n h a t e r m i n a d o . / p t h r e a d j o i n ( t h r e a d 1 i d , NULL) ; / G a r a n t e q u e a s e g u n d a l i n h a d e e x e c u c a o t e n h a t e r m i n a d o . / p t h r e a d j o i n ( t h r e a d 2 i d , NULL) ; / Agora podemos s e g u r a m e n t e return 0 ; } retornar . /

A moral da estria: garanta que qualquer dado que seja passado a uma o linha de execuo por referncia seja mantido na memria, mesmo que por ca e o uma linha de execuo diferente, at que voc tenha certeza que a linha de ca e e execuo tenha terminado com esse dado. Essa garantia verdadeira em ca e ambos os casos tanto para variveis locais, que so removidas quando as a a linhas de execuo saem do ambiente no qual foram denidas, quanto para ca variveis alocadas em grupo/pilha, que voc libera atravs de um chamado a e e a free (ou usando delete em C++). 83

4.1.3

Valores de Retorno de Linhas de Execuo ca

Se o segundo argumento que voc passar a pthread join for no nulo, o valor e a de retorno da linha de execuo ser colocado na localizao apontada por ca a ca aquele argumento. O valor de retorno da linha de execuo,da mesma forma ca que o argumento de linha de execuo, do tipo void*. Se voc desejar devolca e e ver um dado do tipo int simples ou outro nmero pequeno, voc pode fazer u e isso facilmente convertendo o valor para void* e ento convertendo de volta a para o tipo apropriado aps chamar pthread join. 5 O programa na Listagem o 4.4 calcula o ensimo nmero primo em uma linha de execuo isolada. O e u ca valor de retorno dessa linha de execuo isolada o nmero primo desejado. ca e u A linha de execuo principal, enquanto isso, est livre para executar outro ca a cdigo. Note que o algor o tmo de divises sucessivas usado em compute prime o completamente ineciente; consulte um livro sobre algor e tmos numricos se e voc precisar calcular muitos primos em seus programas. e

Note que esse procedimento perde a portabilidade, e cabe a voc garantir que seu e valor pode ser convertido seguramente para void* e ser convertido de volta sem perder bits.

84

Listagem 4.4: ( primes.c) Calcula Nmeros Primos em uma Linha de u Execuo ca


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <p t h r e a d . h> #include <s t d i o . h> / C a l c u l a s u c e s s i v o s numeros p r i m o s ( m u i t o i n e f i c i e n t e m e n t e ) . e n e s i m o numero primo , o n d e N e o v a l o r a p o n t a d o p o r ARG. void c o m p u t e p r i m e ( void a r g ) { int candidate = 2 ; int n = ( ( int ) arg ) ; while ( 1 ) { int f a c t o r ; int i s p r i m e = 1 ; / T e s t e d e p r i m a l i d a d e p o r d i v i s o e s s u c e s s i v a s . / f o r ( f a c t o r = 2 ; f a c t o r < c a n d i d a t e ; ++f a c t o r ) i f ( c a n d i d a t e % f a c t o r == 0 ) { is prime = 0; break ; } / E e s t e o numero p r i m o q u e e s t a m o s p r o c u r a n d o ? / if ( is prime ) { i f (n == 0 ) / R e t o r n a o numero p r i m o d e s e j a d o como v a l o r d e r e t o r n o da . / return ( void ) c a n d i d a t e ; } ++c a n d i d a t e ; Retorna o /

linha

de e x e c u c a o

26 27 28 29 } 30 return NULL ; 31 } 32 33 i n t main ( ) 34 { 35 pthread t thread ; 36 int which prime = 5000; 37 int prime ; 38 39 / I n i c i a a l i n h a d e e x e c u c a o d e c a l c u l o , acima do 5000 e s i m o numero p r i m o . / 40 p t h r e a d c r e a t e (& t h r e a d , NULL, &c ompute prime , &w h i c h p r i m e ) ; 41 / Faz a l g u m o u t r o t r a b a l h o a q u i . . . / 42 / E s p e r a q u e a l i n h a d e e x e c u c a o d e numero p r i m o s e c o m p l e t e , e p e g a o r e s u l t a d o . / 43 p t h r e a d j o i n ( t h r e a d , ( void ) &p r i m e ) ; 44 / M o s t r a o m a i o r p r i m o c a l c u l a d o . / 45 p r i n t f ( O %de simo numero primo e %d . \ n , w h i c h p r i m e , p r i m e ) ; 46 return 0 ; 47 }

4.1.4

Mais sobre IDs de Linhas de Execuo ca

Ocasionalmente, util para uma sequncia de cdigo determinar qual linha e e o de execuo a est executando. A funo pthread self retorna o ID da linha ca a ca de execuo que a chamou. Esse ID de linha de execuo pode ser comparado ca ca com outro ID de linha de execuo usando a funo pthread equal. ca ca Essas funes podem ser uteis para determinar se um ID de linha de co execuo em particular corresponde ao ID da linha de execuo atual. Por ca ca exemplo, um erro para uma linha de execuo chamar pthread join para e ca vincular-se a si mesma. (Nesse caso, pthread join ir retornar o cdigo de a o erro EDEADLK.) Para vericar isso antecipadamente, voc pode usar um e cdigo como o que segue: o
if ( ! pthread equal ( pthread self () , p t h r e a d j o i n ( o t h e r t h r e a d , NULL ) ; other thread ))

85

4.1.5

Atributos de Linha de Execuo ca

Atributos de linha de execuo fornecem um mecanismo para ajuste preciso ca do comportamento de linhas de execuo individuais. Lembrando que pthre ca ad create aceita um argumento que um apontador para um objeto de atrie buto de linha de execuo. Se voc informar um apontador nulo, os atributos ca e de ancadeamento padronizados so usados para congurar a nova linha de a execuo. Todavia, voc pode criar e personalizar um objeto de atributo de ca e linha de execuo para especicar outros valores para os atributos. 6 ca Para especicar atributos personalizados de linhas de execuo, voc deve ca e seguir esses passos: 1. Crie um objeto pthread attr t. O caminho mais fcil de fazer isso a e simplesmente declarar uma varivel automtica desse tipo. a a 2. Chame pthread attr init, informando um apontador para esse objeto. Esse procedimento inicializa os atributos com seus valores padronizados. 3. Modique o objeto de atributo de forma que contenha os valores de atributo desejados. 4. Informe um apontador para o objeto de atributo ao chamar pthread create. 5. Chame pthread attr destroy para liberar o objeto de atributo. A varivel pthread attr t propriamente dita no desalocada. A a a e varivel pthread attr t pode ser reinicializada com pthread attr init. a Um objeto de atributo de linha de execuo simples pode ser usado para ca muitas linhas de execuo. No necessrio manter o objeto de atributo de ca a e a linha de execuo por ai aps as linhas de execuo terem sido criadas. ca o ca Para a maioria das linha de execuo de programao para criao de ca ca ca aplicativos em GNU/Linux, somente um atributo de linha de execuo ca e tipicamente de interesse (os outros atributos dispon veis so primariamente a para especicidades de programao em tempo real). Esse atributo o estado ca e de desvinculao da linha de execuo. Uma linha de execuo pode ser ca ca ca criada como uma linha de execuo vinculvel (o padro) ou como uma ca a a linha de execuo desvinculada. Uma linha de execuo vinculvel, como um ca ca a processo, no tem seus recursos de sistema liberados automaticamente pelo a GNU/Linux quando termina sua execuo. Ao invs disso, o estado de sa ca e da
Nota do tradutor: para mais detalhes sobre threads/linhas de execuo veja http: ca //www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html.
6

86

da linha de execuo vagueia sem destino no sistema (semelhantemente a um ca processo zumbi) at que outra linha de execuo chame pthread join para e ca obter seu valor de retorno. Somente ento so seus recursos liberados. Uma a a Linha de execuo desvinculada, ao cantrrio, tem seus recursos de sistema ca a automaticamete liberados quando termina sua execuo. Pelo fato de uma ca linha de execuo desvinculada ter seus recursos liberados automaticamente, ca outra linha de execuo pode no conseguir informaes sobre sua concluso ca a co a atravs do uso de pthread join ou obter seu valor de retorno. e Para atribuir o estado desvinculado a um objeto de atributo de linha de execuo, use a funo pthread attr setdetachstate. O primeiro argumento ca ca e um apontador para o objeto de atributo de linha de execuo, e o segundo o ca e estado desvinculado desejado. Pelo fato de o estado vinculvel ser o padro, a a e necessrio chamar a funo pthread attr setdetachstate somente para criar lia ca nhas de execuo desvinculadas; informe PTHREAD CREATE DETACHED ca como o segundo argumento. O cdigo na Listagem 4.5 cria uma linha de execuo desvinculada usando o ca o atributo de linha de execuo desvinculada para a linha de execuo. ca ca

Listagem 4.5: (detached.c) Programa Esqueleto Que Cria uma Linha dde Execuo Desvinculada ca
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <p t h r e a d . h> void t h r e a d f u n c t i o n { / F a z e r o t r a b a l h o return NULL ; } i n t main ( ) { pthread attr t attr ; pthread t thread ; pthread pthread pthread pthread a t t r i n i t (& a t t r ) ; a t t r s e t d e t a c h s t a t e (& a t t r , PTHREAD CREATE DETACHED) ; c r e a t e (& t h r e a d , &a t t r , &t h r e a d f u n c t i o n , NULL) ; a t t r d e s t r o y (& a t t r ) ; aqui . . . / linha de e x e c u c a o . / ( void t h r e a d a r g ) aqui . . . /

/ F a z e r o t r a b a l h o / Nao p r e c i s a return 0 ; }

a s s o c i a r a segunda

Mesmo se uma linha de execuo for criada com o estado vinculvel, ele ca a pode ser transformado em uma linha de execuo desvinculada. Para fazer ca isso, chame pthread detach. Uma vez que seja desvinculada, ela no pode se a tornar vinculvel novamente. a 87

4.2

Cancelar Linhas de Execuo ca

Sob circunstncias normais, uma linha de execuo encerra-se quando seu a ca estado de sa normal, ou pelo retorno de seu valor de retorno ou por da e uma chamada ` funo pthread exit. Todavia, poss para uma linha de a ca e vel execuo requisitar que outra linha de execuo termine. Isso chamado ca ca e cancelar uma linha de execuo. ca Para cancelar uma linha de execuo, chame a funo pthread cancel, inca ca formando o ID de linha de execuo da linha de execuo a ser cancelada. ca ca Uma linha de execuo cancelada pode mais tarde ser vinculada; de fato, voc ca e pode vincular uma linha de execuo cancelada para liberar seus recursos, a ca menos que a linha de execuo seja desvinculada (veja a Seo 4.1.5, Atrica ca butos de Linha de Execuo). O valor de retorno de uma linha de execuo ca ca cancelada o valor especial fornecido por PTHREAD CANCELED. e Muitas vezes uma linha de execuo pode ter alguma parte de seu cdigo ca o que deva ser executada em um estilo tudo ou nada. Por exemplo, a linha de execuo pode alocar alguns recursos, us-los, e ento liberar esses mesmos ca a a recursos em seguida. Se a linha de execuo for cancelada no meio do cdigo, ca o pode no ter a oportunidade de liberar os recursos como era esperado, e dessa a forma os recursos iro ser perdidos. Para contar com essa possibilidade, a poss e vel para uma linha de execuo controlar se e quando ela pode ser ca cancelada. Uma linha de execuo pode estar em um dos trs estados abaixo com ca e relao a cancelar linhas de execuo. ca ca A linha de execuo pode ser cancelvel de forma no sincronica a a zada. Isso que dizer que a linha de execuo pode ser cancelada em ca qualquer ponto de sua execuo. ca A linha de execuo pode ser cancelvel sincronizadamente. A lica a nha de execuo pode ser cancelada, mas no em algum ponto ca a determinado de sua execuo. Ou ao contrrio, requisies de canca a co celamento so colocadas em uma regio temporria de armazenaa a a mento, e a linha de execuo cancelada somente quando forem ca e alcanados pontos espec c cos em sua execuo. ca Uma linha de execuo pode ser incancelvel. Tentativas de canca a celar a linha de execuo so silenciosamente ignoradas. ca a Quando criada inicialmente, uma linha de execuo cancelvel sincroca e a nizadamente. 88

4.2.1

Linhas de Execuo Sincronas e Assincronas ca

Uma linha de execuo cancelvel assincronizadamente pode ser cancelado ca a em qualquer ponto de sua execuo. Uma linha de execuo cancelvel sincroca ca a nizadamente, ao contrrio, pode ser cancelado somente em lugares determia nados de sua execuo. Esses lugares so chamados pontos de cancelamento. ca a A linha de execuo ir armazenar uma requisio de cancelamento at que ca a ca e o ponto de cancelamento seguinte seja alcanado. c Para fazer uma linha de execuo assincronizadamente cancelvel, use ca a pthread setcanceltype. A funo pthread setcanceltype afeta linha de execuo ca ca que fez o chamado. O primeiro argumento deve ser PTHREAD CANCEL A SYNCHRONOUS para tornar a linha de execuo assincronizadamente canca celvel, ou PTHREAD CANCEL DEFERRED para retornar a linha de execua ca o ao estado de sincronizadamente cancelvel. O segundo argumento, se no a a for nulo, um apontador para uma varivel que ir receber o tipo de cancee a a lamento anterior para a linha de execuo. A chamada abaixo, por exemplo, ca transforma a linha de execuo que est fazendo a chamada em assincronica a zadamente cancelvel. a
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

O que constitui um ponto de cancelamento, e onde deve ele ser colocado? O caminho mais direto para criar um ponto de cancelamento chamar a e funo pthread testcancel. Essa chamada faz unicamente atender um pedido ca de cancelamento que se encontra pendente em uma linha de execuo sincroca nizadamente cancelvel. Voc deve chamar a funo pthread testcancel perioa e ca dicamente durante computaes longas em uma funo de linha de execuo, co ca ca em pontos onde a linha de execuo pode ser cancelada sem desperdiar ca c quaisquer recursos ou produzir outros efeitos igualmente danosos. Certas outras funes trazem implicitamente pontos de cancelamento co tambm. So elas listadas na pgina de manual da funo pthread cancel e a a ca 7 . Note que outras funes podem usar essas funes internamente e dessa co co forma serem pontos de cancelamento.

4.2.2

Sees Cr co ticas Incancelveis a

Uma linha de execuo pode desabilitar o cancelamento de si mesma comca pletamente com a funo pthread setcancelstate. Da mesma forma que pthca read setcanceltype, a funo pthread setcancelstate afeta a linha de execuo ca ca
Nota do Tradutor:se for usado o comando man pthread cancel e no se encontrar a a a referida pgina de manual instalada no ubuntu 10.10 default mas na Internet existem a pelo menos duas verses de man page para pthread cancel. o
7

89

que zer a chamada. O primeiro argumento PTHREAD CANCEL DISAB e LE para disabilitar a cancelabilidade, ou PTHREAD CANCEL ENABLE para reabilitar a cancelabilidade. O segundo argumento, se no for NULL, a aponta para uma varivel que ir receber o estado de cancelamento anterior. a a A chamada a seguir, por exemplo, desabilita a cancelabilidade da linha de execuo na linha de execuo que zer a referida chamada. ca ca

pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);

Usando a funo pthread setcancelstate habilita voc a implementar sees ca e co cr ticas. Uma seo cr ca tica uma sequncia de cdigo que deve ser executado e e o ou em sua totalidade ou parcialmente; em outras palavras, se uma linha de execuo inicia-se executando uma seo cr ca ca tica, essa linha de execuo deve ca continuar at o nal da seo cr e ca tica sem ser cancelada. Por exemplo, suponhamos que voc est escrevendo uma rotina para um e a programa bancrio que transfere dinheiro de uma conta para outra. Para a fazer isso voc deve adicionar valor ao saldo em uma conta e abater o mesmo e valor do saldo de outra conta. Se a linha de execuo que estiver executando ca sua rotina for cancelada exatamente no pssimo momento entre essas duas e operaes, o programa pode ter um aumento esprio do depsito total cauco u o sado pela falha na concluso da transao. Para previnir essa possibilidade, a ca coloque as duas operaes dentro de uma seo cr co ca tica. Voc pode implementar a transferncia com uma funo tal como a pro e e ca cess transaction, mostrada na Listagem 4.6. Essa funo desabilita o canca celamento da linha de execuo para iniciar uma seo cr ca ca tica antes que a funo modique ou um ou outro balano de conta. ca c 90

Listagem 4.6: (critical-section.c) Protege uma Transao Bancria com ca a uma Seo Cr ca tica
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include <p t h r e a d . h> #include <s t d i o . h> #include < s t r i n g . h> / Um a r r a y d e b a l a n c o s em c o n t a s , indexado p o r numero d e c o n t a . /

float account balances ; / T r a n s f e r e DOLLARS da c o n t a FROM ACCT p a r a a c o n t a TO ACCT . Retorna 0 s e a t r a n s a c a o o b t i v e r s u c e s s o , ou 1 s e o b a l a n c o d e FROM ACCT f o r muito pequeno . / int p r o c e s s t r a n s a c t i o n { int o l d c a n c e l s t a t e ; ( int from acct , int to acct , float dollars )

/ V e r i f i c a o b a l a n c o em FROM ACCT . / i f ( account balances [ from acct ] < d o l l a r s ) return 1 ; / Comeca a s e c a o c r i t i c a . / p t h r e a d s e t c a n c e l s t a t e (PTHREAD CANCEL DISABLE, &o l d c a n c e l s t a t e ) ; / Move o d i n h e i r o . / a c c o u n t b a l a n c e s [ t o a c c t ] += d o l l a r s ; a c c o u n t b a l a n c e s [ f r o m a c c t ] = d o l l a r s ; / Fim da s e c a o c r i t i c a . / p t h r e a d s e t c a n c e l s t a t e ( o l d c a n c e l s t a t e , NULL) ; return 0 ; }

Note que importante restaurar o estado de cancelamento antigo no nal e da seo cr ca tica em lugar de escolher incondicionalmente o estado PTHREA e D CANCEL ENABLE. restaurando o estado antigo ao invs de usar incondicionalmente PTHREAD CANCEL ENABLE habilita voc a chamar e a funo process transaction seguramente de dentro de outra seo cr ca ca tica como no caso mostrado acima, permitindo que o estado de cancelamento seja colocado da mesma forma que se encontrava antes da sua interveno. ca

4.2.3

Quando Cancelar uma Linha de Execuo ca

Em geral, uma boa idia no cancelar linhas de execuo para encerrar a e e a ca execuo de uma linha de execuo, exceto em circunstncias raras. Durante ca ca a operaes normais, a melhor estratgia indicar ` linha de execuo que ela co e e a ca deve encerrar, e ento esperar o trmino da linha de execuo por seu estilo a e ca prprio e ordeiro. Iremos discutir tcnicas para comunicao com linhas de o e ca execuo mais tarde no atual cap ca tulo, e no Cap tulo 5, Comunicao Entre ca Processos. 91

4.3

Area de Dados Espec cos de Linha de Execuo ca

Ao contrrio dos processos, todas as linhas de execuo em um programa a ca simples compartilham o mesmo espao de endereamento. Isso signica que c c se uma linha de execuo modica uma localizao na memria (por exemplo, ca ca o uma varivel global), a mudana vis a c e vel para todas as outras linhas de execuo. Isso permite que multiplas linhas de execuo operem sobre os ca ca mesmos dados sem o uso de mecanismos de comunicao entre processos ca (que so descritos no Cap a tulo 5). Cada linha de execuo tem dua prpria pilha de chamadas, apesar do exca o posto acima. Isso permite a cada linha de execuo executar cdigo diferente ca o e chamar e retornar de sub-rotinas no caminho usual. Como no programa de linha de execuo simples, cada chamada a uma sub-rotina em cada linha de ca execuo tem seu prprio conjunto de variveis locais, que armazenada na ca o a e pilha para aquela linha de execuo. ca Algumas vezes, todavia, desejvel duplicar uma certa varivel de forma e a a que cada linha de execuo tenha uma cpia separada. GNU/Linux suporta ca o isso fornecendo cada linha de execuo com uma rea de dados espec ca a cos de linha de execuo. As variveis armazenadas nessa rea so duplicadas para ca a a a cada linha de execuo, e cada linha de execuo pode modicar sua cpia ca ca o da varivel sem afetar outras linhas de execuo. Devido ao fato de todas a ca as linhas de execuo compartilharem o mesmo espao de memria, dados ca c o espec cos de linha de execuo no podem ser acessados usando referncias ca a e normais de variveis. GNU/Linux fornece funes especiais para modicar e a co recuperar valores da rea de dados espec a cos de linha de execuo. ca Voc pode criar tantos dados espec e cos de linha de execuo quantos ca voc quiser, cada um do tipo void*. Cada item referenciado por uma e e chave. Para criar uma nova chave, e dessa forma um novo item de dado para cada linha de execuo, use a funo pthread key create. O primeiro arguca ca mento um apontador para uma varivel do tipo denido em pthread key t. e a Esse valor de chave pode ser usado por cada linha de execuo para acessar ca sua prpria cpia do correspondente item dos dados. O segundo argumento o o a pthread key create uma funo de limpeza. Se voc informar um apone ca e tador de funo aqui, GNU/Linux automaticamente chama aquela funo ca ca indicada pelo apontador informado quando cada linha de execuo terminar ca sua execuo, informando o valor espec ca co da linha de execuo que corresca ponde quela chave. Isso particularmente adequado pelo fato de a funo de a e ca limpeza ser chamada mesmo se a linha de execuo for cancelada em algum ca ponto arbitrrio em sua execuo. Se o valor espec a ca co da linha de execuo ca 92

for NULL, a funo de limpeza da linha de execuo no chamada. Se voc ca ca a e e no precisa de uma funo de limpeza, voc pode informar null ao invs de a ca e e um apontador de funo. ca

Aps voc ter criado uma chave, cada linha de execuo pode modicar o e ca seu valor espec co correspondente para aquela chave chamando a funo ca pthread setspecic. O Primeiro argumento a chave, e o segundo do tipo e e void* e corresponde ao valor espec co da linha de execuo a ser armazeca nado. Para recuperar algum item de dados espec cos da linha de execuo, ca chame a funo pthread getspecic, informando a chave como seu argumento. ca

Suponhamos, por exemplo, que sua aplicao distribua um trabalho entre ca diversas linhas de execuo. Para propsitos de auditoria, cada linha de ca o execuo tem um arquivo de log separado, no qual mensagens de progresso, ca para os trabalhos executados por aquela linha de execuo, so gravadas. A ca a a rea especica de dados um lugar conveniente para armazenar o apontador e para o arquivo de log de cada linha de execuo. ca

A Listagem 4.7 mostra como voc pode implementar isso. A funo prine ca cipal nesse programa exemplo cria uma chave para armazenar o apontador ao arquivo espec co da linha de execuo e ento armazenar as informaes em ca a co thread log key. Pelo fato de thread log key ser uma varivel global, ela coma e partilhada por todas as linhas de execuo. Quando cada linha de execuo ca ca inicia executando sua funo de linha de execuo, a linha de execuo abre ca ca ca um arquivo de log e armazena o apontador de arquivo sob aquela chave. Mais tarde, qualquer dessas linhas de execuo pode chamar write to thread log ca para escrever uma mensagem para o arquivo de log espec co de linha de execuo. A funo write to thread log recupera o apontador de arquivo ca ca para o arquivo de log da linha de execuo para dados espec ca cos de linha de execuo e escreve a mensagem. ca 93

Listagem 4.7: (tsd.c) Log Por Linhas de Execuo Implementado com ca Dados Espec cos de Linha de Execuo ca
1 2 3 4 5 #include <m a l l o c . h> #include <p t h r e a d . h> #include <s t d i o . h>

/ A c h a v e u s a d a p a r a a s s o c i a r um a p o n t a d o r d e a r q u i v o d e r e g i s t r o a c a d a l i n h a d e execucao . / 6 static pthread key t thread log key ; 7 8 / E s c r e v e MESSAGE no a r q u i v o d e l o g p a r a a a t u a l l i n h a d e e x e c u c a o . / 9 10 void w r i t e t o t h r e a d l o g ( const char m e s s a g e ) 11 { 12 FILE t h r e a d l o g = ( FILE ) p t h r e a d g e t s p e c i f i c ( t h r e a d l o g k e y ) ; 13 f p r i n t f ( t h r e a d l o g , %s \n , m e s s a g e ) ; 14 } 15 16 / F e c h a o a p o n t a d o r p a r a o a r q u i v o d e l o g THREAD LOG . / 17 18 void c l o s e t h r e a d l o g ( void t h r e a d l o g ) 19 { 20 f c l o s e ( ( FILE ) t h r e a d l o g ) ; 21 } 22 23 void t h r e a d f u n c t i o n ( void a r g s ) 24 { 25 char t h r e a d l o g f i l e n a m e [ 2 0 ] ; 26 FILE t h r e a d l o g ; 27 28 / Gera o nome d e a r q u i v o p a r a e s s e a r q u i v o d e l o g d e l i n h a d e e x e c u c a o . / 29 s p r i n t f ( t h r e a d l o g f i l e n a m e , t h r e a d%d . l o g , ( i n t ) p t h r e a d s e l f ( ) ) ; 30 / Open t h e l o g f i l e . / 31 t h r e a d l o g = f o p e n ( t h r e a d l o g f i l e n a m e , w ) ; 32 / Armazena o a p o n t a d o r d e a r q u i v o em d a d o s d e t h r e a d s p e c i f i c s o b t h r e a d l o g k e y . / 33 pthread setspecific ( thread log key , thread log ) ; 34 35 w r i t e t o t h r e a d l o g ( Thread s t a r t i n g . ) ; 36 / Faz a l g u m t r a b a l h o a q u i . . . / 37 38 return NULL ; 39 } 40 41 i n t main ( ) 42 { 43 int i ; 44 pthread t threads [ 5 ] ; 45 46 / C r i a uma c h a v e p a r a a s s o c i a r o a p o n t a d o r d e a r q u i v o d e l o g d e uma l i n h a d e e x e c u c a o em 47 dados de t h r e a d s p e c i f i c . Use c l o s e t h r e a d l o g p a r a l i m p a r o s a p o n t a d o r e s 48 arquivo . / 49 p t h r e a d k e y c r e a t e (& t h r e a d l o g k e y , c l o s e t h r e a d l o g ) ; 50 / C r i a l i n h a s d e e x e c u c a o p a r a f a z e r o t r a b a l h o . / 51 f o r ( i = 0 ; i < 5 ; ++i ) 52 p t h r e a d c r e a t e (&( t h r e a d s [ i ] ) , NULL, t h r e a d f u n c t i o n , NULL) ; 53 / E s p e r a p o r t o d a s a s l i n h a s d e e x e c u c a o t e r m i n a r e m . / 54 f o r ( i = 0 ; i < 5 ; ++i ) 55 p t h r e a d j o i n ( t h r e a d s [ i ] , NULL) ; 56 return 0 ; 57 }

Observe que thread function no precisa fechar o arquivo de log. Isso a ocorre pelo fato de que ao ser o arquivo de log criado, close thread log foi especicada como a funo de limpeza para aquela chave. Sempre que uma ca linha de execuo encerra, GNU/Linux chama close thread log, informando ca o valor espec co de linha de execuo para a chave do log espec ca co da linha de execuo. Essa funo toma o cuidado de fechar o arquivo de log. ca ca 94

4.3.1

Manipuladores de Limpeza

As funes de limpeza para dados espec co cos de linha de execuo so neca a cessrias para garantir que recursos no sejam perdidos quando a linha de a a execuo encerrar ou for cancelada. Algumas vezes, ao longo de todo um ca projeto de software, util estar apto a especicar funes de limpeza sem e co criar novos itens de dados espec cos de linha de execuo que duplicado ca e para cada linha de execuo. GNU/Linux fornece cabealhos de limpeza ca c para esse propsito. o Um manipulador de limpeza simplesmente uma funo que deve ser e ca chamada quando a linha de execuo termina. O manipulador recebe um ca parmetro unico do tipo void*, e seu valor de argumento fornecido quando o a e manipulador registrado isso facilita o uso da mesma funo manipuladora e ca para liberar recursos em multiplas instncias. a Um manipulador um procedimento temporrio, usado para liberar um e a recurso somente se a linha de execuo encerrar ou for cancelada ao invs de ca e terminar a execuo de uma regio particular de cdigo. Sob circunstncias ca a o a normais, quando a linha de execuo no encerra e no cancelada, o reca a a e curso deve ser liberado explicitamente e o manipulador de limpeza deve ser removido. Para registrar um manipulador de limpeza, chame a funo pthread clean ca up push, informando um apontador para a funo de limpeza e o valor do seu ca argumento void*. A chamada a pthread cleanup push deve ser equilibrada por uma correspondente chamada a pthread cleanup pop, que remove o registro do maniplulador de limpeza. Por convenincia, pthread cleanup pop recebe e um argumento sinalizador do tipo int; se o sinalizador for diferente de zero, a ao de limpeza executada imediatamente e seu registro removido. ca e e O fragmento de programa na Listagem 4.8 mostra como voc pode pose sivelmente usar um manipulador de limpeza para garantir que um espao c temporrio de armazenamento alocado dinamicamente seja limpo se a linha a de execuo terminar. ca 95

Listagem 4.8: (cleanup.c) Fragmento de Programa Demonstrando um Manipulador de Limpeza de Linha de Execuo ca
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <m a l l o c . h> #include <p t h r e a d . h> / A l o c a um e s p a c o t e m p o r a r i o d e armazenagem . size ) /

void a l l o c a t e b u f f e r ( s i z e t { return m a l l o c ( s i z e ) ; } / D e s a l o c a um e s p a c o void d e a l l o c a t e b u f f e r { free ( buffer ) ; }

t e m p o r a r i o d e armazenagem ( void b u f f e r )

passageiro .

void d o s o m e w o r k ( ) { / A l o c a um e s p a c o t e m p o r a r i o d e armazenagem . / void t e m p b u f f e r = a l l o c a t e b u f f e r ( 1 0 2 4 ) ; / R e g i s t r a um m a n i p u l a d o r d e l i m p e z a p a r a e s s e e s p a c o t e m p o r a r i o d e armazenagem , p a r a d e s a l o c a l o no 23 c a s o da l i n h a d e e x e c u c a o s a i r ou s e r c a n c e l a d a . / 24 pthread cleanup push ( deallocate buffer , temp buffer ) ; 25 26 / F a z e r a l g u m a c o i s a a q u i q u e p o d e chamar p t h r e a d e x i t ou p o d e s e r 27 cancelada . . . / 28 29 / D e s r e g i s t r a r o m a n i p u l a d o r d e l i m p e z a . Uma v e z q u e i n f o r m a m o s um v a l o r nao n u l o , 30 e s s e r o t i n a a q u i e x e c u t a a t u a l m e n t e a l i m p e z a a t r a v e s de 31 deallocate buffer . / 32 pthread cleanup pop (1) ; 33 }

Pelo fato de o argumento a pthread cleanup pop ser diferene de zero nesse e caso, a funo de limpeza deallocate buer chamada automaticamente aqui ca e no precisa ser chamada explicitamente. Nesse unico caso, pudemos ter a a funo da biblioteca padro liberando diretamente como nosso manipulador ca a de limpeza ao invs de deallocate buer. e

4.3.2

Limpeza de Linha de Execuo em C++ ca

Programadores em C++ esto acostumados limpar livremente empacotando a aes de limpeza em objetos destrutores. Quando os objetos saem fora do co escopo, ou por que um bloco executado para completar alguma coisa ou e pelo fato de uma exceo ser esquecida, C++ garante que destrutores seca jam chamados para aquelas variveis automticas que tiverem as referidas a a excees e blocos. Esse comportamento de C++ fornece um mecanismo maco nipulador para garantir que cdigo de limpeza seja chamado sem importar o como o bloco terminou. Se uma linha de execuo chama a funo pthread exit, C++ no garante ca ca a que destrutores sejam chamados para todas as variveis automticas na pilha a a da linha de execuo. Uma maneira inteligente de recuperar essa funcionaca lidade invocar a funo pthread exit no n mais alto da funo de linha e ca vel ca 96

de execuo abandonando alguma exceo especial. ca ca O programa na Listagem 4.9 demonstra isso. Usando essa tcnica, uma e funo indica sua inteno de encerrar a linha de execuo abandonando uma ca ca ca ThreadExitException ao invs de chamar pthread exit diretamente. Pelo fato e de a exceo ter sido detectada na funo de linha de execuo de n ca ca ca vel mais alto, todas as variveis locais sobre a pilha da linha de execuo sero a ca a destru das como se a exceo limpasse a si mesma. ca Listagem 4.9: (cxx-exit.cpp) Implementando Sa Segura de uma Linha da de Execuo com Excees de C++ ca co
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <p t h r e a d . h> extern b o o l should exit thread immediately () ;

c l a s s ThreadExitException { public : / C r i a uma e x e c a o s i n a l i z a n d o a s a i d a da T h r e a d E x i t E x c e p t i o n ( void r e t u r n v a l u e ) : thread return value ( return value ) { } / A t u a l m e n t e s a i da l i n h a d e e x e c u c a o , construtor . / void DoThreadExit ( ) { pthread exit ( thread return value ) ; } private : / O v a l o r d e r e t o r n o q u e i r a void t h r e a d r e t u r n v a l u e ; }; void d o s o m e w o r k ( ) { while ( 1 ) { / Faz a l g u m a s c o i s a s if } } void t h r e a d f u n c t i o n ( void ) { try { do some work ( ) ; } c a t c h ( T h r e a d E x i t E x c e p t i o n ex ) { / Alguma f u n c a o i n d i c a d a q u e d e v e m o s ex . DoThreadExit ( ) ; } return NULL ; }

linha

d e e x e c u c a o com RETURN VALUE .

usando o v a l o r

de

retorno

f o r n e c i d o no

ser

u s a d o q u a n d o da s a i d a da

linha

de e x e c u c a o .

uteis

aqui . . .

( should exit thread immediately () ) throw T h r e a d E x i t E x c e p t i o n ( / v a l o r d e

r e t o r n o da

linha

d e e x e c u c a o = / NULL) ;

sair

da

linha

de e x e c u c a o .

4.4

Sincronizao e Seoes Cr ca c ticas

Programar com linhas de execuo muito complicado pelo fato de que a ca e maioria dos programas feitos usando linhas de execuo serem programas ca que competem uns com os outros. Em particular, no existe caminho para a saber quando o sistema ir agendar uma linha de execuo para ser execua ca 97

tada e quando o sistema ir executar outra linha de execuo. Uma linha a ca de execuo pode ser executada pelo sistema por tempo muito longo, ou o ca sistema pode alternar entre diversas linhas de execuo muito rapidamente. ca Em um sistema com mltiplos processadores, o sistema pode mesmo agendar u multiplas linhas de execuo para serem executadas literalmente ao mesmo ca tempo. Depurar um programa que usa linha de execuo dif pelo fato de ca e cil voc no poder sempre e facilmente reproduzir o comportamento que causa e a o problema. Voc pode executar o programa e ter tudo trabalhando perfeitae mente; a prxima vez que voc executar o programa, ele pode cair. No existe o e a caminho para fazer o sistema agendar as linhas de execuo exatamente da ca mesma maneira que foi feito anteriormente. A mais recente causa da maioria dos erros envolvendo linhas de execuo ca que as linhas de execuo diferentes acessando a mesma informao na e ca ca memria. Como mencionado anteriormente, esse comportamento de divero sas linhas de execuo acessaem a mesma informao um dos poderosos ca ca e aspctos de uma linha de execuo, mas esse comportamento tambm pode e ca e ser perigoso. Se uma linha de execuo atualiza parcialmente uma estrutura ca de dados quando outra linha de execuo acessa a mesma estrutura de daca dos, vai provavelmente acontecer uma confuso. Muitas vezes, programas a que usam linha de execuo e possuem erros carregam um cdigo que ir traca o a balhar somente se uma linha de execuo recebe agendamento muitas vezes ca mais ou mais cedo que outra linha de execuo. Esses erros so chamaca a dos condies de corrida; as linhas de execuo esto competindo uma com co ca a a outra para modicar a mesma estrutura de dados.

4.4.1

Condies de Corrida co

Suponhamos que seu programa tenha uma srie de trabalhos enleirados e que so processados por muitas linhas de execuo concorrentes. A la de a ca trabalhos representada por uma lista linkada de objetos de estrutura de e trabalho. Aps cada linha de execuo terminar uma operao, ela verica o ca ca a la para ver se um trabalho adicional est dispon a vel. Se job queue for diferente de NULL, a linha de execuo remove o trabalho do topo da lista ca linkada e posiciona job queue no prximo trabalho da lista. A funo de linha o ca de execuo que processa trabalhos na la pode parecer-se com a Listagem ca 4.10. 98

Listagem 4.10: ( job-queue1.c) Funo de Linha de Execuo para Proca ca cessar Trabalhos Enleirados
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include <m a l l o c . h> struct job { / Campo e n c a d e a d o p a r a struct job next ; lista encadeada . /

/ O u t r o s campos d e s c r e v e n d o }; / Uma l i s t a e n c a d e a d a d e struct job job queue ; extern void p r o c e s s j o b / P r o c e s s a trabalhos da

trabalho a ser

feito ...

trabalhos

pendentes .

( struct job ) ; fila a t e que a lista esteja vazia . /

void t h r e a d f u n c t i o n ( void a r g ) { while ( j o b q u e u e != NULL) { / Pega o p r o x i m o t r a b a l h o d i s p o n i v e l . struct job n e x t j o b = job queue ; / Remove e s s e t r a b a l h o da l i s t a . / job queue = job queue >n e x t ; / R e a l i z a o t r a b a l h o . / process job ( next job ) ; / Limpa . / free ( next job ) ; } return NULL ; }

Agora suponhamos que duas linhas de execuo encerrem um trabalho ca aproximadamente ao mesmo tempo, mas somente um trabalho reste na la. A primeira linha de execuo verica se job queue NULL; encontrando que ca e no , a linha de execuo entra no lao e armazena o apontador para o a e ca c objeto de trabalho em next job. Nesse ponto, o sistema GNU/Linux interrompe a primeira linha de execuo e agenda a segunda. A segunda linha ca de execuo tambm verica se job queue NULL; e encontrando que no ca e e a , tambm atribui o mesmo apontador de trabalho para next job. Por desae e fortunada coincidncia, temos agora duas linhas de execuo executando o e ca mesmo trabalho. Para piorar a situao, uma linha de execuo ir deslinkar o objeto ca ca a de trabalho da lista, permitindo que job queue contenha NULL. Quando a outra linha de execuo avaliar job queue->next, uma falha de segmentao ca ca ir aparecer. a Esse um exemplo de condio de corrida. Sob afortunadascircunstne ca a cias, esse particular agendamento de duas linhas de execuo podem nunca ca ocorrer, e a condio de corrida pode nunca mostrar-se. Somente em circa cunstncias diferenciadas, talvez ao executar sobre um sistema muito pesado a (ou sobre um novo servidor multi-processado de um importante usurio!) a pode o erro mostrar-se. Para eliminar condies de corrida, voc precisa de um caminho para co e fazer operaes atmicas. Uma operao atmica indivis e no pode ser co o ca o e vel a 99

interrompida; uma vez que a operao for iniciada, no ir ser pausada ou ca a a interrompida at que se complete, e nenhuma outra operao ir tomar o seu e ca a lugar enquanto isso. Nesse exemplo em particular, voc ir querer vericar e a job queue; se no estivar vazia, remover o primeiro trabalho, tudo isso junto a como uma operao atmica unica. ca o

4.4.2

Mutexes

A soluo para o problema da condio de corrida da la de trabalho ca ca e permitir que somente uma linha de execuo por vez acesse a la de linhas de ca execuo. Assim que uma linha de execuo inicia olhando na la, nenhuma ca ca outra linha de execuo deve estar apta a acessar a la at que a primeira ca e linha de execuo tenha decidido se realiza um trabalho e, se zer isso , tiver ca removido o trabalho da lista. A implementao disso requer suporte por parte do sistema operacional. ca GNU/Linux fornece mutexes, abreviatura de trava de excluso mtua 8 . Um a u mutex uma trava especial que somente uma linha de execuo pode travar e ca a cada vez. Se uma linha de execuo trava um mutex e ento uma segunda ca a linha de execuo tambm tenta travar o mesmo mutex, a segunda linha de ca e execuo bloqueada, ou colocada em espera. somente quando a primeira ca e linha de execuo destrava o mutex a segunda linha de execuo desbloca e ca queada permitindo sua execuo. GNU/Linux garante que condies de ca co corrida no ocorram em meio a linhas de execuo que tentem travar um a ca mutex ; somente uma linha de execuo ir mesmo pegar a trava, e todas as ca a outras linhas de execuo iro ser bloqueadas. ca a Pensando em um mutex como a trava de uma porta de banheiro. Quem chegar primeiro entra no banheiro e trava a porta. Se alguma outra pessoa tenta entrar no banheiro enquanto ele estiver ocupado, aquela pessoa encontra a porta fechada e ir ser forada a esperar do lado de fora at que o a c e ocupante aparea. c Para criar um mutex, crie uma varivel do tipo pthread mutex t e informe a um apontador para essa varivel criada para a funo pthread mutex init. O a ca segundo argumento de pthread mutex init um apontador para um objeto de e atributo de mutex, que especica os atributos de um mutex. Da mesma forma que ocorre com a funo pthread create, se o apontador de atributo for nulo, ca atributos padronizados so assumidos. A Varivel mutex deve ser inicializada a a somente uma unica vez. Esse fragmento de cdigo adiante demonstra a o declarao e a inicializao de uma varivel mutex. ca ca a p t h r e a d m u t e x t mutex ;
8

Nota do tradutor:MUTual EXclusion.

100

p t h r e a d m u t e x i n i t (&mutex , NULL ) ;

Outra maneira mais simples de criar um mutex com atributos padronizados inicializar o referido mutex com o valor especial PTHREAD MUTEX e INITIALIZER. Nenhuma chamada adicional a pthread mutex init necessria. e a Essa forma particularmente conveniente para variveis globais (e, em C++, e a membros de dados estticos). O fragmento de cdigo acima poderia equivaa o lentemente ter sido escrito como segue:

p t h r e a d m u t e x t mutex = PTHREAD MUTEX INITIALIZER ;

Uma linha de execuo pode tentar travar um mutex por meio de uma ca chamada a pthread mutex lock referindo-se ao dito mutex. Se o mutex estiver desbloqueado, ele torna-se travado e a funo retorna imediatamente. Se o ca mutex estiver travado por outra linha de execuo, pthread mutex lock bloca queia a execuo e retorna somente quando o mutex for desbloqueado pela ca outra linha de execuo. Diversas linhas de execuo ao mesmo tempo poca ca dem ser bloqueadas ao tentarem usar um mutex travado. Quando o mutex for desbloqueado, somente uma das linhas de execuo bloqueadas (escolhida ca de forma imprevis vel) desbloqueada e permitido que a referida linha de e e execuo trave o mutex ; as outras linhas de execuo continuam bloqueadas. ca ca Uma chamada a pthread mutex unlock desbloqueia um mutex. Essa funo ca deve sempre ser chamada a partir da mesma linha de execuo que travou o ca mutex. A listagem 4.11 mostra outra verso do exemplo de la de trabalhos. a Agora a la protegida por um mutex. Antes de acessar a la (ou para e leitura ou para escrita), cada linha de execuo trava um mutex primeiraca mente. Somente quando a completa sequncia de vericar a la e remover e um trabalho for completada o mutex destravado. Isso evita a condio de e ca corrida previamente descrita. 101

Listagem 4.11: ( job-queue2.c) Funo de Tarefa da Fila de Trabalho, ca Protegida por um Mutex
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #include <m a l l o c . h> #include <p t h r e a d . h> struct job { / Campo e n c a d e a d o p a r a struct job next ;

lista

encadeada .

/ O u t r o s campos d e s c r e v e n d o o t r a b a l h o a s e r }; / Uma l i s t a e n c a d e a d a d e struct job job queue ; extern void p r o c e s s j o b trabalhos pendentes .

feito ...

( struct job ) ;

/ Um mutex p r o t e g e n d o j o b q u e u e . / p t h r e a d m u t e x t j o b q u e u e m u t e x = PTHREAD MUTEX INITIALIZER ; / P r o c e s s a trabalhos da fila a t e que a fila esteja vazia . /

void t h r e a d f u n c t i o n ( void a r g ) { while ( 1 ) { struct job n e x t j o b ; / Trava o mutex s o b r e o t r a b a l h o da f i l a . / p t h r e a d m u t e x l o c k (& j o b q u e u e m u t e x ) ; / Agora e s e g u r o v e r i f i c a r s e a f i l a e s t a v a z i a . / i f ( j o b q u e u e == NULL) n e x t j o b = NULL ; else { / Pega o p r o x i m o t r a b a l h o d i s p o n i v e l . / next job = job queue ; / Remove e s s e t r a b l h o d a l i s t a . / job queue = job queue >n e x t ; } / D e s b l o q u e i a o mutex s o b r e o t r a b a l h o da f i l a , uam v e z f i l a por agora . / p t h r e a d m u t e x u n l o c k (& j o b q u e u e m u t e x ) ; / E s t a a f i l a v a z i a ? i f ( n e x t j o b == NULL) break ; Se estiver , termine a linha

q u e t e r m i n a m o s com a

de e x e c u c a o .

/ R e a l i z a o t r a b a l h o . / process job ( next job ) ; / Limpa . / free ( next job ) ; } return NULL ; }

Todo o acesso a job queue, o apontador de dados compartilhados, vem entre a chamada a pthread mutex lock e a chamada a pthread mutex unlock. Um objeto de trabalho, armazenado em next job, acessado de fora dessa e regio somente aps aquele objeto de trabalho ter sido removido da la e a o estar, dessa forma, inacess a outras linhas de execuo. vel ca Note que se a la estiver vazia (isto , job queue for NULL), ns no e o a sa mos fora do lao imediatamente pelo fato de termos que manter o mutex c permanentemente travado e devemos prevenir que qualquer outra linha de execuo acesse a la de trabalhos novamente pois ela est vazia. Ao invs ca a e disso, lembramos esse fato escolhendo next job para NULL e saimos fora do lao somente aps desbloquear o mutex. c o O uso de mutex para travar job queue no automtico; cabe a voc a e a e 102

adicionar o cdigo para travar o mutex antes de acessar job queue e tambm o e o cdigo para destravar job queue posteriormente. Por exemplo, uma funo o ca para adicionar um trabalho ` la de trabalhos pode parecer-se com isso: a

void e n q u e u e j o b ( struct j o b new job ) { p t h r e a d m u t e x l o c k (& j ob qu eu e mu te x ) ; new job>next = j o b q u e u e ; j o b q u e u e = new job ; p t h r e a d m u t e x u n l o c k (& j ob qu eu e mu te x ) ; }

4.4.3

Travas Mortas de Mutex

Mutexes fornecem um mecanismo para permitir que uma linha de execuo ca bloquei a execuo de outra. Esse procedimento abre a possibilidade de uma ca nova classe de falhas, chamadas travas mortas. Uma trava morta ocorre quando uma ou mais linhas de execuo esto presas esperando por alguma ca a coisa que nunca ir ocorrer. a Um tipo unico de trava morta ocorre quando a mesma linha de execuo ca tenta bloquear um mutex duas vezes em uma linha. O comportamento nesse caso depende de qual tipo de mutex est sendo usado. Existem trs tipos de a e mutex : 103

rpido - travando um mutex rpido (o tipo padro) far com que a a a a ocorra uma trava morta. Como foi dito anteriormente, uma tentativa trava os blocos mutex at que o mutex seja desbloqueado. Mas e pelo fato de a linha de execuo que travou o mutex estar bloqueada ca nesse mesmo mutex, a trava no pode nunca ser liberada. a recursivo - travando um mutex recursivo no causa uma trava a morta. Um mutex recursivo pode seguramente ser travado vrias a vezes pela mesma linha de execuo. O mutex recursivo lembra ca quantas vezes pthread mutex lock foi chamada sobre o mesmo mutex pela linha de execuo que segura a trava; a linha de execuo ca ca que segura a trava deve fazer o mesmo nmero de chamadas a pthu read mutex unlock antes do mutex atual ser desbloqueado e outra linha de execuo conseguir travar o mutex liberado. ca vericao de erro - GNU/Linux ir detectar e sinalizar uma trava ca a dupla sobre um mutex de vericao de erro que poderia de outra ca forma causar uma trava morta. A segunda chamada consecutiva a pthread mutex lock retorna o cdigo de falha EDEADLK. o Por padro, um mutex GNU/Linux do tipo rpido. Para criar um a e a mutex de um dos outros dois tipos, primeiro crie um objeto de atributo de mutex declarando uma varivel do tipo pthread mutexattr t e chamando ptha a read mutexattr init sobre um apontador para a varivel do tipo pthread mutex attr t. A seguir ajuste o tipo do mutex chamando pthread mutexattr setkind np; o primeiro argumento um apontador para o objeto de atributo de mue tex, e o segundo PTHREAD MUTEX RECURSIVE NP para um mutex e recursivo, ou PTHREAD MUTEX ERRORCHECK NP para um mutex de vericao de erro. Informe um apontador para esse atributo de objeto na ca ca funo pthread mutex init para criar um mutex do tipo de vericao de erro, ca e ento destrua o objeto de atributo com a funo pthread mutexattr destroy. a ca A sequncia de cdigo abaixo ilustra a criao de ummutex de vericao e o ca ca de erro, por exemplo:
pthread pthread pthread pthread pthread pthread mutexattr t attr ; m u t e x t mutex ; m u t e x a t t r i n i t (\& a t t r ) ; m u t e x a t t r s e t k i n d n p (\& a t t r , PTHREAD MUTEX ERRORCHECK NP ) ; m u t e x i n i t (\&mutex , \& a t t r ) ; m u t e x a t t r d e s t r o y (\& a t t r ) ;

Como sugerido pelo suxo np, os mutexes do tipo recursivo e de vericao de erro so espec ca a cos do GNU/Linux e no so portveis. Todavia, a a a no geralmente aconselhado usar esses dois tipos de mutexes em programas. a e (Mutexes de vericao de erro podem ser uteis quando se faz depuraes, ca co apesar disso.) 104

4.4.4

Testes de Mutex sem Bloqueio

Ocasionalmente, util testar se um mutex est travado sem sofrer bloqueio e a algum relativamente a esse mutex. Por exemplo, uma linha de execuo pode ca precisar travar um mutex mas pode ter outro trabalho para fazer ao invs ser e bloqueada se o mutex j estiver travado. Pelo fato de que pthread mutex lock a no ir retornar at que o mutex se torne desbloqueado, alguma outra funo a a e ca necessria. e a GNU/Linux fornece pthread mutex trylock para esse propsito. Se voc o e chamar pthread mutex trylock sobre um mutex destravado, voc ir travar o e a mutex como se voc tivesse chamado called pthread mutex lock, e pthread mut e ex trylock ir retornar zero. Todavia, se o mutex j estiver bloqueado por a a outra linha de execuo, pthread mutex trylock no ir bloquear a linha de ca a a a execuo atual. Ao invs disso, pthread mutex trylock ir retornar imediataca e mente com o cdigo de erro EBUSY. A trava de mutex mantida pela outra o linha de execuo no afetada. Voc pode tentar mais tarde travar o mutex. ca a e e

4.4.5

Semforos para Linhas de Execuo a ca

No exemplo precedente, no qual muitas linhas de execuo processam trabaca lhos a partir de um la, a funo de linha de execuo principal das linhas de ca ca execuo realiza o prximo trabalho at que nenhum trabalho seja esquecido ca o e e ento termina a linha de execuo. Esse esquema funciona se todos os a ca trabalhos forem enleirados previamente ou se novos trabalhos forem enleirados to rapidamente quanto as linhas de execuo os processam. Todavia, a ca se as linhas de execuo trabalham muito rapidamente, a la de trabalhos ir ca a esvaziar e as linhas de execuo encerraram. Se novos trabalhos forem mais ca tarde enleirados, nenhuma linha de execuo pode restar para process-los. ca a O que podemos apreciar ao invs do exposto acima um mecanismo para e e bloquear as linhas de execuo quando a la esvaziar at que novos trabalhos ca e estejam dispon veis. Um semforo fornece um mtodo conveniente para fazer isso. Um semforo a e a um contador que pode ser usado para sincronizar multiplas linhas de e execuo. Da mesma forma que com o mutex, GNU/Linux garante que a ca vericao ou a modicao do valor de um semforo pode ser feito de forma ca ca a segura, sem criar condies de corrida. co Cada semforo tem um valor de contagem, que um inteiro no negativo. a e a Um semforo suporta duas operaes bsicas: a co a 105

Uma operao wait decrementa o semforo de 1. Se o valor j ca a a for zero, a operao bloqueia at que o valor do semforo torneca e a se positivo (devido a ao de alguma outra linha de execuo). ca ca Quando o valor do semforo torna-se positivo, ele decrementado a e de 1 e a operao de espera retorna. ca Uma operao post incrementa o valor do semforo de 1. Se o ca a semforo era anteriormente zero e outras linhas de execuo esto a ca a bloqueadas em uma operao wait sobre o atual semforo, uma ca a daquelas linhas de execuo desbloqueada e sua operao wait ca e ca realiza-se (o que acarreta o retorno do valor do semforo a zero). a Note que GNU/Linux fornece duas implementaes de semforos ligeiraco a mente diferentes. A primeira que descrevemos aqui a implementao de e ca semforos POSIX padro. Use os semforos POSIX quando comunicando-se a a a entre linhas de execuo. A outra implementao, usada para comunicao ca ca ca entre processos, descrita na Seo 5.2, Semforos de Processos. Se voc e ca a e usa semforos, inclua <semaphore.h>. a Um semforo representado por uma varvel sem t. Antes de usar a a e a varivel, voc deve inicializ-la usando a funo sem init, informando um a e a ca apontador para a varivel sem t. O segundo parmetro deve ser zero 9 , e o a a terceiro parmetro o valor inicial do semforo. Se voc no mais precisar a e a e a de um semforo, bom liberar seus recursos com sem destroy. a e Para operaes do tipo wait, use sem wait. Para operaes do tipo post, co co ca a use sem post. Uma funo que no faz bloqueio do tipo wait, chamada e e ca e sem trywait, tambm fornecida. A funo sem trywait semelhante a pthread mutex trylock se a operao do tipo wait puder ser bloqueada pelo ca fato de o valor do semforo ser zero, a funo retorna imediatamente, com o a ca valor de erro EAGAIN, ao invs de efetuar o bloqueio. e GNU/Linux tambm fornece uma funo para recuperar o valor atual de e ca um semforo, sem getvalue, a qual coloca o valor em um apontador para uma a varivel do tipo int por meio de seu segundo argumento. Voc no deve usar a e a o valor do semforo que voc pegou dessa funo para decidir fazer ou um a e ca wait ou um post sobre o semforo, apesar disso. Usar o valor do semforo a a pode levar a uma condio de corrida: Outra linha de execuo pode mudar ca ca o valor do semforo entre a chamada a sem getvalue e a chamada a outra a funo de semforo. Use as funes atmicas post e wait ao invs de usar o ca a co o e valor do semforo. a Retomando para nosso exemplo de la de trabalho, podemos usar um semforo para contar o nmero de trabalhos esperando na la. A Listagem a u
Um valor diferente de zero pode indicar a semforo que pode ser compartilhado por a vrios processos, o que no suportado pelo GNU/Linux para esse tipo de semforo. a a e a
9

106

4.12 controla a la com um semforo. A funo enqueue job adiciona um a ca novo trabalho ` la. a

107

Listagem 4.12: ( job-queue3.c) Fila de Trabalhos Controlada por um Semforo a


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 #include <m a l l o c . h> #include <p t h r e a d . h> #include <semaphore . h> struct job { / Campo e n c a d e a d o p a r a struct job next ;

lista

encadeada .

/ O u t r o s campos d e s c r e v e n d o }; / Uma l i s t a e n c a d e a d a d e struct job job queue ; extern void p r o c e s s j o b

trabalho a ser

feito ...

trabalhos

pendentes .

( struct job ) ;

/ Um mutex p r o t e g e n d o j o b q u e u e . / p t h r e a d m u t e x t j o b q u e u e m u t e x = PTHREAD MUTEX INITIALIZER ; / Um s e m a f o r o c o n t a n d o o numero d e sem t job queue count ; / E x e c u t e d e uma s o vez a t r a b a l h o s na fila . /

inicializacao

da

fila

de

trabalhos .

void i n i t i a l i z e j o b q u e u e ( ) { / A f i l a e s t a i n i c i a l m e n t e v a z i a . / j o b q u e u e = NULL ; / I n i c i a l i z a o s e m a f o r o no q u a l t r a b a l h o s v a l o r i n i c i a l deve ser zero . / s e m i n i t (& j o b q u e u e c o u n t , 0 , 0 ) ; } / P r o c e s s a t r a b a l h o s na fila a t e que a fila

sao

c o n t a d o s na

fila .

Seu

esteja

vazia .

void t h r e a d f u n c t i o n ( void a r g ) { while ( 1 ) { struct job n e x t j o b ; / E s p e r a p e l o s e m a f o r o da f i l a d e t r a b a l h o . Se s e u v a l o r f o r p o s i t i v o , i n d i c a n d o q u e a f i l a nao e s t a v a z i a , d e c r e m e n t e o c o n t a d o r d e um . Se a f i l a e s t i v e r v a z i a , b l o q u e i e a t e q u e um n o v o t r a b a l h o s e j a enfileirado . / s e m w a i t (& j o b q u e u e c o u n t ) ; / T r a v e o mutex s o b r e a f i l a d e t r a b a l h o . / p t h r e a d m u t e x l o c k (& j o b q u e u e m u t e x ) ; / D e v i d o ao s e m a f o r o , s a b e m o s q u e a f i l a nao e s t a v a z i a . Pegue o trabalho disponivel seguinte . / next job = job queue ; / Remove e s s e t r a b a l h o da l i s t a . / job queue = job queue >n e x t ; / D e s b l o q u e i a o mutex s o b r e a f i l a d e t r a b a l h o , uma v e z q u e t e r m i n a m o s com a f i l a por agora . / p t h r e a d m u t e x u n l o c k (& j o b q u e u e m u t e x ) ; / R e a l i z a m o s o t r a b a l h o . process job ( next job ) ; / Limpamos . / free ( next job ) ; } return NULL ; } / A d i c i o n e um n o v o t r a b a l h o na f r e n t e da fila de do trabalho . trabalho / aqui . . . / ) /

void e n q u e u e j o b ( / I n f o r m e d a d o s { struct job new job ;

especificos

/ A l o q u e um n o v o o b j e t o d e t r a b a l h o . / new job = ( struct job ) malloc ( s i z e o f ( struct job ) ) ; / A j u s t e o s o u t r o s campos da e s t r u t u r a d e t r a b a l h o a q u i . . . / T r a v e o mutex s o b r e a f i l a d e t r a b a l h o a n t e s d e p t h r e a d m u t e x l o c k (& j o b q u e u e m u t e x ) ; / C o l o q u e o n o v o t r a b a l h o na c a b e c a da f i l a . / n e w j o b >n e x t = j o b q u e u e ; job queue = new job ; acessar a

/ fila . /

108

Listagem 4.13: ( job-queue3.c) Continuao ca


80 81 82 83 84 85 / D e s b l o q u e i a o mutex da f i l a d e t r a b a l h o . 86 p t h r e a d m u t e x u n l o c k (& j o b q u e u e m u t e x ) ; 87 } / Faca o p o s t s o b r e o s e m a f o r o p a r a i n d i c a r q u e o u t r o t r a b a l h o e s t a d i s p o n i v e l . Se l i n h a s d e e x e c u c a o e s t i v e r e m b l o q u e a d a s , e s p e r a n d o o s e m a f o r o , uma i r a t o r n a r s e d e s b l o q u e a d a de forma que p o s s a p r o c e s s a r o t r a b a l h o . / s e m p o s t (& j o b q u e u e c o u n t ) ; /

Antes de pegar um trabalho da primeira posio da la, cada linha de ca execuo ir primeiramente realizar uma operao wait sobre o semforo. ca a ca a Se o valor do semforo for zero, indicando que a la est vazia, a linha de a a execuo ser simplesmente bloqueada at que o valor do semforo torne-se ca a e a positivo, indicando que um trabalho foi adicionado ` la. a A funo enqueue job adiciona um trabalho ` la. Da mesma forma que ca a thread function, a funo enqueue job precisa travar o mutex da la antes de ca modicar a la. Aps adicionar um trabalho ` la, a funo enqueue job efeo a ca tua uma operao do tipo post no semforo, indicando que um novo trabalho ca a est dispon a vel. Na verso mostrada na Listagem 4.12, as linhas de execuo a ca que atuam sobre os trabalhos nunca terminam; se no houverem trabalhos a dispon veis em algum momento, todas as linhas de execuo simplesmente ca bloqueiam em sem wait.

4.4.6

Variveis Condicionais a

Mostramos como usar um mutex para proteger uma varivel contra acessos a simultneos de duas linhas de execuo e como usar semforos para implea ca a mentar um contador compartilhado. Uma varivel condicional uma terceiro a e dispositivo de sincronizao que GNU/Linux fornece; com variveis condicioca a nais, voc pode implementar condicionais mais complexas sob as quais linhas e de execuo realizam trabalhos. ca Suponhamos que voc escreva uma funo que executa um lao innitae ca c mente, fazendo algum trabalho a cada iterao. O lao da linha de execuo ca c ca , todavia, precisa ser controlado por um sinalizador: o lao executa somente c quando o sinalizador est ativo; quando o sinalizador est desativado, o lao a a c para. A Listagem 4.14 mostra como voc pode implementar a funo suposta e ca acima girando em um lao. Durante cada iterao do lao, a funo de linha c ca c ca de execuo verica se o sinalizador est ativo. Pelo fato de o sinalizador ca a ser acessado por vrias linhas de execuo, ele protegido por um mutex. a ca e Essa implementao pode ser correta, mas no eciente. A funo de ca a e ca linha de execuo ir gastar recursos de CPU sempre que sinalizador estiver ca a 109

dasativado, at que alguma circunstncia possa fazer com que o sinalizador e a torne-se ativado. Listagem 4.14: (spin-condvar.c) Uma Implementao Simples de Varivel ca a Condicional
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <p t h r e a d . h> extern void do wor k () ;

int t h r e a d f l a g ; pthread mutex t thread flag mutex ; void i n i t i a l i z e f l a g ( ) { p t h r e a d m u t e x i n i t (& t h r e a d f l a g m u t e x , NULL) ; thread flag = 0; } / Chama d o w o r k r e p e t i d a m e n t e a j u s t a d o ; de o u t r a forma laco . / void t h r e a d f u n c t i o n { while ( 1 ) { int f l a g i s s e t ; enquanto o sinalizador da linha de e x e c u c a o esta

( void t h r e a d a r g )

/ P r o t e g e o s i n a l i z a d o r com uma t r a v a d e mutex . p t h r e a d m u t e x l o c k (& t h r e a d f l a g m u t e x ) ; f l a g i s s e t = thread flag ; p t h r e a d m u t e x u n l o c k (& t h r e a d f l a g m u t e x ) ; ( flag is set ) do wor k ( ) ; / Caso c o n t r a r i o nao } return NULL ; } / A j u s t a o v a l o r do sinalizador da linha de e x e c u c a o if

faz

nada .

Apenas l a c o

novamente .

p a r a FLAG VALUE .

void s e t t h r e a d f l a g ( i n t f l a g v a l u e ) { / P o r t e g e o s i n a l i z a d o r com uma t r a v a d e mutex . p t h r e a d m u t e x l o c k (& t h r e a d f l a g m u t e x ) ; thread flag = flag value ; p t h r e a d m u t e x u n l o c k (& t h r e a d f l a g m u t e x ) ; }

Uma varivel condicional capacita voc a implementar uma condio sob a e ca a qual uma linha de execuo realiza algum trabalho e, inversamente, a ca condio sob a qual a linha de execuo bloqueada. Enquanto toda linha ca ca e de execuo que potencialmente modica o senso da condio usa a varivel ca ca a condicional propriamente, GNU/Linux garante que linhas de execuo bloca queadas na condio iro ser desbloqueadas quando a condio mudar. ca a ca Da mesma forma que com um semforo, uma linha de execuo pode a ca esperar por uma varivel condicional. Se linha de execuo A espera por a ca uma varivel condicional, a linha de execuo A bloqueada at que alguma a ca e e outra linha de execuo, uma linha de execuo B, sinalize a mesma varivel ca ca a condicional. Diferentemente do semforo, uma varivel condicional no tem a a a contador ou memria; a linha de execuo A deve esperar pela varivel condio ca a cional antes da linha de execuo B sinalize essa mesma varivel condicional ca a 110

novamente. Se a linha de execuo B sinaliza a varivel condicional antes ca a que a linha de execuo A espere pela mesma varivel condicional, o sinal ca a e perdido, e a linha de execuo A ca bloqueada at que alguma outra linha ca e de execuo sinalize a varivel condicional novamente. ca a Adiante mostra-se como voc poderia usar uma varivel condicional para e a fazer a linha de execuo acima de forma mais eciente: ca O lao em thread function verica o sinalizador. Se o sinalizador c est desativado, a linha de execuo espera pela varivel condicioa ca a nal. a o A funo set thread ag sinaliza a varivel condicional aps moca dicar o valor do sinalizador. Por esse caminho, se o lao estiver c bloqueado na varivel condicional, ir ser desbloqueado e vericar a a a a condicional novamente. Existe um problema com isso: h uma condio de corrida entre vericar o a ca valor do sinalizador e modicar seu valor ou esperar pela varivel condicional. a Suponhamos que thread function vericou o sinalizador e encontrou-a desabilitada. Naquele momento, o GNU/Linux agendou uma pausa para aquela linha de execuo e retomou a linha de execuo principal. Por alguma coinca ca cidncia, a linha de execuo principal est em na funo set thread ag. A e ca a ca a funo set thread ag ajusta o sinalizador e sinaliza a varivel condicional. ca Pelo fato de nenhuma linha de execuo estar esperando pela varivel conca a dicional naquele momento (lembre que thread function estava pausada antes de poder esperar pela varivel condicional), o sinal perdido. Agora, quando a e GNU/Linux reagenda a outra linha de execuo, ela inicia esperando pela ca varivel condicional e pode acabar bloqueada para sempre. a Para resolver esse problema, precisamos de um caminho para travar o sinalizador e a varivel condicional juntos com um mutex unico. Afortunaa damente, GNU/Linux fornece exatamente esse mecanismo. Cada varivel a condicional deve ser usada conjuntamente com um mutex, para prevenir esse tipo de condio de corrida. Usando esse esquema, a funo de linha de ca ca execuo segue os passos abaixo: ca 1. O lao em thread function trava o mutex e l o valor do sinalizador. c e 2. Se o sinalizador estiver ativado, o sinalizador ativado causa o desbloqueio do mutex e a execuo da funo de trabalho. ca ca 3. Se o sinalizador estiver desativado, o sinalizador desativado causa o desbloqueio atomicamente do mutex e a espera pela varivel cona dicional. 111

A funcionalidade cr tica aqui est no passo 3, no qual GNU/Linux permite a a voc destravar o mutex e esperar pela varivel condicional atomicamente, e a sem a possibilidade de outra linha de execuo interferir. Isso elimina a ca possibilidade que outra linha de execuo possa modicar o valor da varivel ca a condicional entre o teste de thread function do valor do sinalizador e a espera pela varivel condicional. a Uma varivel condicional representada por uma instncia de pthread con a e a d t. Lembrando que cada varivel condicional deve ser acompanhada de um a mutex. Abaixo temos as funes que manipulam variveis condicional: co a pthread cond init inicializa uma varivel condicional. O primeiro a argumento um apontador para a instncia pthread cond t. O see a gundo argumento, um apontador para uma objeto de atributo de varivel condicional , o qual ignorado em GNU/Linux. O mutex a e deve ser inicializado separadamente, como descrito na Seo 4.4.2, ca Mutexes. pthread cond signal sinaliza uma varivel condicional. Uma linha a de execuo unica, que bloqueada conforme o estado da varivel ca e a condicional, ir ser desbloqueada. Se nenhuma outra linha de a execuo estiver bloqueada conforme a varivel de condio, o sica a ca nal ignorado. O argumento um apontador para a instncia e e a pthread cond t. Uma chamada similar, pthread cond broadcast, desbloqueia todos as linhas de execuo que estiverem bloqueadas conforme a varivel ca a condicional, ao invs de apenas uma. e pthread cond wait bloqueia a linha de execuo que a est chaca a mado at que a varivel de condio for sinalizada. O argumento e a ca um apontador par a instncia pthread cond t. O segundo argue a mento um apontador para instncia de mutex pthread mutex t. e a Quando pthread cond wait for chamada, o mutex deve j estar traa vado por meio da linha de execuo que o chamou. A funo pthca ca read cond wait atomicamente desbloqueia o mutex e bloqueia sob a varivel de condio. Quando a varivel de condio seja sinalizada a ca a ca e a linha de execuo que chamou desbloquear, pthread cond wait ca automaticamente readquire uma trava sob o mutex. Sempre que seu programa executar uma ao que pode modicar o senso ca da condio voc est protegendo com a varivel condicional, seu programa ca e a a deve executar os passos adiante. (No nosso exemplo, a condio o estado ca e 112

do sinalizador da linha de execuo, de forma que esses passos devem ser ca executados sempre que o sinalizador for modicado.)

1. Travar o mutex que acompanha a varivel condicional. a 2. Executar a ao que pode mudar o senso da condio (no nosso ca ca exemplo, ajustar o sinalizador). 3. Sinalizar ou transmitir a varivel condicional, dependendo do coma portamento desejado. 4. Desbloquear o mutex acompanhando a varivel condicional. a

A Listagem 4.15 mostra o exemplo anterior novamente, agora usando uma varivel condicional para proteger o sinalizador da linha de execuo. a ca Note que na funo thread function, uma trava sob o mutex mantida antes ca e de vericar o valor de thread ag. Aquela trava automaticamente liberada e por pthread cond wait antes de bloquear e automaticamente readquirida e posteriormente. Tambm note que set thread ag trava o mutex antes de e ajustar o valor de thread ag e sinalizar o mutex. 113

Listagem 4.15: (condvar.c) Controla uma Linha de Execuo Usando uma ca Varivel Condicional a
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #include <p t h r e a d . h> extern void do wor k () ;

int t h r e a d f l a g ; pthread cond t thread flag cv ; pthread mutex t thread flag mutex ; void i n i t i a l i z e f l a g ( ) { / I n i c i a l i z a o mutex e a v a r i a v e l d e c o n d i c a o . p t h r e a d m u t e x i n i t (& t h r e a d f l a g m u t e x , NULL) ; p t h r e a d c o n d i n i t (& t h r e a d f l a g c v , NULL) ; / I n i c i a l i z a o v a l o r do s i n a l i z a d o r . / thread flag = 0; } / Chama d o w o r k r e p e t i d a m e n t e e n q u a n t o o ajustada ; b l o q u e i a se o s i n a l i z a d o r e s t a limpo . /

sinalizador

da

linha

de e x e c u c a o e

void t h r e a d f u n c t i o n ( void t h r e a d a r g ) { / Laco i n f i n i t a m e n t e . / while ( 1 ) { / t r a v a o mutex a n t e s d e a c e s s a r o v a l o r do s i n a l i z a d o r . / p t h r e a d m u t e x l o c k (& t h r e a d f l a g m u t e x ) ; while ( ! t h r e a d f l a g ) / O s i n a l i z a d o r e l i m p o . E s p e r a p o r um s i n a l s o b r e a v a r i a v e l d e c o n d i c a o , i n d i c a n d o q u e o v a l o r do s i n a l i z a d o r mudou . Quando o s i n a l c h e g a e s u a l i n h a d e e x e c u c a o d e s b l o q u e i a , l a c o e v e r i f i c a c a o do s i n a l i z a d o r novamente . / p t h r e a d c o n d w a i t (& t h r e a d f l a g c v , &t h r e a d f l a g m u t e x ) ; / Quando t i v e r m o s a q u i , s a b e m o s q u e o s i n a l i z a d o r f o i a j u s t a d o . Destrava o o mutex . / p t h r e a d m u t e x u n l o c k (& t h r e a d f l a g m u t e x ) ; / Faz a l g u m t r a b a l h o . / do wor k ( ) ; } return NULL ; } / A j u s t a o v a l o r do sinalizador da linha de e x e c u c a o p a r a FLAG VALUE . /

void s e t t h r e a d f l a g ( i n t f l a g v a l u e ) { / Trava o mutex a n t e s d e a c e s s a r o v a l o r do s i n a l i z a d o r . / p t h r e a d m u t e x l o c k (& t h r e a d f l a g m u t e x ) ; / A j u s t a o v a l o r do s i n a l i z a d o r , e e n t a o o s i n a l no c a s o da t h r e a d f u n c t i o n e s t a r b l o q u e a d a , e s p e r e p e l o s i n a l i z a d o r t o r n a r s e a j u s t a d o . Todavia , t h r e a d f u n c t i o n nao p o d e a t u a l m e n t e v e r i f i c a r o s i n a l i z a d o r a t e q u e o mutex estar desbloqueado . / thread flag = flag value ; p t h r e a d c o n d s i g n a l (& t h r e a d f l a g c v ) ; / D e s b l o q u e i a o mutex . / p t h r e a d m u t e x u n l o c k (& t h r e a d f l a g m u t e x ) ; }

A condio protegida pela varivel condicional pode ser arbitrariamente ca a complexa. Todavia, antes de executar qualquer operao que possa mudar ca o senso da condio, uma trava de mutex deve ser requerida, e a varivel ca a condicional deve ser sinalizada depois. Uma varivel condicional pode tambm ser usada sem uma condio, a e ca simplesmente como um mecanismo para bloquear uma linha de execuo at ca e que outra linha de execuo acorde-a. Um sinalizador pode tambm ser ca e usado para aquele propsito. A principal diferena que um sinalizador o c e lembra o chamada para acordar mesmo se nenhuma linha de execuo ca 114

tiver bloqueada sobre ele naquela ocasio, enquanto uma varivel condicional a a discarta a chamada para acordar a menos que alguma linha de execuo esteja ca atualmente bloqueada sob essa mesam varivel condicional naquela ocasio. a a Tambm, um sinalizador entrega somente um unico acorde por post; com e pthread cond broadcast, um nmero arbitrrio e desconhecido de linhas de u a execuo bloqueadas pode ser acordado na mesma ocasio. ca a

4.4.7

Travas Mortas com Duas ou Mais Linhas de Execuo ca

Travas mortas podem ocorrer quando duas (ou mais) linhas de execuo ca estiverem bloqueadas, esperando que uma condio ocorra e que somente ca outra das duas (ou mais) pode fazer acontecer. Por exemplo, se uma linha de execuo A est bloqueada sob uma varivel condicional esperando pela linha ca a a de execuo B sinalize a varivel condicional, e a linha de execuo B est ca a ca a bloqueada sob uma varivel de condio esperando que a linha de execuo a ca ca A sinalize essa mesma varivel de condio, uma trava morta ocorreu pelo a ca fato de que nenhuma das linhas de execuo envolvidas ir sinalizar para a ca a outrar. Voc deve evitar a todo custo a possibilidade de tais stuaes pelo e co fato de elas serem bastante dif ceis de detectar. Um erro comum que causa uma trava morta envolve um problema no qual mais de uma linha de execuo est tentando travar o mesmo conjunto de ca a objetos. Por exemplo, considere um programa no qual duas diferentes linhas de execuo, executando duas diferentes funes de linha de execuo, precica co ca sam travar os mesmos dois mutexes. Suponhamos que a linha de execuo A ca trave o mutex 1 e a seguir o mutex 2, e a linha de execuo B precise travar ca o mutex 2 antes do mutex 1. Em um sucientemente desafortunado cenrio a de agendamento, GNU/Linux pode agendar a linha de execuo A por um ca tempo suciente para travar o mutex 1, e ento agende a linha de execuo a ca B, que prontamente trava mutex 2. Agora nenhuma linha de execuo pode ca progredir pelo fato de cada uma estar bloqueada sob um mutex que a outra linha de execuo mantm bloqueada. ca e Acima temos um exemplo de um problema genrico de trava morta, que e pode envolver no somente sincronizao de objetos tais como mutexes, mas a ca tambm outros recursos, tais como travas sob arquivos ou dispositivos. O e problema ocorre quando multiplas linhas de execuo tentam travar o mesmo ca conjunto de recursos em diferentes ordens. A soluo garantir que todas as ca e linhas de execuo que travam mais de um recurso faam tambm o travaca c e mento desses recursos na mesma ordem. 115

4.5

Implementao de uma Linha de Execuo ca ca em GNU/Linux

A implementao de linhas de execuo POSIX em GNU/Linux difere da ca ca implementao de linha de execuo de muitos outros sistemas semelhantes ca ca ao UNIX em um importante caminho: no GNU/Linux, linhas de execuo ca so implementadas como processos. Sempre que voc chamar pthread create a e para criar uma nova linha de execuo, GNU/Linux cria um novo processo ca que executa aquela linha de execuo. Todavia, esse processo no o mesmo ca a e que o processo criado com fork ; particularmente, o processo criado com pthread create compartilha o mesmo espao de endereo e recursos que o proc c cesso original em lugar de receber cpias. o O programa thread-pid mostrado na Listagem 4.16 demonstra isso. O programa cria uma linha de execuo; ambas a nova linha de execuo e a ca ca original chamam a funo getpid e imprimem seus respectivos IDs de processo ca e ento giram innitamente. a Listagem 4.16: (thread-pid) Imprime IDs de processos para Linhas de Execuo ca
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <p t h r e a d . h> #include <s t d i o . h> #include <u n i s t d . h> void t h r e a d f u n c t i o n ( void a r g ) { f p r i n t f ( s t d e r r , p i d da l i n h a de e x e c u c a o / C i c l o i n f i n i t o . / while ( 1 ) ; return NULL ; }

filha

e %d\n , ( i n t )

getpid

() ) ;

i n t main ( ) { pthread t thread ; f p r i n t f ( s t d e r r , p i d da l i n h a de e x e c u c a o p r i n c i p a l e %d\n , ( i n t ) p t h r e a d c r e a t e (& t h r e a d , NULL, &t h r e a d f u n c t i o n , NULL) ; / C i c l o i n f i n i t o . / while ( 1 ) ; return 0 ; }

getpid

() ) ;

Execute o programa em segundo plano, e ento chame ps x para mostrar a seus processos executando. Lembre-se de matar o programa thread-pid depois o mesmo consome muito da CPU sem fazer absolutamente nada. Aqui est a como a sa do ps x pode parecer: da % cc thread-pid.c -o thread-pid -lpthread % ./thread-pid \& [1] 14608 main thread pid is 14608 child thread pid is 14610 116

\% ps x PID TTY STAT 14042 pts/9 S 14608 pts/9 R 14609 pts/9 S 14610 pts/9 R 14611 pts/9 R \% kill 14608 [1]+ Terminated

TIME COMMAND 0:00 bash 0:01 ./thread-pid 0:00 ./thread-pid 0:01 ./thread-pid 0:00 ps x ./thread-pid

Noticao de Controle de Trabalho no Shell ca As linhas iniciam-se com [1] so do shell. Quando voc executa um programa a e em segundo plano, o shell atribui um nmero de trabalho para ele nesse caso, u 1 e imprime o pid do programa. Se o trabalho em segundo plano encerra-se, o shell mostra esse fato da prxima vez que voc chamar um comando. o e

Chamo a ateno para o fato de que existem trs processos executando ca e o programa thread-pid. O primeiro desses, com o pid 14608, a linha de e execuo principal no programa; o terceiro, com pid 14610, a linha de ca e execuo que criamos para executar thread function. ca O que dizer da segunda linha de execuo, com pid 14609? Essa a linha ca e de execuo gerente que parte da implementao interna de linhas de ca e ca execuo em GNU/Linux. A linha de execuo gerente criada na primeira ca ca e vez que um programa chama pthread create para criar uma nova linha de execuo. ca

4.5.1

Manipulando Sinal

Suponhamos que um programa com vrias linhas de execuo receba um sia ca nal. Em qual linha de execuo das linhas de execuo multiplas deve ser ca ca chamado o manipulador para esse sinal? O comportamento da interao enca tre sinais e linhas de execuo varia de entre os diversos sistemas operacionais ca semelhantes ao UNIX. Em GNU/Linux, o comportamento ditado pelo fato e de que as linhas de execuo so implementadas como processos. ca a Pelo fato de cada linha de execuo ser um processo separado, e pelo ca fato de um sinal ser entregue para um processo em particular, no existe a ambiguidade sobre qual linha de execuo recebe o sinal. Tipicamente, sinais ca enviados de fora do programa so enviados para o processo correspondente a a ` linha de execuo principal do programa. Por exemplo, se um programa ca executa forks e o processo lho faz execs sobre um programa com vrias a linhas de execuo, o processo pai ir manter o ID de processo da linha de ca a execuo principal do programa do processo lho e ir usar aquele ID de ca a 117

processo para enviar sinais para seu lho. Esse comportamento geralmente e uma boa conveno a seguir por voc mesmo quando enviar sinais para um ca e programa com vrias linhas de execuo. a ca Note que esse aspecto da implementao em GNU/Linux das linhas de ca execuo uma varincia da linha de execuo POSIX padro. No cone ca e a ca a a nesse comportamento em programas que so signicativamente para serem a portveis. a Dentro de um programa com vrias linhas de execuo, poss para a ca e vel uma linha de execuo enviar um sinal especicamente para outra linha de ca execuo. Use a funo pthread kill para fazer isso. O primeiro parmetro ca ca a e um ID de linha de execuo, e seu segundo parmetro um nmero de sinal. ca a e u

4.5.2

Chamada de Sistema clone

Embora linhas de execuo em GNU/Linux criadas em um mesmo proca grama sejam implementadas como processos separados, eles compartilham seu espao virtual de memria e outros recursos. Um processo lho criado c o com uma operao fork, todavia, recebe cpias desses itens. Como personaca o lizar o processo criado? A chamada de sistema GNU/Linux clone uma forma generalizada de e a fork e de pthread create que permite a quem est chamando especicar quais recursos so compartilhados entre o processo que est chamando e o processo a a criado recentemente. Tambm, clone requer que voc especique a regio e e a de memria para a pilha de execuo que o novo processo ir usar. Embora o ca a mencionemos clone aqui para satisfazer a curiosidade do leitor, essa chamada de sistema no deve frequentemente ser usada em programas. a Use fork para criar novos processos ou pthread create para criar linhas de execuo. ca

4.6

Processos Vs. Linhas de Execuo ca

Para alguns programas que se beneciam da concorrncia, a deciso entre e a usar processos ou linhas de execuo pode ser dif ca cil. Aqui esto algumas a linhas guias para ajudar voc a decidir qual modelo de concorrncia melhor e e se ajusta ao seu programa: 118

Todas as linhas de execuo em um programa devem rodar o mesmo ca executvel. Um processo lho, por outro lado, pode rodar um a executvel diferente atravs da funo exec. a e ca Uma linha de execuo errante pode prejudicar outras linhas de ca execuo no mesmo processo pelo fato de linhas de execuo comca ca partilharem o mesmo espao de memria virtual e outros recursos. c o Por exemplo, uma brbara escrita na memria por meio de um pona o teiro no inicializado em uma linha de execuo pode corromper a a ca memria vis para outra linha de execuo. Um processo errante, o vel ca por outro lado, no pode fazer isso pelo fato de cada processo ter a uma cpia do espao de memria do programa. o c o A cpia de memria para um novo processo cria um trabalho adio o cional diminuindo a performace em comparao ` criao de uma ca a ca nova linha de execuo. Todavia, a cpia executada somente ca o e quando a memria modicada, de forma que o penalti minimo o e e se o processo lho somente l a memria. e o Linhas de Execuo podem ser usadas por programas que precisam ca de paralelismo no e granulado. Por exemplo, se um problema pode ser quebrado em multiplos trabalhos aproximamente identicos, linhas de execuo podem ser uma boa escolha. Processos podem ca ser usados por programas que precisam de paralelismo rude. Compartilhando dados em torno de linhas de execuo trivial ca e pelo fato de linhas de execuo compartilharem a mesma memria ca o (Todavia, grande cuidado deve ser tomado para evitar condies co de corrida, como descrito anteriormente). Compartilhando dados em torno de processos requer o uso de mecanismos IPC a , como descrito no Cap tulo 5. Compartilhar dados em torno de processos pode ser incmodo mas faz multiplos processos parecer menos com o navegar em erros de concorrncia. e
a

Nota do tradutor:Comunicao Entre Processos. ca

119

120

Cap tulo 5 Comunicao Entre Processos ca


NO CAP ITULO 3,PROCESSOS FOI DISCUTIDO A CRIACAO DE PROCESSOS e mostrado como um processo pode obter a situao de sa ca da de um processo lho. Essa a forma mais simples de comunicao entre e ca dois processos, mas isso no signica que seja o mais poderoso. Os mecaa nismos do Cap tulo 3 no fornecem nenhum caminhos para que o processo a pai comunique-se com o processo lho a no ser atravs de argumentos de a e linha de comando e de variveis de ambiente, nem fornece tambm qualquer a e caminho para o processo lho comunicar-se com o processo pai a no ser a atravs da situao de sa do processo lho. Nenhum desses mecanismos e ca da fornece quaisquer meios para comunicao com o processo lho enquanto ele ca estiver executando, nem faz esses mecanismos permitir comunicao com um ca processo fora do relacionamento pai-lho. Esse cap tulo descreve meios para comunicao entre processos que conca tornam as limitaes descritas acima. Apresentaremos vrios caminho para co a comunicao entre pais e lhos, entre processos desaparentados, e mesmo ca entre processos em diferentes mquinas. a Comunicao entre processos (IPC)1 a transferncia de dados em meio ca e e a processos. Por exemplo, um navegador Web pode requisitar uma pgina a Web de um servidor Web, que ento envia dados no formato HTML. Essa a transferncia de dados comumente usa sockets em uma coneco semelhante e ca a `s coneces telefnicas. Em outro exemplo, voc pode desejar imprimir os co o e nomes de arquivos em um diretrio usando um comando tal como ls | lpr. o O shell cria um processo ls e um processo lpr separado, conectando os dois com um pipe, representado pelo s mbolo |. Um pipe permite comunicao ca de mo unica entre dois processos relacionados. O processo ls envia dados a para o pipe, e o processo lpr l dados a partir do pipe. e
1

Nota do tradutor:a traduo da sigla no adequada nesse caso - CEP. ca a e

121

No presente cap tulo, discutiremos cinco tipos de comunicao entre proca cessos: Memria compartilhada - permite que processos comuniquem-se o simplesmente lendo e escrevendo para uma localizao de memria ca o especicada. Memria mapeada - similar ` memria compartilhada, execeto o e a o que a memria mapeada est associada com um arquivo no sistema o a de arquivos. Pipes - permite comunicao sequncial de um processo para um ca e outro processo seu parente. FIFOs - so similares a pipes, exceto que processos no aparentados a a podem comunicar-se pelo fato de ao pipe ser fornecido um nome no sistema de arquivos. Sockets - suporta comunicao entre processos no aparentados ca a mesmo em computadores diferentes. Esses tipos de IPC diferem pelos seguintes critrios: e Se a comunicao restrita de processos aparentados (processos ca e com um ancestral comum) com processos no aparentados compara tilhando o mesmo sistema de arquivos ou com qualquer computador conectado a uma rede Se um processo de comunicao limitado a somente escrita ou ca e somente leitura de dados O nmero de processo permitidos para comunicar-se u Se os processos de comunicao so sincronizados atravs de IPC ca a e por exemplo, um processo de leitura pra at que dados estejam a e dispon veis para leitura Nesse cap tulo, omitiremos consideraes acerca de IPC permitindo comuco nicaes somente por um limitado nmero de vezes, tais como comunicao co u ca atravs de um valor de sa de processo lho. e da

5.1

Memria Compartilhada o

Um dos mais simples mtodos de comunicao entre processos o uso de e ca e memria compartilhada. Memria compartilhada permite a dois ou mais o o 122

processos acessarem a mesma memria como se todos eles tivessem chao mado malloc e tivessem obtido, como valor de retorno, apontadores para a mesma rea de memria em uso atualmente. Quando um processo modica a o a memria, todos os outros processos veem a modicao. o ca

5.1.1

Comunicao Local Rpida ca a

Memria compartilhada a forma mais rpida de comunicao entre proo e a ca cessos pelo fato de todos os processos compartilharem a mesma pea de c memria. O acesso a essa memria compartilhada to rpido quanto o o o e a a acesso a memria no compartilhada de processos, e no requer uma chao a a mada de sistema ou entrada para o kernel. A comunicao usando memria ca o compartilhada tambm evita cpias desnecessrias de informaes. e o a co Pelo fato de o kernel no sincronizar acessos ` memria compartilhada, a a o voc deve fornecer sua prpria sincronizao. Por exemplo, um processo no e o ca a deve ler a memria somente aps dados serem escritos nela, e dois processos o o no devem escrever na mesma localizao de memria ao mesmo tempo. Uma a ca o estratgia comum para evitar essas condies de corrida usar-se semforos, e co e a que sero discutidos na prxima seo. Nossos programas ilustrativos, apesar a o ca disso, mostram apenas um unico processo acessando a memria, para eviden o ciar o mecanismo de memria compartilhada e para evitar um amontoado a o amostra de cdigo com sincronizao lgica. o ca o

5.1.2

O Modelo de Memria o

Para usar um segmento de memria compartilhada, um processo deve alocar o o segmento. Ento cada processo desejando acessar o segmento deve anexar a esse mesmo segmento. Aps terminar seu uso do segmento, cada processo o desanexa o segmento. Em algum ponto, um processo deve desalocar o segmento. Entendendo o modelo de memria do GNU/Linux ajuda a explicao do o ca mecanismo de alocao e anexao. Sob GNU/Linux, cada memria virtual ca ca o usada por um processo quebrada em pginas. Cada processo mantm um e a e mapeamento de seus endereos de memria para essas pginas de memria c o a o virtual, as quais carregam os dados atuais. Alm disso cada processo tem e seus prprio endereos, mapeamentos de multiplos processos podem apontar o c para a mesma pgina, permitindo compartilhameto de memria. Pginas de a o a memria so adicionalmente discutidas na Seo 8.8,A Fam mlock : Trao a ca lia vando Memria F o sica do Cap tulo 8,Chamadas de Sistema do GNU/Linux. A alocao de um novo segmento de memria compartilhada faz com que ca o pginas de memria virtual sejam criadas. Pelo fato de todos os procesa o 123

sos desejarem acessar o mesmo segmento compartilhado, somente um processo deve alocar um novo segmento compartilhado. A alocao de um segca mento existente no cria novas pginas, mas ir retornar um identicador a a a para as pginas existentes. Para permitir a um processo usar o segmento a de memria compartilhado, um processo anexa-o, o que adiciona entradas o mapeando de sua memria virtual para as pginas compartilhadas do sego a mento. Quando termina com o segmento, essas entradas de mapeamento so removidas. Quando nenhum processo deseja acessar esses segmentos de a memria compartilhada, exatamente um processo deve desalocar as pginas o a de memria virtual. o Todos segmentos de memria compartilhada so alocados como multiplos o a inteiros do tamanho de pgina do sistema, que o nmero de ocupado por a e u uma pgina de memria. Sob sistemas GNU/Linux, o tamanho da pgina a o a e 4KB, mas voc pode obter esse valor chamando a funo getpagesize. e ca

5.1.3

Alocao ca

Um processo aloca um segmento de memria compartilhada usando shmget o (SHared Memory GET ). O primeiro parmetro a shmget uma chave a e inteira que especica qual o segmento a ser criado. Processos no aparentados a podem acessar o mesmo segmento compartilhado especicando o mesmo valor de chave inteira. Desafortunadamente, outros processos podem ter tambm e escolhido a mesma chave xada, o que pode levar a conitos. Usando a constante especial IPC PRIVATE como local de armazenamento da chave garante que um segmento de memria marcado como novo seja criado. o O segundo parmetro a shmget especica o nmero de bytes no segmento. a u Pelo fato de segmentos serem alocados usando pginas, o nmero de bytes a u alocados atualmente arredondado para cima para um inteiro multiplo do e tamanho da pgina. a O terceiro parmetro a shmget o conjunto de valores de bits ou de a e sinalizadores que especicam opes a shmget. co Os valores de sinalizadores incluem os seguintes: 124

IPC CREAT Esse sinalizador indica que um novo segmeto deve ser criado. Permite a criao de um novo segmento na mesma hora ca em que especica um valor de chave. IPC EXCL Esse sinalizador, que sempre usado com e IPC CREAT, faz com que shmget falhe se uma chave de segmento que j exista for especicada. Portanto, IPC EXCL possibilita ao a processo que est chamando ter um segmento exclusivo. Se esse a sinalizador no for fornecido e a chave de um segmento existente a for usada, shmget retorna o segmento existente ao invs de criar e um novo. Sinalizadores de modo Esse valor composto de 9 bits indicando e permisses garantidas ao dono, grupo e o restante do mundo para o controlar o acesso ao segmento. Bits de execuo so ignorados. ca a Um caminho fcil para especicar permisses usar constantes dea o e nidas no arquivo de cabealho <sys/stat.h> e documentadas na c seo 2 da pgina de manual de stat a . Por exemplo, S IRUSR e ca a o S IWUSR especicam permisses de leitura e escrita para o dono do segmento de memria compartilhada, e S IROTH e S IWOTH o especicam permisses de leitura e escrita para outros. o
Esses bits de permisso so os mesmos aqueles usados para arquivos. Eles so a a a descritos na Seo 10.3, Permisses do Sistema de Arquivos. ca o
a

Por exemplo, a chamada adiante a shmget cria um novo segmento de a memria compartilhada (ou acessa um que j existe, se shm key j estio a ver sendo usada) que pode ser lido e escrito pelo dono mas no por outros a usurios. a
int segment\_id = shmget (shm\_key, getpagesize (), IPC\_CREAT | S\_IRUSR | S\_IWUSR);

Se a chamada obtiver sucesso,shmget retorna um identicador de segmento. Se o segmento de memria compartilhada j existir, as permisses de o a o acesso so vericadas e uma conrmao feita para garantir que o segmento a ca e no seja marcado para destruio. a ca

5.1.4

Anexando e Desanexando

Para tornar o segmento de memria compartilhada dispon o vel, um processo deve usar shmat, SHared Memory ATtach. Informe a shmat o identicador de segmento de memria compartilhada SHMID retornado por shmget. O o segundo argumento um apontador que especica onde no seu espao de e c endereamento de processo voc deseja mapear a memria compartilhada; se c e o 125

voc especicar NULL, GNU/Linux ir escolher um endereo dispon e a c vel. O terceiro argumento um sinalizador, que pode incluir o seguinte: e SHM RND indica que o endereo especicado para o segundo c parmetro deve ser arredondado por baixo para um multiplo do a tamanho da pgina de memria. Se voc no especicar esse sinaa o e a lizador, voc deve ajustar conforme o tamanho da pgina o segundo e a argumento para shmat por si mesmo. SHM RDONLY indica que o segmento ir ser somente para leitura, a no para escrita. a Se a chamada obtiver sucesso, a chamada ir retornar o endereo do a c segmento compartilhado anexado. Processos lhos criados por chamadas a fork herdaro os segmentos de memria compartilhada anexados; eles podem a o desanexar os segmentos de memria anexados, se assim o desejarem. o Quando voc tiver terminado com um segmento de memria compartie o lhada, o segmento deve ser liberado usando shmdt (SHared Memory DeTach). Informe a shmdt o endereo retornado por shmat. Se o segmento c tiver sido desalocado e o processo atual for o ultimo processo usando o seg mento de memria em questo, esse segmento removido. Chamadas a exit e o a e a qualquer chamada da fam exec automaticamente desanexam segmentos. lia

5.1.5

Controlando e Desalocando Memria Compartio lhada

A chamada shmctl (SHared Memory ConTroL) retorna informaes sobre co um segmento de memria compartilhada e pode modicar o referido sego mento. O primeiro parmetro um identicador de segmento de memria a e o compartilhada. Para obter informaes sobreu um segmento de memria compartilhada, co o informe IPC STAT como o segundo argumento e um apontador para uma varivel do tipo struct chamada shmid ds. a Para remover um segmento, informe IPC RMID como o segundo argumento, e informe NULL como o terceiro argumento. O segmento removido e quando o ultimo processo que o tiver anexado nalmente o desanexe. Cada segmento de memria compartilhada deve ser explicitamente desao locado usando shmctl quando voc tiver acabado com esse mesmo segmento, e para evitar violao um limite de tamanho interno ao GNU/Linux 2 com ca
Nota do tradutor:system-wide limit conjunto de limites respeitado pelo kernel para proteger o sistema. Os limites so aplicados na quantidade de arquivos aberto por processo, a
2

126

relao ao nmero total de segmentos de memria compartilhada. Chamaca u o das a exit e exec desanexam segmentos de memria mas no os desalocam. o a Veja a pgina de manual para shmctl para uma descrio de outras a ca operaes que voc pode executar sobre segmentos de memria compartico e o lhada.

5.1.6

Um programa Exemplo

O programa na Listagem 5.1 ilustra o uso de memria compartilhada. o Listagem 5.1: Exerc de Memria Compartilhada cio o
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #include <s t d i o . h> #include <s y s /shm . h> #include <s y s / s t a t . h> i n t main ( ) { int segment id ; char shared memory ; struct shmid ds shmbuffer ; int s e g m e n t s i z e ; const i n t s h a r e d s e g m e n t s i z e = 0 x6400 ; / A l l o c a t e a s h a r e d memory s e g m e n t . / s e g m e n t i d = shmget ( IPC PRIVATE , s h a r e d s e g m e n t s i z e , IPC CREAT | IPC EXCL | S IRUSR | S IWUSR ) ; / A t t a c h t h e s h a r e d memory s e g m e n t . / shared memory = ( char ) shmat ( s e g m e n t i d , 0 , 0 ) ; p r i n t f ( s h a r e d memory a t t a c h e d a t a d d r e s s %p\n , shared memory ) ; / D e t e r m i n e t h e s e g m e n t s s i z e . / s h m c t l ( s e g m e n t i d , IPC STAT , &s h m b u f f e r ) ; segment size = shmbuffer . shm segsz ; p r i n t f ( segment s i z e : %d\n , s e g m e n t s i z e ) ; / W r i t e a s t r i n g t o t h e s h a r e d memory s e g m e n t . / s p r i n t f ( shared memory , H e l l o , w o r l d . ) ; / D e a t c h t h e s h a r e d memory s e g m e n t . / shmdt ( shared memory ) ; / R e a t t a c h t h e s h a r e d memory s e g m e n t , a t a d i f f e r e n t a d d r e s s . / shared memory = ( char ) shmat ( s e g m e n t i d , ( void ) 0 x5000000 , 0 ) ; p r i n t f ( s h a r e d memory r e a t t a c h e d a t a d d r e s s %p\n , shared memory ) ; / P r i n t o u t t h e s t r i n g f r o m s h a r e d memory . / p r i n t f ( %s \n , shared memory ) ; / D e t a c h t h e s h a r e d memory s e g m e n t . / shmdt ( shared memory ) ; / D e a l l o c a t e t h e s h a r e d memory s e g m e n t . s h m c t l ( s e g m e n t i d , IPC RMID , 0 ) ; return 0 ; } /

5.1.7

Depurando

Os comandos ipc fornecem informao sobre as facilidade da comunicao ca ca entre processos, incluindo segmentos compartilhados. Use o sinalizador -m para obter informao sobre memria compartilhada. Por exemplo, o cdigo ca o o
no tamanho de alguma mensagem do sistema, na quantidade de arquivos em uma la, etc. So obtidos com o comando sysctl -a em um slackware por exemplo. a

127

a seguir ilustra que um segmento de memria compartilhada, cujo nmero o u e 1627649, est em uso: a
% ipcs -m ------ Shared Memory Segments -------key shmid owner perms 0x00000000 1627649 user 640

bytes 25600

nattch 0

status

Se esse segmento de memria tiver sido errneamente deixado para trs o o a por um programa, voc pode usar o comando ipcrm para remov-lo. e e % ipcrm shm 1627649

5.1.8

Prs e Contras o

Segmentos de memria compartilhada permitem comunicao bidirecional o ca rpida envolvendo qualquer nmero de processos. Cada usurio pode tanto a u a ler quanto escrever, mas um programa deve estabelecer e seguir algum protocolo para prevenir condies de corrida tais como sobrescrever informao anco ca tes que essa mesma informao seja lida. Desafortunadamente, GNU/Linux ca no garante estritamente acesso exclusivo mesmo se voc criar um novo a e segmnto compartilhado com IPC PRIVATE. Tambm, para multiplos processos usarem um segmento compartilhado, e eles devem fazer arranjos para usar a mesma chave.

5.2

Semforos de Processos a

Como se nota na seo anterior, processos devem ter acesso coordenado a ca memria compartilhada. Como discutimos na Seo 4.4.5, Semforos para o ca a Linhas de Execuo no Cap ca tulo 4, Linhas de Execuo semforos so ca a a contadores que permitem sincronizar multiplas linhas de execuo. GNU/Linux ca fornece uma implementao alternativa diferente de semforos que pode ser ca a usada para sincronizar processos (chamada semforos de processo ou algumas a vezes semforos System V ). Se mforos de processo so alocados, usados, e a a a desalocados como segmentos de memria compartilhada. Embora um unico o semforo seja suciente para a maioria dos usos, semforos de processo veem a a em conjuntos. ao longo de toda essa seo, apresentamos chamadas de sisca tema para semforos de processo, mostrando como implementar semforos a a binrios simples usando essas chamadas de sistema. a 128

5.2.1

Alocao e Desalocao ca ca

As chamadas semget e semctl alocam e desalocam semforos, ambas anlogas a a a shmget e shmctl para memria compartilhada. Chame semget com uma o chave especicando um conjunto de semforo, o nmero de semforos no a u a conjunto, e sinalizadores de permisso da mesma forma que para shmget; a o valor de retorno um identicador do conjunto de semforo. Voc pode e a e obter o identicador de um conjunto de semforo existente especicando o a valor da chave respectiva; nesse caso, o nmero de semforos pode ser zero. u a Semforos continuam a existir mesmo aps todos os processos que os a o tiverem usado tenham terminado. O ultimo processo a usar um conjunto de semforo deve explicitamente remover o conjunto de forma a garantir a que o sistema operacional no desperdisse semforos. Para fazer isso, chame a a semctl com o identicador de semforo, o nmero de semforos no conjunto, a u a IPC RMID como o terceiro argumento, e qualquer valor de union semun 3 como o quarto argumento (que ignorado). O identicador efetivo do usurio e a do processo que est chamando deve coincidir com o do alocador do semforo a a (ou o chamador deve ser o superusurio). Ao contrrio do que ocorre com a a segmentos de memria compartilhada, a remoo de um conjunto de semforo o ca a faz com que GNU/Linux o desaloque imediatamente. A Listagem 5.2 mostra funes para alocar e desalocar um semforo co a binrio. a a Listagem 5.2: (sem all deall.c) Alocando e Desalocando um semforo Binrio a
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <s y s / i p c . h> #include <s y s / sem . h> #include <s y s / t y p e s . h> / We must define u n i o n semun o u r s e l v e s . /

union semun { int val ; struct semid ds buf ; unsigned short i n t a r r a y ; struct seminfo b u f ; }; / O b t a i n a b i n a r y s e m a p h o r e s ID , allocating if necessary . sem flags ) /

i n t b i n a r y s e m a p h o r e a l l o c a t i o n ( k e y t key , { return s e m g e t ( key , 1 , s e m f l a g s ) ; } / D e a l l o c a t e a b i n a r y s e m a p h o r e . All use . R e t u r n s 1 on f a i l u r e . /

int

u s e r s must h a v e

finished

their

i n t b i n a r y s e m a p h o r e d e a l l o c a t e ( i n t s e m id ) { union semun i g n o r e d a r g u m e n t ; return s e m c t l ( semid , 1 , IPC RMID , i g n o r e d a r g u m e n t ) ; }

Nota do tradutor: denido em sem.h.

129

5.2.2

Inicializando Semforos a

Alocao e inicializao so duas operaes distintas. Para inicializar um ca ca a co semforo, use semctl com zero como o segundo argumento e SETALL como a o terceiro argumento. Para quarto argumento, voc deve criar um objeto e union semun e apontar seu campo array para um array de valores inteiros curtos. Cada valor usado para inicializar um semforo no conjunto. e a A Listagem 5.3 mostra uma funo que inicializa um semforo binrio. ca a a

Listagem 5.3: (sem init.c) Inicializando um Semforo Binrio a a


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <s y s / t y p e s . h> #include <s y s / i p c . h> #include <s y s / sem . h> / We must define u n i o n semun o u r s e l v e s . /

union semun { int val ; struct semid ds buf ; unsigned short i n t a r r a y ; struct seminfo b u f ; }; / Initialize a binary semaphore with a value o f one . /

i n t b i n a r y s e m a p h o r e i n i t i a l i z e ( i n t s e m id ) { union semun argument ; unsigned short v a l u e s [ 1 ] ; values [ 0 ] = 1; argument . a r r a y = v a l u e s ; return s e m c t l ( semid , 0 , SETALL, argument ) ; }

5.2.3

Operaes Wait e Post co

Cada semforo tem um valor no negativo e suporta operaes wait e post. a a co A chamada de sistema semop implementa ambas as operaes. Seu primeiro co parmetro especica um identicador de conjunto de semforo. Seu segundo a a parmetro um array de elementos do tipo struct sembuf, que especica as a e operaes que voc deseja executar. O terceiro parmetro o comprimento co e a e desse array. Os campos de struct sembuf so listados aqui: a 130

sem num o nmero do semforo no conjunto de semforo sobre e u a a o qual a operao executada. ca e sem op um inteiro que especica a operao do semforo. e ca a Se sem op for um nmero positivo, esse nmero positivo adiciou u e nado ao valor do semforo Imediatamente. a Se sem op for um nmero negativo, o valor absoluto do nmero u u negativo subtra do valor do semforo. Se isso zer com que o e do a valor de semforo torne-se negativo, a chamada bloqueia at que o a e valor de semforo torne-se to grande quanto o valor absoluto de a a sem op (pelo fato de algum outro processo incrementar esse valor). Se sem op for zero, a operao bloqueia at que o valor do semforo ca e a torne-se zero. sem g um valor de sinalizador. Especique IPC NOWAIT para e prevenir a operao de bloquear; se a operao puder ter bloca ca queio, a chamada a semop falha ao invs disso. Se voc especicar e e SEM UNDO, GNU/Linux automaticamente desmancha a operao ca sobre o semforo quando o processo encerra. a A Listagem 5.4 ilustra operaes wait e post para um semforo binrio. co a a Listagem 5.4: (sem pv.c) Operaes Wait e Post para um Semforo co a Binrio a
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include <s y s / t y p e s . h> #include <s y s / i p c . h> #include <s y s / sem . h> / Wait on a b i n a r y s e m a p h o r e . p o s i t i v e , then decrement i t Block u n t i l b y one . / the semaphore value is

i n t b i n a r y s e m a p h o r e w a i t ( i n t s e m id ) { s t r u c t sembuf o p e r a t i o n s [ 1 ] ; / Use t h e f i r s t ( and o n l y ) s e m a p h o r e . o p e r a t i o n s [ 0 ] . sem num = 0 ; / D e c r e m e n t b y 1 . / o p e r a t i o n s [ 0 ] . sem op = 1; / P e r m i t undo i n g . / o p e r a t i o n s [ 0 ] . s e m f l g = SEM UNDO ; return semop ( semid , } / P o s t t o a b i n a r y s e m a p h o r e : returns immediately . / increment operations , 1) ;

its

value

b y one .

This

i n t b i n a r y s e m a p h o r e p o s t ( i n t s e m id ) { s t r u c t sembuf o p e r a t i o n s [ 1 ] ; / Use t h e f i r s t ( and o n l y ) s e m a p h o r e . o p e r a t i o n s [ 0 ] . sem num = 0 ; / I n c r e m e n t b y 1 . / o p e r a t i o n s [ 0 ] . sem op = 1 ; / P e r m i t undo i n g . / o p e r a t i o n s [ 0 ] . s e m f l g = SEM UNDO ; return semop ( semid , } operations , 1) ;

131

Especicando o sinalizador SEM UNDO permite lidar com o problema de terminar um processo enquanto esse mesmo processo tem recursos alocados atravs de um semforo. Quando um processo encerra, ou voluntariamente e a ou involuntriamente, o valores do semforo so automaticamente ajustados a a a para desfazer os efeitos do processo sobre o semforo. Por exemplo, se um a processo que tiver decrementado um semforo for morto, o valor do semforo a a incrementado. e

5.2.4

Depurando Semforos a

Use o comando ipcs -s para mostrar informao sobre conjuntos de semforo ca a existentes. Use o comando ipcrm sem para remover um conjunto de semaforo a partir da linha de comando. Por exemplo, para remover o conjunto de semforo com o identicador 5790517, use essa linha: a \% ipcrm sem 5790517

5.3

Arquivos Mapeados em Memria o

Memria mapeada permite a diferentes processos comunicarem-se por meio o de um arquivo compartilhado. Embora voc possa entender memria mae o peada como sendo um segmento de memria compartilhada com um nome, o voc deve ser informado que exitem diferenas tcnicas. Memria mapeada e c e o pode ser usada para comunicao entre processos ou como um caminho fcil ca a para acessar o contedo de um arquivo. u Memria mapeada forma uma associao entre um arquivo e a memria o ca o de um processo. GNU/Linux quebra o arquivo em pedaos do tamanho de c pginas de memria e ento copia esses pedaos para dentro das pginas de a o a c a memria virtual de forma que os pedaos possam se tornar dispon o c veis no espao de endereamento de um processo. Dessa forma, o processo pode ler c c o contedo do arquivo com acesso de memria comum. O processo pode u o tambm modicar o contedo do arquivo escrevendo para a memria. Esse e u o processo de leitura e escrita para a memria permite acesso rpido a arquivos. o a Voc pode entender a memria mapeada como alocao de um espao e o ca c temporrio de armazenamento para manter o contedo total de um arquivo, a u e ento lendo o arquivo na rea temporria de armazenamento e (se a rea a a a a temporria de armazenamento for modicada) escrevendo a rea temporria a a a de armazenamento de volta para o arquivo posteriormente. GNU/Linux manipula as operaes de leitura e escrita para voc. co e 132

Existem outros usos para arquivos mapeados em memria alm do uso o e para comunicao entre processos. Alguns desses outros usos so discutidos ca a na Seo 5.3.5, Outros Usos para Arquivos Mapeados em Memria. ca o

5.3.1

Mapeando um Arquivo Comum

Para mapear um arquivo comum para a memria de um processo, use a o chamada de sistema mmap (Memory MAPped pronuncia-se em-map). O primeiro argumento o endereo no qual voc gostaria que GNU/Linux e c e mapeasse o arquivo dentro do espao de endereamento do processo; o valor c c NULL permite ao GNU/Linux escolher um endereo inicial dispon c vel. O segundo argumento o comprimento do mapa em bytes. O terceiro argue mento especica a proteo sobre o intervalo de endereamento mapeado. A ca c proteo consiste de um ou bit a bit de PROT READ, PROT WRITE, ca a ca e PROT EXEC, correspondendo a permisso de leitura, escrita, e execuo, respectivamente. O quarto argumento um valor de sinalizador que especie ca opes adicionais. O quinto argumento um descritor de arquivo aberto co e para o arquivo a ser mapeado. O ultimo argumento o oset a partir do e in do arquivo do qual inicia-se o mapa. Voc pode mapear todo ou parte cio e do arquivo para dentro da memria escolhendo o oset de in e o comprio cio mento apropriadamente. O valor do sinalizador um ou bit a bit restrito aos seguintes: e MAP FIXED Caso especique esse sinalizador, GNU/Linux usa o endereo de sua requisio para mapear o arquivo em lugar de c ca tratar esse endereo como uma sugesto. Esse endereo deve ser c a c ajustado ` pgina de memria. a a o MAP PRIVATE Escritas para o intervalo de memria mapeado o no devem ser escritos de volta ao arquivo mapeado, mas para uma a cpia privada do arquivo mapeado. Nenhum outro processo v essas o e escritas. Esse modo no pode ser usado com MAP SHARED. a MAP SHARED Escritas so imediatamente reetidas no ara quivo correspondente ao invs de serem guardadas em uma rea e a temporria na memria. Use esse modo quando estiver usando a o memria mapeada em IPCa . Esse modo no pode ser usado com o a MAP PRIVATE.
a

Nota do tradutor:Inter Process Communication.

Se a chamada de sistema mmap obtiver sucesso, ir retornar um apona tador para o in da memria mapeada. Em caso de falha, a chamada de cio o sistema mmap retorna MAP FAILED. 133

Quando voc tiver terminado com a memria mapeada, libere-a usando e o munmap. Informe a munmap o endereo inicial e o comprimento da regio de c a memria mapeada. GNU/Linux automaticamente desmancha o mapeamento o das regies de memria mapeada quando um processo terminar. o o

5.3.2

Programas Exemplo

Vamos olhar em dois programas para ilustrar a utilizao de regies de ca o memria mapeada para ler e escrever em arquivos. O primeiro programa, o Listagem 5.5, gera um nmero aleatrio e escreve-o em um arquivo mapeado u o em memria. O segundo programa, Listagem 5.6, l o nmero, mostra-o, e o e u substitui seu valor no arquivo de memria mapeada com o valor dobrado. o Ambos recebem um argumento de linha de comando do arquivo a ser mapeado. Listagem 5.5: (mmap-write.c) Escreve um Nmero Aleatrio para um u o Arquivo Mapeado em Memria o
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #include < s t d l i b . h> #include <s t d i o . h> #include < f c n t l . h> #include <s y s /mman . h> #include <s y s / s t a t . h> #include <t i m e . h> #include <u n i s t d . h> #d e f i n e FILE LENGTH 0 x100 / R e t u r n a u n i f o r m l y random number i n the range [ low , h i g h ] . /

i n t r a n d o m r a n g e ( unsigned const low , unsigned const h i g h ) { unsigned const r a n g e = h i g h low + 1 ; return low + ( i n t ) ( ( ( double ) r a n g e ) rand ( ) / (RAND MAX + 1 . 0 ) ) ; } i n t main ( i n t a r g c , char const a r g v [ ] ) { int fd ; void f i l e m e m o r y ; / S e e d t h e random number g e n e r a t o r . s r a n d ( t i m e (NULL) ) ; /

/ P r e p a r e a f i l e l a r g e e n o u g h t o h o l d an u n s i g n e d i n t e g e r . f d = open ( a r g v [ 1 ] , O RDWR | O CREAT, S IRUSR | S IWUSR ) ; l s e e k ( f d , FILE LENGTH+1 , SEEK SET ) ; w r i t e ( fd , , 1) ; l s e e k ( f d , 0 , SEEK SET ) ;

/ C r e a t e t h e memorymapping . / f i l e m e m o r y = mmap ( 0 , FILE LENGTH , PROT WRITE, MAP SHARED, f d , 0 ) ; c l o s e ( fd ) ; / W r i t e a random i n t e g e r t o memorymapped a r e a . / s p r i n t f ( ( char ) f i l e m e m o r y , %d\n , r a n d o m r a n g e ( 100 , 1 0 0 ) ) ; / R e l e a s e t h e memory ( u n n e c e s s a r y s i n c e t h e p r o g r a m e x i t s ) . / munmap ( f i l e m e m o r y , FILE LENGTH) ; return 0 ; }

O programa mmap-write abre o arquivo, criando-o se ele j no existir a a previamente. O terceiro argumento a open especica que o arquivo deve ser 134

aberto para leitura e escrita. Pelo fato de no sabermos o comprimento do a arquivo, usamos lseek para garantir que o arquivo seja grande o suciente para armazenar um inteiro e ento mover de volta a posio do arquivo para a ca seu in cio. O programa mapeia o arquivo e ento fecha o descritor de arquivo pelo a fato de esse descritor no ser mais necessrio. O programa ento escreve a a a um inteiro aleatrio para a memria mapeada, e dessa forma para o arquivo, o o e desmapeia a memria. A chamada de sistema munmap desnecessria o e a pelo fato de que GNU/Linux deve automaticamente desmapear o arquivo ao trmino do programa. e Listagem 5.6: (mmap-read.c) L um Inteiro a partir de um Arquivo Mae peado em Memria, e Dobra-o o
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include < s t d l i b . h> #include <s t d i o . h> #include < f c n t l . h> #include <s y s /mman . h> #include <s y s / s t a t . h> #include <u n i s t d . h> #d e f i n e FILE LENGTH 0 x100 i n t main ( i n t a r g c , char const a r g v [ ] ) { int fd ; void f i l e m e m o r y ; int i n t e g e r ; / Open t h e f i l e . / f d = open ( a r g v [ 1 ] , O RDWR, S IRUSR | S IWUSR ) ; / C r e a t e t h e memorymapping . / f i l e m e m o r y = mmap ( 0 , FILE LENGTH , PROT READ | PROT WRITE, MAP SHARED, f d , 0 ) ; c l o s e ( fd ) ; / Read t h e i n t e g e r , p r i n t i t o u t , and d o u b l e i t . / s s c a n f ( f i l e m e m o r y , %d , &i n t e g e r ) ; p r i n t f ( v a l u e : %d\n , i n t e g e r ) ; s p r i n t f ( ( char ) f i l e m e m o r y , %d\n , 2 i n t e g e r ) ; / R e l e a s e t h e memory ( u n n e c e s s a r y s i n c e t h e p r o g r a m e x i t s ) . munmap ( f i l e m e m o r y , FILE LENGTH) ; return 0 ; }

O programa mmap-read l o nmero para fora do arquivo e ento escreve e u a o valor dobrado para o arquivo. Primeiramente, mmap-read abre o arquivo e mapeia-o para leitura e escrita. Pelo fato de podermos assumir que o arquivo grande o suciente para armazenar um inteiro sem sinal, no precisamos e a usar lseek, como no programa anterior. O programa l e informa o valor para e fora da memria usando sscanf e ento formata e escreve o valor dobrado o a usando sprintf. Aqui est um exemplo de execuo desses dois programas exemplo. Os a ca dois mapeiam o arquivo /tmp/integer-le. \% ./mmap-write /tmp/integer-file \% cat /tmp/integer-file 135

42 \% ./mmap-read /tmp/integer-file value: 42 \% cat /tmp/integer-file Observe que o texto 42 foi escrito para o arquivo de disco sem mesmo haver uma chamada ` funo write, e foi lido de volta novamente sem haver a ca uma chamada ` funo read. Note que esses programas amostra escrevem e a ca leem ponteiro como uma sequncia de caracteres (usando sprintf e sscanf ) e com propsitos didticos somente no existe necessidade de o contedo o a a u de um arquivo mapeado em memria ser texto. Voc pode armazenar e o e recuperar binrios arbitrrios em um arquivo mapeado em memria. a a o

5.3.3

Acesso Compartilhado a um Arquivo

Diferentes processos podem comunicar-se usando regies mapeadas em memria o o associadas ao mesmo arquivo. Especicamente o sinalizador MAP SHARED permite que qualquer escrita a essa regies sejam imediatamente transferidas o ao correspondente arquivo mapeado em memria e tornados vis o veis a outros processos. Se voc no especicar esse sinalizador, GNU/Linux pode colocar e a as operaes de escrita em reas temporrias de armazenamento antes de co a a transfer -las ao arquivo mapeado. Alternativamente, voc pode forar o GNU/Linux a esvaziar as reas e c a temporrias de armazenamento para o arquivo em disco chamando msync. a Os primeiros dois parmetros a msync especicam uma regio de memria a a o mapeada, da mesma forma que para munmap. O terceiro parmetro pode os a os seguintes valores de sinalizador: MS ASYNC A atualizao agendada mas no necessriamente ca e a a efetuada antes de a chamada retornar. MS SYNC A atualizao imediata; a chamada a msync bloca e queia at que a atualizao tenha sido nalizada. MS SYNC e e ca MS ASYNC no podem ambas serem usadas simultneamente. a a MS INVALIDATE Todos os outros mapeamentos so invalidados a de forma que eles possam ver os valores atualizados. Por exemplo, para descarregar a rea de armazenamento temporrio de a a um arquivo compartilhado mapeado no endereo mem addr de comprimento c mem length bytes, chame o seguinte: msync (mem_addr, mem_length, MS_SYNC | MS_INVALIDATE); 136

Da mesma forma que com segmentos de memria compartilhada, os o usurios de regies de memria mapeada devem estabelecer e seguir um proa o o tocolo para evitar condies de corrida. Por exemplo, um semforo pode ser co a usado para garantir que somente um processo acesse a regio de memria a o mapeada de cada vez. Alternativamente, voc pode usar fcntl para coloe car uma trava de leitura ou escrita no arquivo, como descrito na Seo 8.3, ca A Chamada de Sistema fcntl : Travas e Outras Operaes em Arquivosno co Cap tulo 8.

5.3.4

Mapeamentos Privados

A especicao de MAP PRIVATE a mmap cria uma regio copie-na-escrita. ca a Qualquer escrita para a regio reetida somente nessa memria do processo; a e o outros processos que mapeiam o mesmo arquivo no iro ver as modicaes. a a co Ao invs de escrever diretamente para uma pgina compartilhada por todos e a os processos, o processo escreve para uma cpia privada dessa pgina. Todas o a as leituras e escritas subsequentes feitas pelo processo usaram essa cpia o privada.

5.3.5

Outros Usos para Arquivos Mapeados em Memo ria

A chamada mmap pode ser usada para outros propsitos alm da comuo e nicao entre processos. Um uso comum uma substituio para leitura e ca e ca escrita. Por exemplo, ao invs de explicitamente ler um contedo de arquivo e u dentro da memria, um programa pode mapear o arquivo na memria e ver o o seu contedo atravs de leituras de memria. Para alguns programas, isso u e o e mais conveniente e pode tambm executar mais rapidamente que operaes e co expl citas de entrada e sa em arquivos. da Uma tcnica avanada e poderosa usada por alguns programas conse c e truir estruturas de dados (comumente instncias de estruturas, por exemplo) a em um arquivo mapeado em memria. Em uma chamada subsequnte, o o e programa mapeia aquele arquivo de volta na memria, e as estruturas de o dados so restabelecidas em seu estado anterior. Note que, apesar disso, que a apontadores nessas estruturas de dados iro ser invlidos a menos que eles a a todos apontem para dentro da mesma regio mapeada de memria e a menos a o que cuidados sejam tomados para mapear o arquivo de volta para dentro do mesma regio de endereamento que o arquivo ocupava originalmente. a c Outra tcnica usada mapear o arquivo especial de dispositivo /dev/zero e e para a memria. O arquivo /dev/zero, que descrito na Seo 6.5.2, O o e ca 137

Dispositivo /dev/zero do Cap tulo 6, Dispositivoscomporta-se como se fosse um arquivo innitamente longo preenchido com 0 bytes. Um programa que precisa uma fonte de 0 bytes pode mmap o arquivo /dev/zero. Escritas para /dev/zero so descartadas, de forma que a memria mapeada possa ser a o usada para qualquer propsito. Alocaes de memria personalizadas muitas o co o vezes mapeiam /dev/zero para obter pedaos de memria pr-inicializados. c o e

5.4

Pipes

A pipe um dispositivo de comunicao que permite comunicao unidirecie ca ca onal. Dados escritos para a escrita nal do pipe lido de volta a partir da e leitura nal. Os Pipes so dispositivos seriais; os dados so sempre lidos a a a partir do pipe na mesma ordem em que foram escritos. Tipicamente, um pipe usado para comunicao entre duas linhas de execuo em um unico e ca ca processo ou entre processos pai e lho. Em um shell, o s mbolo | cria um pipe. Por exemplo, o comando shell adiante faz com que o shell produza dois processos lhos, um para o comando ls e outros para o comando less: \% ls | less O shell tambm cria um pipe conectando a sa padro do subprocesso e da a ls com a entrada padro do processo less. Os nomes de arquivos listados a pelo ls so enviados para o less na exatamente mesma ordem como se a eles tivessem sido enviados diretamente para o terminal. A capacidade de dados do pipe limitada. Se o processo escritor escreve e mais rapidamente que o processo leitor pode consumir os dados, e se o pipe no puder armazenar mais dados, o processo escritor blioqueia at que mais a e capacidade torne-se dispon vel. Se o leitor tenta ler mas nenhum dado a ser lido est dispon a vel, o processo leitor bloqueia at que dados tornem-se dise pon veis. Dessa forma, o pipe automaticamente sincroniza os dois processos.

5.4.1

Criando Pipes

Para criar um pipe, chame o comando pipe. Fornea um array de inteiros de c tamanho 2. A chamada a pipe armazena o descritor do arquivo de leitura na posio 0 do array e o descritor do arquivo de escrita na posio 1. Por ca ca exemplo, considere o cdigo abaixo: o int pipe_fds[2]; int read_fd; 138

int write_fd; pipe (pipe_fds); read_fd = pipe_fds[0]; write_fd = pipe_fds[1];

Dados escritos para o descritor de arquivo write fd podem ser lidos de volta a partir de read fd.

5.4.2

Comunicao Entre Processos Pai e Filho ca

Uma chamada a pipe cria descritores de arquivo, os quais so vlidos somente a a dentro do referido processo e seus lhos. Descritores de arquivo de processo no podem ser informados a processos no aparentados; todavia, quando o a a processo chama fork, descritores de arquivo so copiados para o novo processo a lho. Dessa forma, pipes podem conectar somente com processos parentes. No programa na Listagem 5.7, um fork semeia um processo lho. O lho herda os descritores de arquivo do pipe. O pai escreve uma sequncia de e caracteres para o pipe, e o lho l a sequncia de caracteres. O programa de e e amostra converte esses descritores de arquivo em uxos FILE* usando fdop en. Pelo fato de usarmos uxos ao invs de descritores de arquivo, podemos e usar funes de entrada e sa da biblioteca C GNU padro de n mais co da a vel alto tais como printf e fgets. 139

Listagem 5.7: (pipe.c) Usando um pipe para Comunicar-se com um Processo Filho
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 #include < s t d l i b . h> #include <s t d i o . h> #include <u n i s t d . h> / W r i t e COUNT c o p i e s between each . / o f MESSAGE t o STREAM, pausing f o r a second

void w r i t e r ( const char message , i n t count , FILE s t r e a m ) { f o r ( ; c o u n t > 0 ; c o u n t ) { / W r i t e t h e m e s s a g e t o t h e s t r e a m , and s e n d i t o f f i m m e d i a t e l y . f p r i n t f ( stream , %s \n , m e s s a g e ) ; f f l u s h ( stream ) ; / S n o o z e a w h i l e . / sleep (1) ; } } / Read random strings from t h e stream as long as possible . /

void r e a d e r ( FILE s t r e a m ) { char b u f f e r [ 1 0 2 4 ] ; / Read u n t i l we h i t t h e end o f t h e s t r e a m . f g e t s reads u n t i l e i t h e r a n e w l i n e o r t h e endo f f i l e . / while ( ! f e o f ( s t r e a m ) && ! f e r r o r ( s t r e a m ) && f g e t s ( b u f f e r , s i z e o f ( b u f f e r ) , s t r e a m ) != NULL) fputs ( buffer , stdout ) ; } i n t main ( ) { int f d s [ 2 ] ; p i d t pid ; / C r e a t e a p i p e . F i l e d e s c r i p t o r s f o r t h e two ends o f t h e p i p e a r e placed in fds . / pipe ( fds ) ; / F o r k a c h i l d p r o c e s s . / pid = f o r k ( ) ; i f ( p i d == ( p i d t ) 0 ) { FILE s t r e a m ; / T h i s i s t h e c h i l d p r o c e s s . C l o s e o u r c o p y o f t h e w r i t e end o f the f i l e descriptor . / close ( fds [ 1 ] ) ; / C o n v e r t t h e r e a d f i l e d e s c r i p t o r t o a FILE o b j e c t , and r e a d from i t . / stream = fdopen ( f d s [ 0 ] , r ) ; r e a d e r ( stream ) ; close ( fds [ 0 ] ) ; } else { / T h i s i s t h e p a r e n t p r o c e s s . / FILE s t r e a m ; / C l o s e o u r c o p y o f t h e r e a d end o f t h e f i l e d e s c r i p t o r . / close ( fds [ 0 ] ) ; / C o n v e r t t h e w r i t e f i l e d e s c r i p t o r t o a FILE o b j e c t , and w r i t e to i t . / s t r e a m = f d o p e n ( f d s [ 1 ] , w ) ; w r i t e r ( Hello , world . , 5 , stream ) ; close ( fds [ 1 ] ) ; } return 0 ; }

No in da main, a varivel fds declarada como sendo do tipo array cio a e inteiro de tamanho 2. A chamada a pipe cria um pipe e coloca os descritores de arquivo de leitura e de escrita naquele array. O programa ento faz um a fork no processo lho. Aps o fechamento da leitura nal do pipe, o processo o pai inicia escrevendo sequncias de caractere para o pipe. Aps o fechamento e o 140

da escrita nal do pipe, o lho l sequncias de caractere a partir do pipe. e e Note que aps a escrita na funo escritora, o pai esvazia o pipe atravs o ca e de chamada a ush. De outra forma, a sequncia de caracteres pode no ter e a sido enviada imediatamente atravs do pipe. e Quando voc chama o comando ls | less, dois forks ocorrem: um para e o processo lho ls e um para processo lho less. Ambos esses processos herdam o descritores de arquivo do pipe de forma que eles podem comunicarse usando um pipe. Para ter processos no aparentados comunicando-se use a um FIFO ao invs de pipe, como discutido na Seo 5.4.5, FIFOs. e ca

5.4.3

Redirecionando os Fluxos da Entrada Padro, da a Sa Padro e de Erro da a

Frequentemente, voc no ir querer criar um processo lho e escolher o nal e a a de um pipe bem como suas entrada padro e sua sa padro. Usando a a da a chamada dup2, voc pode equiparar um descritor de arquivo a outro. Por e exemplo, para redirecionar a sa padro de um processo para um descritor da a de arquivo fd, use a seguinte linha:

dup2 (fd, STDIN\_FILENO);

A constante simblica STDIN FILENO representa o descritor para a eno trada padro, cujo valor 0. A chamada fecha a entrada padro e ento a e a a reabre-a com uma duplicata de fd de forma que os dois caminhos possam ser usados alternadamente. Descritores de arquivos equiparados compartilham a mesma posio de arquivo e o mesmo conjunto de sinalizadores de situao ca ca atual do arquivo. Dessa forma, caracteres lidos a partir de fd no so lidos a a novamente a partir da entrada padro. a O programa na Listagem 5.8 usa dup2 para enviar a sa de um pipe da 4 para o comando sort . Aps criar um pipe, o programa efetua um fork. O o processo pai imprime algumas sequncias de caractere para o pipe. O processo e lho anexa o descritor de arquivo de leitura do pipe para sua entrada padro a usando dup2. O processo lho ento executa o programa sort. a
O comando sort l linhas de texto a partir da entrada padro, ordena-as em ordem e a alfabtica, e imprime-as para a sa padro. e da a
4

141

Listagem 5.8: (dup2.c) Redirecionar a Sa de um pipe com dup2 da


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include #include #include #include <s t d i o . h> <s y s / t y p e s . h> <s y s / w a i t . h> <u n i s t d . h>

i n t main ( ) { int f d s [ 2 ] ; p i d t pid ; / C r e a t e a p i p e . F i l e d e s c r i p t o r s f o r t h e two ends o f t h e p i p e a r e placed in fds . / pipe ( fds ) ; / F o r k a c h i l d p r o c e s s . / pid = f o r k ( ) ; i f ( p i d == ( p i d t ) 0 ) { / T h i s i s t h e c h i l d p r o c e s s . C l o s e o u r c o p y o f t h e w r i t e end o f the f i l e descriptor . / close ( fds [ 1 ] ) ; / C o n n e c t t h e r e a d end o f t h e p i p e t o s t a n d a r d i n p u t . / dup2 ( f d s [ 0 ] , STDIN FILENO ) ; / R e p l a c e t h e c h i l d p r o c e s s w i t h t h e s o r t p r o g r a m . / execlp ( s o r t , s o r t , 0) ; } else { / T h i s i s t h e p a r e n t p r o c e s s . / FILE s t r e a m ; / C l o s e o u r c o p y o f t h e r e a d end o f t h e f i l e d e s c r i p t o r . / close ( fds [ 0 ] ) ; / C o n v e r t t h e w r i t e f i l e d e s c r i p t o r t o a FILE o b j e c t , and w r i t e to i t . / s t r e a m = f d o p e n ( f d s [ 1 ] , w ) ; f p r i n t f ( stream , T h i s i s a t e s t . \ n ) ; f p r i n t f ( stream , H e l l o , w o r l d . \ n ) ; f p r i n t f ( stream , My dog h a s f l e a s . \ n ) ; f p r i n t f ( stream , T h i s program i s g r e a t . \ n ) ; f p r i n t f ( stream , One f i s h , two f i s h . \ n ) ; f f l u s h ( stream ) ; close ( fds [ 1 ] ) ; / Wait f o r t h e c h i l d p r o c e s s t o f i n i s h . / w a i t p i d ( pid , NULL, 0 ) ; } return 0 ; }

5.4.4

As Funes popen e pclose co

Um uso comum de pipes enviar dados para ou receber dados de um proe grama sendo executado em um sub-processo. As funes popen e pclose co facilitam esse paradigma por meio da eliminao da necessidade de chamar ca pipe, fork, dup2, exec, e fdopen. Compare a Listagem 5.9, que utiliza popen e pclose, com o exemplo anterior (a Listagem 5.8). 142

Listagem 5.9: (popen.c) Exemplo Usando popen


1 2 3 4 5 6 7 8 9 10 11 12 13 #include <s t d i o . h> #include <u n i s t d . h> i n t main ( ) { FILE s t r e a m = popen ( s o r t , w ) ; f p r i n t f ( stream , T h i s i s a t e s t . \ n ) ; f p r i n t f ( stream , H e l l o , w o r l d . \ n ) ; f p r i n t f ( stream , My dog h a s f l e a s . \ n ) ; f p r i n t f ( stream , T h i s program i s g r e a t . \ n ) ; f p r i n t f ( stream , One f i s h , two f i s h . \ n ) ; return p c l o s e ( s t r e a m ) ; }

A chamada a popen cria um processo lho executando o comando sort, substituindo chamadas a pipe, fork, dup2, e execlp. O segundo argumento, w, indica que o processo que fez a chamada a popen espera escrever para o processo lho. O valor de retorno de popen um m de pipe; o outro nal e e conectado ` entrada padro do processo lho. Aps a escrita terminar, pclose a a o fecha o uxo do processo lho, espera que o processo encerre, e retorna valor de situao atual. ca O primeiro argumento a popen executado como um comando shell em e um sub-processo executando /bin/sh. O shell busca pela varivel de ambia ente PATH pelo caminho usual para encontrar programas executveis. Se a o segundo argumento for r, a funo retorna o uxo de sa padro do ca da a processo lho de forma que o processo pai possa ler a sa da. Se o segundo argumento for w, a funo retorna o uxo de entrada padro do processo ca a lho de forma que o processo pai possa enviar dados. Se um erro ocorrer, popen retorna um apontador nulo. Chama pclose para fechar um uxo retornado por popen. Aps fechar o o uxo especicado, pclose espera pelo m do processo lho.

5.4.5

FIFOs

Um arquivo rst-in, rst-out (FIFO)5 um pipe que tem um nome no sistema e de arquivos. Qualquer processo pode abrir ou fechar o FIFO; os processo em cada lado do pipe precisam ser aparentados uns aos outos. FIFOs so a tambm chamados pipes com nomes. e Voc cria um FIFO usando o comando mkfo. Especique o caminho do e FIFO na linha de comando. Por exemplo, para criar um FIFO em /tmp/fo voc deve fazer o seguinte: e
\% mkfifo /tmp/fifo \% ls -l /tmp/fifo prw-rw-rw1 samuel

users

0 Jan 16 14:04 /tmp/fifo

Nota do tradutor:Quem entrar primeiro sai tambm primeiro. e

143

O primeiro caractere da sa do comando ls uma letra p, indicando da e que esse arquivo atualmente um FIFO (pipe com nome). Em uma janela, e leia a partir do FIFO usando o seguinte: \% cat < /tmp/fifo Em uma segunda janela, escreva para o FIFO fazendo o seguinte: \% cat > /tmp/fifo Ento digite algumas linhas de texto. A cada vez que voc pressionar a e Enter, a linha de texto enviada atravs do FIFO e aparece na primeira e e janela. Feche o FIFO pressionando Ctrl+D na segunda janela. Remova o FIFO com a seguinte linha: \% rm /tmp/fifo 5.4.5.1 Criando um FIFO

Criar um FIFO a partir de um programa em linguagem C use a funo mkca 6 fo . O primeiro argumento a localizao na qual criar o FIFO; o segundo e ca parmetro especica o dono do pipe, o grupo ao qual pertence o group, e as a permisses para o resto do mundo, como discutido no Cap o tulo 10, Segurana na Seo 10.3, Permisses do Sistema de Arquivo. Pelo fato de um c ca o pipe possuir obrigatriamente um leitor e um escritor, as permisses devem o o incluir ambas tanto para leitura quanto para escrita. Se o pipe no puder a ser criado (por exemplo, se um arquivo com o nome escolhido para o pipe j a exista), mkfo retorna -1. Inclua os arquivos de cabealho <sys/types.h> e c <sys/stat.h> se voc chamar a funo mkfo. e ca 5.4.5.2 Accessando um FIFO

Acesse um FIFO da mesma forma que feita com arquivos comuns. Para e comunicar-se atravs de um FIFO, um programa deve abr para escrita, e -lo e outro programa deve abr para leitura. Ou ainda usando as funes de -lo co entra e sa de baixo n da vel (open, write, read, close, e assim por diante, como listado no apndice B, E/S de Baixo N e vel) ou as funes de E/S co da bilioteca C (fopen, fprintf, fscanf, fclose, e assim por diante) podem ser usadas. Por exemplo, para escrever uma rea temporria de armazenamento de a a dados para um FIFO usando rotinas de E/S de baixo n vel, voc pode usar e o cdigo abaixo: o
6

Nota do tradutor:para mais informaes use o comando shell man 3 mkfo. co

144

int f d = open ( f i f o p a t h , O WRONLY) ; w r i t e ( fd , data , d a t a l e n g t h ) ; c l o s e ( fd ) ; Para ler uma sequncia de caracteres a partir do FIFO usando as funes e co de E/S da biblioteca C GNU padro, voc pode usar o cdigo abaixo: a e o FILE f i f o = f o p e n ( f i f o p a t h , r ) ; f s c a n f ( f i f o , %s , b u f f e r ) ; fclose ( fifo ); Um FIFO pode ter multiplos leitores ou multiplos escritores. Os Bytes de cada escritor so escritos automaticamente at alcanar o mximo tamanho a e c a de PIPE BUF (4KB no GNU/Linux). Pedaos de escritas sumultneas pode c a ser intercalados. Regras similares aplicam-se a leituras simultnea. a Dierenas de Pipes nomeados do Windows c Pipes no sistemas operacionais Win32 so muito similares a pipes em a GNU/Linux. (Reporte-se ` documentao de biblioteca do Win32 para dea ca talhes tcnicos sobre isso.) As principais diferenas referem-se a pipes nomee c ados, os quais, para Win32, funcionam mais como sockets. Pipes nomeados em Win32 podem conectar processos em cmputadores separados conectados via rede. Em GNU/Linux, sockets so usados para esse propsito. Tambm, a o e Win32 permite multiplas coneces de leitura e escrita por meio de pipe co nomeado sem intercalao de dados, e pipes podem ser usados para comuca nicao em mo dupla.7 ca a

5.5

Sockets

Um socket um dispositivo de coneco bidirecional que pode ser usado para e ca comunicar-se com outro processo na mesma mquina ou com um processo a em outras mquinas. Sockets so o unico tipo de comunicao entre processo a a ca que discutiremos nesse cap tulo que permite comunicao entre processos em ca dirferentes computadores . Programas de Internet tais como Telnet, rlogin, FTP, talk, e a World Wide Web usam sockets. Por exemplo, voc pode obter a pgina WWW de um servidor Web e a usando o programa Telnet pelo fato de eles ambos (servidor WWW e Telnet do cliente) usarem sockets para comunicaes em rede.8 Para abrir uma co
Note que somente Windows NT pode criar um pipe nomeado; programas Windows 9x pode formar somente coneces como cliente. co 8 Comumente, poderia usar telnet para conectar um servidor Telnet para acesso remoto. Mas voc pode tambm usar o telnet para conectar um servidor de um tipo diferente e e e ento digitar comentrios diretamete no prprio telnet. a a o
7

145

coneco com um servidor WWW localizado em www.codesourcery.com, use ca telnet www.codesourcery.com 80. A constante mgica 80 especica uma coa neco para o programa de servidor Web executando www.codesourcery.com ca ao invs de algum outro processo. Tente digitar GET / aps a coneco e o ca ser estabelecida. O comando GET / envia uma mensagem atravs do e socket para o servidro Web, o qual responde enviando o cdigo fonte em na o linguagem HTML da pgina inicial fechando a coneco em seguida: a ca
\% telnet www.codesourcery.com 80 Trying 206.168.99.1... Connected to merlin.codesourcery.com (206.168.99.1). Escape character is ^]. GET / <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> ...

5.5.1

Conceitos de Socket

Quando voc cria um socket, voc deve especicar trs parmetros: o estilo e e e a da comunicao,o escopo, e o protocolo. ca Um estilo de comunicao controla como o socket trata dados transmitica dos e especica o nmero de parceiros de comunicao. Quando dados so u ca a enviados atravs de um socket, esses dados so empacotados em partes menoe a res chamadas pacotes. O estilo de comunicao determina como esses pacotes ca so manuseados e como eles so endereados do emissor para o receptor. a a c Estilos de coneco garantem a entrega de todos os pacotes na orca dem que eles foram enviados. Se pacotes forem perdidos ou reordenados por problemas na rede, o receptor automaticamente requisita a retransmisso desses pacotes perdidos/reordenados ao emissor. a Um socket de estilo do tipo coneco como uma chamada teca e lefnica: O endereo do emissor e do receptor so xados no in o c a cio da comunicao quando a coneco estabelecida. ca ca e Um socket de estilo do tipo datagrama no garante a entrega ou a a ordem de chegada. Pacotes podem ser perdidos ou reordenados no caminho devido a erros de rede ou outras condies. Cada paco cote deve ser rotulado com seu destino e no garantido que seja a e entregue. O sistema garante somente o melhor esforo de forma c que pacotes podem desaparecer ou chegar em uma ordem diferente daquela que foi transportado. Um estilo de transmisso do tipo a datagram socket comporta-se mais como vrias cartas colocadas a na agncia de correio. O emissor especica o endereo do receptor e c para cada carta individualmente. 146

Um escopo de socket especica como endereos de socket so escritos. Um c a endereo de socket identica a outra extremidade de uma coneco de socket. c ca Por exemplo, endereos de socket no espao de endereamento localso c c c a comumente nomes de arquivo comuns. No escopo de Internet um endereo c de socket composto do endereo Internet (tambm conhecido como um e c e endereo de protocolo de Internet ou endereo IP) de uma mquina anexada c c a a ` rede e um nmero de porta. O nmero de porta faz distino no conjunto u u ca de multiplos sockets na mesma mquina. a Um protocolo especica como dados so transmitidos. Alguns protocolos a so TCP/IP, os protocolos primrios usados pela Internet ; o protocolo de a a rede AppleTalk ; e o protocolo de comunicao local UNIX. Algumas comca binaes de estilos, escopo, e protocolos no so suportadas. co a a

5.5.2

Chamadas de Sistema

Os Sockets so mais ex a veis que as tcnicas de comunicao discutidas ane ca teriormente. Adiante temos as chamadas de sistema relacionadas a sockets 9 : socket Cria um socket close Destri um socket o connect Cria uma coneco entre dois sockets ca bind Rotula um socket de servidor com um endereo c listen Congura um socket para aceitar condies co accept Aceita uma coneco e cria um novo socket para a coneco ca ca Sockets so representados por descritores de arquivo. a Criando e Destruindo Sockets As funes socket e close criam e destroem sockets, respectivamente. co Quando voc cria um socket, especica as trs escolhas de socket: escopo, e e estilo de comunicao, e protocolo. Para o parmetro de escopo, use consca a tantes iniciando por PF (abreviatura de protocol families). Por exemplo, PF LOCAL ou PF UNIX especicam o escopo local, e PF INET especicam escopos de Internet . Para o parmetro de estilo de comunicao, use a ca constantes iniciando com SOCK . Use SOCK STREAM para um socket de
Nota do tradutor: no slackware 13.1 padro o comando man 2 socketcall retorna, a entre outras coisas: accept(2), bind (2), connect(2), getpeername(2), getsockname(2), getsockopt(2), listen(2), recv (2), recvfrom(2), recvmsg(2), send (2), sendmsg(2), sendto(2), setsockopt(2), shutdown(2), socket(2), socketpair (2).
9

147

estilo do tipo coneco, ou use SOCK DGRAM para um socket de estilo do ca tipo datagrama. O terceiro parmetro, o protocolo, especica o mecanismo de baixo n a vel para transmitir e receber dados. Cada protocolo vlido para uma come a binao particular de estilo e escopo. Pelo fato de existir habitualmente um ca melhor protocolo para cada tal par de estilo e espao de endereamento, espec c cicar 0 (zero) comumente o protocolo correto. Se o socket obtiver sucesso, e ele retornar um descritor de arquivo para o socket. Voc pode ler de ou esa e crever para o socket usando read, write, e assim por diante, como com outro descritor de arquivo. Quando voc tiver terminado com um socket, chame e close para remov-lo. e Chamando connect Para criar uma coneco entre dois sockets, o cliente chama connect, especa cicando o endereo de um socket de servidor para conectar-se. Um cliente c e o processo que inicia a coneco, e um servidor um processo esperando para ca e aceitar coneces. O cliente chama connect para iniciar uma coneco de um co ca socket local para o socket de servidor especicado pelo segundo argumento. O terceiro argumento o comprimento, em bytes, da estrutura de endereo e c apontada pelo segundo argumento. O formato de endereo de socket difere c conforme o escopo do socket. Enviando Informaes co Qualquer tcnica para escrever para um descritor de arquivos pode ser e usada para para escrever para um socket. Veja o Apndice B para uma dise curso sobre funo de E/S de baixo n do GNU/Linux e algumas questes a ca vel o envolvendo seu uso. A funo send, que espec ca e ca para descritores de arquivo de socket, fornece uma alternativa pra escrever com poucas escolhas adicionais; veja a pgina de manual de send para mais informaes10 . a co

5.5.3

Servidores

Um ciclo de vida de um servidor consiste da criao de um socket de estilo ca do tipo coneco, associao de um endereo a esse socket, colocao de uma ca ca c ca chamada pra escutar e que habilita coneces para o socket, colocao de chaco ca madas para aceitar coneces de entrada, e nalmente fechamento do socket. co Dados no so lidos e escritos diretamente via socket do servidor; ao invs a a e disso, a cada vez que um programa aceita uma nova coneco, GNU/Linux ca cria um socket em separado para usar na transferncia de dados sobre aquela e conneco. Nessa seo, introduziremos as chamadas de sistema bind, listen, ca ca e accept.
10

Nota do tradutor: man 2 send.

148

Um endereo deve ser associado ao socket do servidor usando bind se for c para um cliente encontr-lo. O primeiro argumento de bind o descritor de a e arquivo do socket. O segundo argumento de bind um apontador para uma e estrutura de endereo de socket; o formato desse segundo argumento depende c da fam de endereo do socket. o terceiro argumento o comprimento da lia c e estrutura de endereo, em bytes. Quando um endereo associado a um c c e socket de estido do tipo coneco, esse socket de estido do tipo coneco ca ca deve chamar listen para indicar que esse socket de estido do tipo coneco ca um servidor. O primeiro argumento ` chamada listen o descritor de e a e arquivo do socket. O segundo argumento a listen especica quantas coneces co pendentes so enleiradas. Se a la estiver cheia, coneces adicionais iro ser a co a rejeitadas. Essa rejeio de coneces no limita o nmero total de coneces ca co a u co que um servidor pode manipular; Essa rejeio de coneces limita o nmero ca co u de clientes tentando conectar que no tiveram ainda aceitao. a ca Um servidor aceita uma requisio de coneco de um cliente por meio de ca ca uma chamada ` chamada de sistema accept. O primeiro argumento a accept a e o descritor de arquivo do socket. O segundo argumento a accept aponta para uma estrutura de endereo de socket, que preenchida com o endereo de c e c socket do cliente. O terceiro argumento a accept o comprimento, em bites, e de uma estrutura de endereo de socket. O servidor pode usar o endereo do c c cliente para determinar se o socket servidor realmente deseja comunicar-se com o cliente. A chamada a accept cria um novo socket para comunicao ca com o cliente e retorna o correspondente descritor de arquivos. O socket servidor original continua a accept novas coneces de outros clientes. Para co ler dados de um socket sem remover esse socket da la de entrada, use recv. A chamada recv recebe os mesmos argumentos que a chamada read, mas adicionalmente o argumento FLAGS. Um sinalizador do tipo MSG PEEK faz com que dados sejam lidos mas no removidos da la de entrada. a

5.5.4

Sockets Locais

Sockets conectando processos no mesmo computador podem usar o escopo local representado pelos sinnimos PF LOCAL e PF UNIX. Sockets coneco tando processos no mesmo computador so chamados sockets locais ou soca kets de dom UNIX. Seus endereos de socket, especicados por nomes de nio c arquivo, so usados somente quando se cria coneces. a co O nome de socket especicado em struct sockaddr un. Voc deve escoe e lher o campo sun family para AF LOCAL, indicando que o nome do socket s vlido no escopo local. O campo sun path especica o nome de arquivo oe a que vai ser usado e pode ser, no mximo, do comprimento de 108 bytes. O a comprimento atual de struct sockaddr un deve ser calculado usando a ma149

cro SUN LEN. Qualquer nome de arquivo pode ser usado, mas o processo deve ter permisso de escrita no diretrio, o que permite a adio de arquia o ca vos ao diretrio. Para conectar um socket, um processo deve ter permisso o a de leitura para o arquivo. Mesmo atravs de diferentes computadores come partilhando o mesmo sistema de arquivos, somente processos executando no mesmo computador podem comunicar-se com sockets de escopo local. O unico protocolo permitido para o escopo local 0 (zero). e Pelo fato de residir no sistema de arquivos, um socket local listado como e um arquivo. Por exemplo, preste ateno o s inicial: ca

\% ls -l /tmp/socket srwxrwx--x 1 user

group

0 Nov 13 19:18 /tmp/socket

Chame unlink para remover um socket local quando voc tiver encerrado e com o referido socket local.

5.5.5

Um Exemplo Usando um Sockets de Escopo local

Ilustraremos sockets com dois programas. O programa do servidor, na Listagem 5.10, cria um socket de escopo local e escuta ` espera de coneces a a co esse socket de escopo local. Quando esse socket de escopo local recebe uma coneco, ele l mensagens de texto a partir da coneco e mostra-as at que ca e ca e a coneco feche. Se uma das mensagens recebidas pelo socket do servidor ca for quit o programa do servidor remove o socket e termina. O programa socket-server recebe o caminho para o socket como seu argumetnode linha de comando. 150

Listagem 5.10: (socket-server.c) Servidor de Socket de Escopo Local


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 #include #include #include #include #include #include <s t d i o . h> < s t d l i b . h> < s t r i n g . h> <s y s / s o c k e t . h> <s y s /un . h> <u n i s t d . h> out . Continue u n t i l the c l i e n t sent a quit

/ Read t e x t f r o m t h e s o c k e t and p r i n t i t socket closes . R e t u r n nonz e r o i f t h e message , z e r o o t h e r w i s e . / int s e r v e r ( int { while ( 1 ) { int length ; char t e x t ; client socket )

/ F i r s t , r e a d t h e l e n g t h o f t h e t e x t m e s s a g e f r o m t h e s o c k e t . read r e t u r n s zero , the c l i e n t c l o s e d the connection . / i f ( r e a d ( c l i e n t s o c k e t , &l e n g t h , s i z e o f ( l e n g t h ) ) == 0 ) return 0 ; / A l l o c a t e a b u f f e r t o h o l d t h e t e x t . / t e x t = ( char ) m a l l o c ( l e n g t h ) ; / Read t h e t e x t i t s e l f , and p r i n t i t . / read ( c l i e n t s o c k e t , text , length ) ; p r i n t f ( %s \n , t e x t ) ; / F r e e t h e b u f f e r . / free ( text ) ; / I f t h e c l i e n t s e n t t h e m e s s a g e q u i t , we r e a l l d o n e . / i f ( ! strcmp ( text , q u i t ) ) return 1 ; } } i n t main ( i n t a r g c , char const a r g v [ ] ) { const char const s o c k e t n a m e = a r g v [ 1 ] ; int s o c k e t f d ; s t r u c t s o c k a d d r u n name ; int c l i e n t s e n t q u i t m e s s a g e ; / C r e a t e t h e s o c k e t . / s o c k e t f d = s o c k e t (PF LOCAL , SOCK STREAM, / I n d i c a t e t h i s i s a s e r v e r . / name . s u n f a m i l y = AF LOCAL ; s t r c p y ( name . s u n p a t h , s o c k e t n a m e ) ; b i n d ( s o c k e t f d , &name , SUN LEN (&name ) ) ; / L i s t e n f o r c o n n e c t i o n s . / l i s t e n ( soc ke t fd , 5) ;

If

0) ;

/ R e p e a t e d l y a c c e p t c o n n e c t i o n s , s p i n n i n g o f f one s e r v e r ( ) t o d e a l with each c l i e n t . Continue u n t i l a c l i e n t sends a q u i t message . do { struct sockaddr un c l i e n t n a m e ; socklen t client name len ; int c l i e n t s o c k e t f d ;

/ A c c e p t a c o n n e c t i o n . / c l i e n t s o c k e t f d = a c c e p t ( s o c k e t f d , &c l i e n t n a m e , &c l i e n t n a m e l e n ) ; / H a n d l e t h e c o n n e c t i o n . / client sent quit message = server ( client socket fd ) ; / C l o s e o u r end o f t h e c o n n e c t i o n . / close ( client socket fd ) ; } while (! client sent quit message ) ; /

/ Remove t h e s o c k e t f i l e . close ( socket fd ) ; unlink ( socket name ) ; return 0 ; }

O programa cliente, na Listagem 5.11, conecta a umsocket de escopo local e envia uma mensagem. O nome path para o socket e a mensagem so a especicados na linha de comando. 151

Listagem 5.11: (socket-client.c) Cliente de Socket de Escopo Local


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #include #include #include #include #include <s t d i o . h> < s t r i n g . h> <s y s / s o c k e t . h> <s y s /un . h> <u n i s t d . h> the socket given by file d e s c r i p t o r SOCKET FD . /

/ W r i t e TEXT t o

void w r i t e t e x t ( i n t s o c k e t f d , const char t e x t ) { / W r i t e t h e number o f b y t e s i n t h e s t r i n g , i n c l u d i n g NUL e r m i n a t i o n . t / int length = s t r l e n ( text ) + 1 ; w r i t e ( s o c k e t f d , &l e n g t h , s i z e o f ( l e n g t h ) ) ; / W r i t e t h e s t r i n g . / write ( socket fd , text , length ) ; } i n t main ( i n t a r g c , char const a r g v [ ] ) { const char const s o c k e t n a m e = a r g v [ 1 ] ; const char const m e s s a g e = a r g v [ 2 ] ; int s o c k e t f d ; s t r u c t s o c k a d d r u n name ; / C r e a t e t h e s o c k e t . / s o c k e t f d = s o c k e t (PF LOCAL , SOCK STREAM, 0 ) ; / S t o r e t h e s e r v e r s name i n t h e s o c k e t a d d r e s s . / name . s u n f a m i l y = AF LOCAL ; s t r c p y ( name . s u n p a t h , s o c k e t n a m e ) ; / C o n n e c t t h e s o c k e t . / c o n n e c t ( s o c k e t f d , &name , SUN LEN (&name ) ) ; / W r i t e t h e t e x t on t h e command l i n e t o t h e s o c k e t . / w r i t e t e x t ( s o c k e t f d , message ) ; close ( socket fd ) ; return 0 ; }

Antes de o cliente enviar uma mensagem de texto, ele envia o comprimento do texto que pretende enviar mandando bytes da varivel inteira a length. Da mesma forma, o servidor l o comprimento do texto a partir e do socket de dentro da varivel inteira. Isso permite ao servidor alocar uma a a rea temporria de armazenamento de tamanho apropriado para manter a a mensagem de texto antes de l-la a partir do socket. e Para tentar esse exemplo, inicie o programa servidor em uma janela. Especique um caminho para o socket por exemplo, /tmp/socket. \% ./socket-server /tmp/socket Em outra janela, execute o cliente umas poucas vezes, especicando o mesmo caminho de socket adicionando mensagens para enviar para o servidor: \% ./socket-client /tmp/socket Hello, world." \% ./socket-client /tmp/socket This is a test." O programa servidor recebe e imprime as mensagens acima. Para fechar o servidor, envie a menssagem quit a partir de um cliente: \% ./socket-client /tmp/socket quit" O programa servidor termina. 152

5.5.6

Sockets de Dom nio Internet

Sockets de dom UNIX podem ser usados somente para comunicao entre nio ca dois processos no mesmo computador. Sockets de dom Internet , por ounio tro lado, podem ser usados para conectar processos em diferentes mquinas a conectadas por uma rede. Sockets conectando processos atravs da Internet e usam o escopo de Internet representado por PF INET. Os protocolos mais comuns so TCP/IP. O protocolo Internet (IP), um protocolo de baixo n a vel, move pacotes atravs da Internet , quebrando em pedaos e remontando os e c pedaos, se necessrio. O IP garante somente melhor esforo de entrega, c a c de forma que pacotes podem desaparece ou serem reordenados durante o transporte. Todo computador participante especicando usando um unico e nmero IP. O Protocolo de Controle de Transmisso (TCP), formando uma u a camada sobre o IP, fornece transporte convel no que se refere a ordenao a ca na coneco. Os dois protocolos juntos tornam possivel que coneces semeca co lhantes `s telefnicas sejam estabelecidas entre computadores e garante que a o dados se entregues de forma convel e em ordem. a
Nomes de DNS Pelo fato de ser mais fcil lembrar nome que nmeros, o Servio de Nomes de a u c Dom nio (DNS) associa nomes tais como www.codesourcery.com a nmeros IP u unicos de computadores. DNS implementado por meio de uma hierarquia e mundial de servidores de nome, mas voc no precisa entender o protocolo DNS e a para usar nomes de computador conectado ` rede Internet em seus programas. a

Endereos de socket localizados na Internet possuem duas partes: uma c mquina e um nmero de porta. Essa informao armazenada na varivel a u ca e a struct sockaddr in. Escolha o campo sin family para AF INET de forma a indicar que struct sockaddr in um endereo de escopo Internet . O e c campo sin addr armazena o endereo Internet da mquina desejada como c a um nmero de IP inteiro de 32-bit. Um nmero de porta distingue entre diu u ferentes sockets em uma mesma mquina. Pelo fato de diferentes mquinas a a armazenarem valores multibyte em ordem de bytes diferentes, use o comando htons para converter o nmero da porta para ordem de byte de rede. Veja a u pgina de manual para o comando ip para maiores informaes.11 a co Para converter para converter nomes de computador conectado ` rede a leg veis a humanos, ou em nmeros na notao de ponto padronizada (tais u ca como 10.0.0.1) ou em nomes de DNS12 (tais como www.codesourcery.com) em
11 12

Nota do tradutor:temos ip tanto na seo 7 como na seo 8 das pginas de manual. ca ca a Nota do tradutor:Domain Name service.

153

nmeros IP de 32-bit, voc pode usar gethostbyname. A funo gethostbyu e ca name retorna um apontador para a estrutura struct hostent; o campo h addr contm o nmero IP do computador conectado ` rede. Veja o programa e u a amostra na Listagem 5.12. A Listagem 5.12 ilustra o uso de sockets de dom nio Internet . O programa obtm o pgina inicial do servidor Web cujo nome do computador e a conectado ` rede especicado na linha de comando. a e Listagem 5.12: (socket-inet.c) L de um Servidor WWW e
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 #include #include #include #include #include #include #include < s t d l i b . h> <s t d i o . h> <n e t i n e t / i n . h> <n e t d b . h> <s y s / s o c k e t . h> <u n i s t d . h> < s t r i n g . h> the server s socket .

/ P r i n t t h e c o n t e n t s o f t h e home p a g e f o r R e t u r n an i n d i c a t i o n o f s u c c e s s . / void g e t h o m e p a g e ( i n t s o c k e t f d ) { char b u f f e r [ 1 0 0 0 0 ] ; s s i z e t number characters read ;

/ Send t h e HTTP GET command f o r t h e home p a g e . / s p r i n t f ( b u f f e r , GET /\ n ) ; write ( socket fd , buffer , strlen ( buffer ) ) ; / Read f r o m t h e s o c k e t . r e a d may n o t r e t u r n a l l t h e d a t a a t one t i m e , s o k e e p t r y i n g u n t i l we r un o u t . / while ( 1 ) { number characters read = read ( s o c k e t f d , buffer , 10000) ; i f ( n u m b e r c h a r a c t e r s r e a d == 0 ) return ; / W r i t e t h e d a t a t o s t a n d a r d o u t p u t . / f w r i t e ( b u f f e r , s i z e o f ( char ) , n u m b e r c h a r a c t e r s r e a d , s t d o u t ) ; } } i n t main ( i n t a r g c , char const a r g v [ ] ) { int s o c k e t f d ; s t r u c t s o c k a d d r i n name ; struct hostent h o s t i n f o ; / C r e a t e t h e s o c k e t . / s o c k e t f d = s o c k e t ( PF INET , SOCK STREAM, 0 ) ; / S t o r e t h e s e r v e r s name i n t h e s o c k e t a d d r e s s . / name . s i n f a m i l y = AF INET ; / C o n v e r t f r o m s t r i n g s t o n um b e r s . / h o s t i n f o = gethostbyname ( argv [ 1 ] ) ; i f ( h o s t i n f o == NULL) return 1 ; else name . s i n a d d r = ( ( s t r u c t i n a d d r ) h o s t i n f o >h a d d r ) ; / Web s e r v e r s u s e p o r t 8 0 . / name . s i n p o r t = h t o n s ( 8 0 ) ; / C o n n e c t t o t h e web s e r v e r / i f ( c o n n e c t ( s o c k e t f d , &name , s i z e o f ( s t r u c t perror ( connect ) ; return 1 ; } / R e t r i e v e t h e s e r v e r s home p a g e . / get home page ( s o c k e t f d ) ; return 0 ; }

s o c k a d d r i n ) ) == 1) {

Esse programa recebe o nome do computador conectado ` rede do servia dor Web na linha de comando (no uma URL isto , recebe a informao a e ca 154

sem o http://). O programa chama a funo gethostbyname para traduca zir o nome do computador conectado ` rede em um endereo IP numrico a c e e ento conectar um uxo (TCP) socket na porta 80 daquele computador a conectado ` rede. Servidores Web falam o Protocolo de Transporte de Hia pertexto (HTTP), de forma que o programa emita o comando HTTP GET e o servidor responda enviando o texto da pgina inicial. a
N meros de Porta Padronizados u Por conveno, servidores Web esperam por coneces na porta 80. A maioria ca co dos servios de rede Internet so associados a nmeros de prota padronizac a u dos. Por exemplo, servidores Web que usam SSL esperam por coneces na co porta 443, e servidores de e-mail (que usam o protocolo SMTP) esperam por coneces na porta 25. Em sistemas GNU/Linux, a associao entre nomes de co ca protocolos, nomes de servios e nmeros de porta padronizados est listada c u a no arquivo /etc/services. A primeira coluna o protocolo ou nome de servio. e c A segunda coluna lista o nmero da porta e o tipo de coneco: tcp para u ca servios orientados ` coneco, ou udp para datagramas. Se voc implementar c a ca e algum servio personalizado de rede usando sockets de dom Internet , use c no nmeros de porta maiores que 1024. u

Por exemplo, para recuperar a pgina inicial do s Web www.codesour a tio cery.com, chame o seguinte:
\% ./socket-inet www.codesourcery.com <html> <meta http-equiv=Content-Type" content="text/html; charset=iso-8859-1"> ...

5.5.7

Sockets Casados

Como vimos anteriormente, a funo pipe cria dois descritores de arquivo ca para o in e o m de um pipe. Pipes so limitados pelo fato de os descricio a tores de arquivo deverem ser usados por processos aparentados e pelo fato de a comunicao ser unidirecional. A funo socketpair cria dois descritoca ca res de arquivo para dois sockets conectados no mesmo computador. Esses descritpres de arquivo permitem comunicao de mo dupla entre processos ca a aparentados. Seus primeiros trs parmetros so os mesmo que aqueles da chamada de e a a sistema socket: eles especicam o dom nio, estilo de coneco, e o protocolo. O ultimo parmetro um array de dois inteiros, os quais so preenchidos com a e a as descries de arquivo dos dois sockets, de maneira similar a pipe. Quando co voc chama socketpair, voc deve especicar PF LOCAL como o dom e e nio.

155

156

Parte II Dominando GNU/Linux

157

6 Dispositivos 7 O Sistema de Arquivos /proc 8 Chamadas de Sistema do GNU/Linux 9 Cdigo Assembly Embutido o 10 Segurana c 11 Um Modelo de Aplicao GNU/Linux ca

159

160

Cap tulo 6 Dispositivos


GNU/LINUX, COMO A MAIORIA DOS SISTEMAS OPERACIONAIS, INTERAGE COM DISPOSITIVOS de hardware por meio de componentes de software modularizados chamados programas controladores de dispositivos1 . Um programa controlador de dispositivo esconde as peculiaridades de protocolos de comunicao de dispositivos de hardware do systema operaca cional e permite ao sistema interagir o dispositivo atravs de uma interface e padronizada. Sob GNU/Linux, programas controladores de dispositivos so parte do a kernel e poderm ser ou linkados estaticamente dentro do kernel ou chamados conforme a necessidade como mdulos do kernel. Programas controladoo res de dispositivos executam como parte do kernel e no esto diretamente a a acess veis a processos de usurio. Todavia, GNU/Linux fornece um mecaa nismo atravs do qual processos podem comunicar-se com um acionador de e dispositivo e atravs desse mesmo acionador de dispositivo, com um dise positivo de hardware por meio de objetos semelhantes a arquivos. Esses objetos aparecem no sistema de arquivos, e programas podem abr -los, ler a partir deles, e escrever para eles praticamente como se eles fossem arquivos normais. Usando ou operaes de E/S de baixo n do GNU/Linux (veja o co vel Apndix B, E/S de Baixo N e vel) ou operaes de E/S da biblioteca C GNU co padro, seus programas podem comunicar-se com dispositivos de hardware a atravs desse objetos semelhantes a arquivos. e GNU/Linux tambm fornece muitos objetos semelhantes a arquivos que e comunicam-se diretamente com o kernel em lugar de com programas controladores de dispositivos. Esses objetos semelhantes a arquivos que comunicamse diretamente com o kernel no so linkados para dispositivos de hardware; a a ao invs disso, eles fornecem vrios tipos de comportamento especializado e a
1

Nota do tradutor: device drivers.

161

que podem ser de uso para aplicaes e programas de sitema. co


Cultive a Precauo Quando Estiver Acessando Dispositivos! ca A tcnica nesse cap e tulo fornece acesso direto a programas controladores de dispositivos executando no kernel do GNU/Linux, e atravs desses acionae dores de dispositivo tem-se acesso a dispositivos de hardware conectados ao sistema. Use essas tcnicas com cuidado pelo fato de que o abuso dessas e mesmas tcnicas pode vir a prejudicar ou danicar o sistema GNU/Linux. e Veja especialmente a barra lateral Perigos de Dispositivos de Bloco.

6.1

Tipos de Dispositivos

Arquivos de dispositivo no so arquivos comuns eles no representam a a a regies de dados sobre um sistema de arquivos localizado sobre um disco. Ao o invs disso, dados lidos de um ou escritos para um arquivo de dispositivo e e comunicado ao correspondente acionador de dispositivo, e do acionador de dispositivo para o dispositivo subjacente. Arquivos de dispositivos veem em dois sabores: Um dispositivo de caractere representa um dispositivo de hardware que l ou escreve um uxo serial de bytes de dados. Portas seriais e e paralelasa , acionadores de ta, dispositivos de terminal, e placas de som so exemplos de dispositivos de caractere. a Um dispositivo de bloco representa um dispositivo de hardware que l ou escreve dados em blocos de tamanho xo. Ao contrrio de um e a dispositivo de caractere, um dispositivo de blocos fornece acesso aleatrio a dados armazenados no dispositivo. Um acionador de e disco um exemplo de dispositivo de bloco. e
Nota do tradutor: as modernas portas USB funcionam como tanto como dispositivo de bloco quanto como dispositivo de caractere, dependendo do dispositivo que estiver conectado a ela.
a

Programas de aplicao t ca picos nunca iro usar dispositivos de bloco. a Enquanto um acionador de disco representado como um dispositivo de e bloco, o contedo de cada partio do disco tipicamente contm um sistema u ca e de arquivos, e esse sistema de arquivos montado dentro da rvore do sistema e a de arquivos ra do GNU/Linux. Somente o cdigo do kernel que implementa z o o sistema de arquivos precisa acessar o dispositivo de bloco diretamente; programas de aplicao acessam o contedo do disco atravs de arquivos ca u e normais e diretrios. o 162

Perigos de Dispositivos de Bloco Dispositivos de bloco fornecem acesso direto a dados do acionador de disco. Apesar de a maioria dos sistema GNU/Linux esteja congurado para prevenir que processos de usurios comuns acessem esses dispositivos diretamente, um a processo de superusurio pode iningir danos severos atravs da modicao a e ca do contedo do disco. Por meio da escrita no dispositivo de bloco do disco, u um programa pode modicar ou destuir informaes de controle do sistema co de arquivos e mesmo uma tabela de partio do disco e o registro principal de ca inicializaoa , dessa forma travar um acionador ou mesmo colocar o sistema ca inteiro inutilizado. Sempre acesse esses dispositivos com grande cuidado. Aplicaes algumas vezes fazem uso de dispositivos de caractere, apesar da co maioria dos dispositivos ser de bloco. Discutiremos muitos dispositivos de caractere nas sees seguintes. co
a

Nota do tradutor: o Master Boot Record - MBR.

6.2

N meros de Dispositivo u

GNU/Linux identica dispositivos usando dois nmeros: o nmero de disu u positivo principal e o nmero de dispositivo secundrio. O nmero de disu a u positivo principal especica a qual programa controlador o dispositivo corresponde. A correspondncia entre nmeros de dispositivo principal e proe u gramas controladores xa e faz parte dos fontes do kernel do GNU/Linux. e Note que o mesmo nmero de dispositivo principal pode corresponder a dois u diferentes programas controladores, um deles um dispositivo de caractere e e outro um dispositivo de bloco. Nmeros de dispositivo secundrio dise u a tinguem dispositivos individuais ou componenetes controlados por um unico acionador. O signicado de um nmero de dispositivo secundrio depende u a do acionador de dispositivo. Por exemplo, dispositivo principal no. 3 corresponde ` controladora IDE a primria no sistema. Uma controladora IDE pode ter dois dispositivos (disco, a ta, ou acionador de CD-ROM) conectados a essa mesma controladora; o dispositivo mestre tem nmero de dispositivo secundrio 0, e o dispositivo u a escravo tem nmero de dispositivo secundrio 64. Parties individuais no u a co dispositivo mestre (se o dispositivo suportar parties) so representados por co a nmeros de dispositivo secundrio 1, 2, 3, e assim por diante. Parties indiu a co viduais no dispositivo escravo so representados por nmeros de dispositivo a u secundrio 65, 66, 67, e assim por diante. a Nmeros de dispositivo principal so listados na documentao dos fonu a ca tes do kernel do GNU/Linux. Em muitas distribuies GNU/Linux, essa co documentao pode ser encontrada em /usr/src/linux/Documentation/deca 163

vices.txt 2 . A entrada especial /proc/devices lista nmeros de dispositivo u principal correspondendo a programas controladores de dispositivos ativos atualmente carregados dentro do kernel 3 . (Veja Cap tulo 7, O Sistema de Arquivos /proc para mais informao sobre as entradas do sistema de arca quivos /proc.)

6.3

Entradas de Dispositivo

Uma entrada de dispositivo de muitas formas o mesmo que um arquivo e regular. Voc pode mover a entrada de dispositivo usando o comando mv e e apagar uma entrada de dispositivo usando o comando rm . Se voc tentar e copiar uma entrada de dispositivo usando cp apesar disso, voc ir ler bytes e a a partir do dispositivo (se o dispositivo suportar leitura) e escrever esses bytes para o arquivo de destino. Se voc tentar sobrescrever uma entrada de e dispositivo, voc ir escrever bytes no dispositivo correspondente ao invs de e a e sobrescrever a entrada. Voc pode criar uma entrada de dispositivo no sistema de arquivos usando e o comando mknod (use o comando man 1 mknod para a pgina de maa nual) ou usando a chamada de sistema mknod (use o comando man 2 mknod para acessar a pgina de manual correspondente). Criando uma entrada de a dispositivo no sistema de arquivos no implica automaticamente que o cora respondente programa controlador de dispositivo ou dispositivo de hardware esteja presente ou dispon vel; a entrada de dispositivo meramente um acesso e 4 de comunicao com o programa controlador , se ele existir. Somente o proca cesso de superusurio pode criar dispositivos de bloco e de caractere usando a o comando mknod ou a chamada de sistema mknod. Para criar um dispositivo usando o comando mknod , especique como primeiro argumento o caminho no qual a entrada ir aparecer no sistema de a arquivos. Para o segundo argumento, especique b para um dispositivo de bloco ou c para um dispositivo de caractere. Fornea os nmeros de dispoc u sitivo principal e secundrio como o terceiro e o quarto argumento, respectia vamente. Por exemplo, o comando adiante cria uma entrada de dispositivo de caractere chamada lp0 no diretrio atual. O dispositivo tem nmero de o u
Nota do tradutor: o slackware 13.37 padro trs o referido arquivo no local indicado a a acima mas a verso mais recente que encontrada localiza-se em ftp://ftp.kernel.org/ a pub/linux/docs/device-list/devices-2.6+.txt. 3 Nota do tradutor: o comando cat /proc/devices e mostra uma sa dividida em e da dois grupos, os dispositivos de bloco e os dispositivos de caractere. 4 Nota do tradutor: um porto de embarque de aeroporto. O porto sempre est l e a a a a mas voc tem que esperar pelo avio que vai usar o porto de embarque. e a a
2

164

dispositivo principal 6 e nmero de dispositivo secundrio 0. Esses nmeros u a u correspondem ` primeira porta paralela no sistema GNU/Linux. a % mknod ./lp0 c 6 0 Lembrando que somente processos do superusurio podem criar dispositia vos de bloco e dispositivos de caractere, de forma que voc deve estar logado e como root para usar o comando acima com sucesso. O comando ls mostra entradas de dispositivos especicamente. Se voc usar comando ls com a opo -l ou com a opo -o , o primeiro e ca ca caractere de cada linha de sa especica o tipo de entrada de dispositivo. da Relembrando que o caractere (um h fem) designa um arquivo normal, enquanto d designa um diretrio. Similarment, b designa um dispositivo o de bloco, e c designa um dispositivo de caractere. Para os dois ultimos o comando ls mostra os nmeros de dispositivo principal e secundrio onde u a seria mostrado o tamanho de um arquivo comum. Por exemplo, podemos mostrar o dispositivo de caractere que acabamos de criar:
% ls -l lp0 crw-r----1 root root 6, 0 Mar 7 17:03 lp0

Em um programa, voc pode determinar se uma entrada de sistema de e arquivos um dispositivo de bloco ou um dispositivo de caractere e ento e a recuperar seus nmeros de dispositivo usando o comando stat. Veja a u Seo B.2, stat no Apndice B, para instrues. ca e co Para remover uma entrada de dispositivo use o comando rm. O comando rm simplesmente remove a entrada de dispositivo do sistema de arquivos.
% rm ./lp0

6.3.1

O Diretrio /dev o

Por conveno, um sistema GNU/Linux inclui um diretrio /dev contendo o ca o conjunt completo das entradas de dispositivos de caractere e de dispositivos de bloco que GNU/Linux tem conhecimento. Entradas no /dev possuem nomes padronizados correspondendo aos nmeros de dispositivo principal e u secundrio. a Por exemplo, o dispositivo mestre anexado ` controladora IDE primria, a a que tem nmeros de dispositivo principal e secundrio 3 e 0, tem o nome u a padro /dev/hda. Se esse dispositivo suporta parties, a primeira partio a co ca do dispositivo /dev/hda, que tem nmero de dispositivo secundrio 1, tem u a o nome padronizado /dev/hda1 . Voc pode vericar que isso verdadeiro e e em seu sistema: 165

% ls -l /dev/hda /dev/hda1 brw-rw---1 root disk brw-rw---1 root disk

3, 3,

0 May 1 May

5 5

1998 /dev/hda 1998 /dev/hda1

Similarmente, /dev tem uma entrada para o dispositivo de caractere porta paralela que usamos anteriormente:
% ls -l /dev/lp0 crw-rw---1 root daemon 6, 0 May 5 1998 /dev/lp0

Na maioria dos casos, voc no deve usar mknod para criar suas prprias e a o entradas de dispositivo. Use as entradas no /dev ao invs de criar entrae das. Programas comuns no possuem escolha e devem usar as entradas de a dispositivo pr-existentes pelo fato de eles no poderem criar suas prprias e a o entradas de dispositivo. Tipicamente, somente administradores de sistema e desenvolvedores que trabalham com dispositivos de hardware especializados iro precisar criar entradas de dispositivo. A maioria das distribuies a co GNU/Linux incluem facilidade para ajudar administradores de sistema a criar entradas dispositivo padronizadas com os nomes corretos.

6.3.2

Acessando Dispositivos por meio de Abertura de Arquivos

Como voc pode usar esses dispositivos? no caso de dispositivos de caractere, e o uso pode ser bastante simples: Abra o dispositivo como se ele fosse um arquivo normal, e leia a partir do ou escreva para o dispositivo. Voc pode e mesmo usar comandos comuns para arquivos tais como cat, ou sua sintaxe de redirecionamento de shell, para enviar dados ao dispositivo ou para ler dados do dispositivo. Por exemplo, se voc tiver uma impressora conectada na primeira porta e paralela de seu computador, voc pode imprimir arquivos enviando-os diree tamente para /dev/lp0 .5 Para imprimir o contedo de documento.txt, use u o comando seguinte:
% cat document.txt > /dev/lp0\\

Voc deve ter permisso de escrita para a entrada de dispositivo de forma e a que esse comando funcione; em muitos sistemas GNU/Linux, as permisses o so escolhidas de forma que somente root e o systems printer daemon (lpd) a possa escrever para o arquivo. Tambm, o que aparece na sa de sua e da impressora depende de como sua impressora interpreta o contedo dos dados u
Usurios windows iro reconhecer que esse dispositivo similar ao arquivo mgico a a e a Windows LPT1.
5

166

que voc envia. Algumas impressoras iro imprimir arquivos no formato e a 6 texto plano que forem enviadas a ela, enquanto outras no iro imprim a a los. Impressoras com suporte a PostScript iro converter e imprimir arquivo a PostScript que voc enviar para ela. e Em um programa, o envio de dados para um dispositivo muito simples. Por exemplo, o fragmento de cdigo adiante7 usa funes de entrada e sa o co da de baixo n para enviar o contedo de uma rea temporria de armazenavel u a a mento para /dev/lp0. int f d = open ( / dev / l p 0 , O WRONLY) ; w r i t e ( fd , b u f f e r , b u f f e r l e n g t h ) ; c l o s e ( fd ) ;

6.4

Dispositivos de Hardware

Alguns dispositivos de bloco comuns so listados na Tabela 6.1. Nomes de a dispositivo para dispositivos similares seguem o modelo bvio (por exemplo, o a segunda partio no primeiro acionador SCSI /dev/sda2 ). Essa aparncia ca e e o bvia ocasionalmente util para saber a quais dispositivos esses nomes de e dispositivos correspondem ao examinar sistemas de arquivos montados em /proc/mounts (veja a Seo 7.5, Acionadores, Montagens, e Sistemas de ca Arquivos no Cap tulo 7, para mais sobre isso). A Tabela 6.2 lista alguns dispositivos de caractere comuns. Voc pode acessar certos componentes de hardware atravs de mais de e e um dispositivo de caractere; muitas vezes, os diferentes dispositivos de caractere fornecem diferentes semnticas. Por exemplo, quando voc usa o a e dispositivo de ta IDE /dev/ht0, GNU/Linux automaticamente rebobina a ta no acionador quando voc fecha o descritor de arquivo. Voc pode usar e e o dispositivo /dev/nht0 para acessar o mesmo acionador de ta, exceto que GNU/Linux no ir rebobinar automaticamente a ta quando voc fechar o a a e descritor de arquivo. Voc algumas vezes possivelmente pode ver programas e usando /dev/cua0 e dispositivos similares; esses so antigos dispositivos para a portas seriais tais como /dev/ttyS0. Ocasionalmente, voc ir desejar escrever dados diretamente para dispoe a sitivos de caractere por exemplo:
Sua impressora pode requerer caracteres expl citos de retorno de cabea de impresso, c a cdigo 13 ASCII, ao nal de cada linha, e pode requerer um caractere de alimentao de o ca pgina, cdigo ASCII 12, ao nal de cada pgina. a o a 7 Nota do tradutor:em linguagem C.
6

167

Tabela 6.1: Lista Parcial de Dispositivos de Bloco Comuns Dispositivo Nome Principal secundrio a Primeiro acionador de dis- /dev/fd0 2 0 quetes Segundo acionador de dis- /dev/fd1 2 1 quetes Controladora IDE primria, /dev/hda a 3 0 dispositivo mestre Controladora IDE primria, /dev/hda1 a 3 1 dispositivo mestre, primeira partio ca Controladora IDE primria, /dev/hdb a 3 64 dispositivo secundrio a Controladora IDE primria, /dev/hdb1 a 3 65 dispositivo secundrio, pria meira partio ca Controladora IDE se- /dev/hdc 22 0 cundria, a dispositivo mestre Controladora IDE se- /dev/hdd 22 64 cundria, a dispositivo secundrio a Primeiro acionador SCSI /dev/sda 8 0 Primeiro acionador SCSI, /dev/sda1 8 1 primeira partio ca Segundo disco SCSI /dev/sdb 8 16 Segundo acionador SCSI, /dev/sdb1 8 17 primeira partio ca Primeiro acionador de CD- /dev/scd0 11 0 ROM/DVD SCSI Segundo acionador de CD- /dev/scd1 11 1 ROM/DVD SCSI Pendrive em porta usb8 /dev/sdc 8 32 Primeira partio do pen- /dev/sdc1 ca 8 33 9 drive acima

168

Tabela 6.2: Alguns Dispostivos de Caractere Comuns Dispositivo Nome Principal secundrio a Porta paralela 0 /dev/lp0 ou 6 0 /dev/par0 Porta paralela 1 /dev/lp1 ou 6 1 /dev/par1 Primeira porta serial /dev/ttyS0 4 64 Segunda porta serial /dev/ttyS1 4 65 Acionador de ta IDE /dev/ht0 37 0 Primeiro acionador de ta /dev/st0 9 0 SCSI Segundo acionador de ta /dev/st0 9 1 SCSI Console do sistema /dev/console 5 1 Primeiro terminal virtual /dev/tty1 4 1 Segundo terminal virtual /dev/tty2 4 2 Dispositivo de terminal do /dev/tty 5 0 processo atual Placa de som /dev/audio 14 4

Um programa de terminal possivelmente pode acessar um modem diretamente atravs de um dispositivo de porta serial. Dados ese critos para ou lidos dos dispositivos so transmitidos por meio do a modem para um computador remoto. Um programa de backup de ta possivelmente pode escrever dados diretamente para um dispositivo de ta. O programa de backup pode implementar seu prprio formato de compresso e vericao o a ca de erro. Um programa pode escrever diretamente no primeiro terminal virtuala enviando dados para /dev/tty1. Janelas de terminal executando em um ambiente grco, ou em sesses de terminal de login a o remoto, no esto associados a terminais virtuais; ao invs disso, a a e essas janelas de terminal esto associadas a pseudo-terminais. Veja a a seo 6.6,PTYs para informaes sobre esses terminais. ca co
Na maioria dos sistemas GNU/Linux, voc pode alternar para o primeiro tere minal virtual pressionand Ctrl+Alt+F1. Use Ctrl+Alt+F2 para o segundo terminal virtual, e assim por diante.
a

169

Algumas vezes um programa precisa acessar o dispositivo de terminal com o qual est associado. a Por exemplo, seu programa pode precisar perguntar ao usurio por a uma senha. Por razes de segurana, voc pode desejar ignorar o o c e redirecionamento da entrada padro e da sa padro e sempre ler a da a a senha a partir do terminal, no importa como o usurio chame o a a comando. Um caminho para fazer isso abrir /dev/tty, que sempre e corresponde ao dispositivo de terminal associado com o processo que o abriu. Escreve uma mensagem para aquele dispositivo, e l e a senha a partir de /dev/tty tambm. Atravs do ato de ignorar a e e entrada e a sa padro, evita que o usrio possa fornecer ao seu da a a programa uma senha a partir de um arquivo usando uma sintaxe do shell tal como: % secure\_program < my-password.txt Se voc precisar autenticar usurios em seu programa. voc deve e a e aprender mais sobre o recurso PAM do GNU/Linux. Veja a seo ca 10.5, Autenticando Usurios no Cap a tulo 10, Segurana para c maiores informaes. co

170

Um programa pode emitir sons atravs da placa de som do sistema e enviando dados de audio para o dispositivo /dev/audio. Note que os dados de audio devem estar no formato da Sun (comumente associado com a extenso .au). Por exemplo, muitas distria buies GNU/Linux so acompanhadas do arquivo de som clssico co a a /usr/share/sndcong/sample.au a . Se seu sistema inclui esse arquivo, tente toc-lo atravs do seguinte comando: a e % cat /usr/share/sndconfig/sample.au > /dev/audio Se voc est planejando usar sons em seu programa, apee a sar disso, voc deve investigar as vrias bibliotecas sonoras e a e servios despon c veis para GNU/Linux. O ambiente Gnome windowing usa o Enlightenment Sound Daemon (EsounD), em http://www.tux.org/ricdude/EsounD.htmlb . KDE usa o aRts, em http://space.twc.de/stefan/kde/arts-mcop-doc/c . Se voc usa e um desses sistemas de som ao invs de escrever diretamente para e /dev/audio, seu programa ir cooperar melhor com outros prograa mas que usam a placa de som do computador.
Nota do tradutor: o referido arquivo no foi encontrado no slackware 13.1 padro a a mas o comando nd / -name *.au 2>/dev/null. encontra outro para voc. e b Nota do tradutor:Atualmente temos o ALSA - Advanced Linux Sound Architecture. c Nota do tradutor: http://www.arts-project.org/, aRts - analog Realtime synthesizer.
a

6.5

Dispositivos Especiais

GNU/Linux tambm fornece muitos dispositivos de caractere que no correse a pondem a dispositivos de hardware. Essas entradas todas usam o nmero de u dispositivo principal 1, que associado ao dispositivo de memria do kernel e o do GNU/Linux ao invs de ser associado a um acionador de dispositivo. e

6.5.1

O Dispositivo /dev/null

A entrada /dev/null, o dispositivo nulo, muito util. Esse dispositivo nulo e serve a dois propsitos; voc est provavelmente familiarizado ao menos com o e a o primeiro deles: 171

GNU/Linux descarta quaisquer dados escritos para /dev/null. Um artif comum para especicar /dev/null como um arquivo de co sa em algum contexto onde a sa descartvel. da da e a Por exemplo, para executar um comando e descartar sua sa da padro (sem mostr-la ou escrev-la em um arquivo), redirecione a a a e sa padro para /dev/null : da a % verbose_command > /dev/null L de /dev/null sempre resulta em um caractere de m de arquivo. e Por exemplo, se voc abre um descritor de arquivo para /dev/null e usando a funo open e ento tenta ler a partir desse descritor de ca a arquivo, a leitura ir ler nenhum byte e ir retornar 0. Se voc copia a a e a partir do /dev/null para outro arquivo, o arquivo de destino ir a ser um arquivo de tamanho zero:
% cp /dev/null empty-file % ls -l empty-file -rw-rw---1 samuel samuel

0 Mar

8 00:27 empty-file

6.5.2

O Dispositivo /dev/zero

A entrada de dispositivo /dev/zero comporta-se como se fosse um arquivo innitamente longo preenchido com 0 bytes. Tantas quantas forem as tentativas de ler bytes de /dev/zero, GNU/Linux gera sucientes 0 bytes. Para ilustrar isso, vamos executar o programa hexdump mostrado na Listagem B.4 na Seo B.1.4, Lendo Dados do Apndice B. Esse programa ca e mostra o contedo de um arquivo na forma hexadecimal. u
% ./hexdump /dev/zero 0x000000 : 00 00 00 00 0x000010 : 00 00 00 00 0x000020 : 00 00 00 00 0x000030 : 00 00 00 00 ... 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Aperte Ctrl+C quando estiver convencido que a visualizao ir prosseca a guir innitamente. Mapeamento de memria para /dev/zero uma tcnica avanada de o e e c alocao de memria. Veja a Seo 5.3.5, Outros Usos para mmap no ca o ca Cap tulo 5, Comunicao Entre Processos para mais informao, e veja a ca ca barra lateral Obtendo Pgina de Memria Alinhada na Seo 8.9, mproa o ca tect: Ajustando as Permisses da Memria no Cap o o tulo 8, Chamadas de Sistema do GNU/Linux para um exemplo. 172

6.5.3

/dev/full

A entrada /dev/full comporta-se como se fosse um arquivo sobre um sistema de arquivos cheio. Uma escrita para /dev/full ir falhar e escolher errno para a ENOSPC, que comumente indica que a escrita para o dispositivo no pode a ser feita pelo fato de o dispositivo estar cheio. Por exemplo, voc pode tentar escrever para /dev/full usando o comando e cp: % cp /etc/fstab /dev/full cp: /dev/full: No space left on device A entrada /dev/full primriamente util para testar como seu sistema e a comporta-se se esse mesmo sistema executar sem espao no disco durante c uma tentativa de escrever para um arquivo.

6.5.4

Dispositivos Geradores de Bytes Aleatrios o

Os dispositivos especiais /dev/random e /dev/urandom fornecem acesso ` a facilidade intena do kernel do GNU/Linux de gerao de nmeros aleatrios. ca u o A maioria das funes de software para gerar nmeros aleatrios, tais co u o como a funo rand na biblioteca C GNU padro, atualmente geram nmeros ca a u aleatrios imperfeitos. Embora esses nmeros satisfaam algumas proprieo u c dades dos nmeros aleatrios, eles so reprodut u o a veis: Se voc iniciar com o e mesmo valor semente, voc ir obter a mesma sequncia de nmeros aleatrios e a e u o imperfeitos todas as vezes que zer isso. Esse comportamento inevitvel e a pelo fato de computadores serem intrinsecamente determin sticos e previs veis. Para certas aplicaes, apesar disso, esse comportamento determin o stico ine desejvel; por exemplo, algumas vezes poss quebrar um algor a e vel tmo criptogrco se voc puder obter a sequncia de nmeros aleatrios que o referido a e e u o algor tmo emprega. Para obter melhores nmeros aleatrios em programas de computadores u o necessrio uma fonte externa de aleatoriedade. O kernel do GNU/Linux e a fornece as ferramentas necessrias a uma particularmente boa fonte de alea atoriedade: voc! Medindo o espao de tempo entre suas aes de entrada, e c co tais como pressionamentos de tecla e movimentos de mouse, GNU/Linux e capaz de gerar um uxo imprevis de nmeros aleatrios de alta qualidade. vel u o Voc pode acessar esse uxo por meio da leitura a partir de /dev/random e e de /dev/urandom. Os dados que voc l correspondem a um uxo de bytes e e gerados aleatriamente. o 173

A diferena entre os dois dispositivos10 mostra-se por si mesma quando c exaure-se seu reservatrio de aleatriedade. Se voc tenta ler um grande o o e nmero de bytes a partir de /dev/random mas no gera qualquer aes de u a co entrada (voc no digita, o mouse ca parado, ou executa aes similares), e a co GNU/Linux bloqueia a operao de leitura. Somente ao voc fornecer alca e guma aleatoriedade que poss ao GNU/Linux gerar mais alguns bytes e e vel aleatrios e retornar esses bytes aleatrios para seu programa. o o Por exemplo, tente mostrar o contedo de /dev/random usando o cou 11 mando od. Cada linha de sa mostra 16 bytes aleatrios. da o
% od -t 0000000 0000020 0000040 0000060 x1 2c d3 b3 05 /dev/random 9c 7a db 2e 6d 1e a7 91 b0 8d 94 21 a3 02 cb 22 79 05 57 0a 3d 2d f3 bc 65 4d 90 c9 36 c3 61 45 c2 a6 dd dd e3 de 26 a6 1b 54 ac 59 52 29 94 40 75 f4 c3 22 1e 46 b9 53 1a 04 3a d4

O nmero de linhas de sa que voc v ir variar podendo haver algumas u da e e a poucas e a sa pode eventualmente pausar quando GNU/Linux esvazia seu da estoque de aleatoriedade. Agora tente mover seu mouse ou digitar no seu teclado, e assista nmeros aleatrios adicionais aparecerem. Para realmente u o melhor aleatoriedade, ponha seu gato para andar no teclado. Uma leitura a partir de /dev/urandom, ao contrrio, nunca ir bloquear. a a Se GNU/Linux executa com aleatoriedade esgotada, /dev/urandom usa um algor tmo criptogrco para gerar bytes aleatrios imperfeitos a partir da a o sequncia anterior de bytes aleatrios. Embora esses bytes sejam aleatrios e o o o suciente para a maioria dos propsitos, eles no passam em muitos testes o a de aleatoriedade quanto aqueles obtidos a partir de /dev/random. Por exemplo, se voc usar o comando seguinte, os bytes aleatrios iro e o a voar para sempre, at que voc mate o programa com Ctrl+C : e e % od -t 0000000 0000020 0000040 ... x1 62 26 95 /dev/urandom 71 d6 3e af dd de 62 c0 42 78 bd 29 9c 69 49 3b 95 bc b9 6c 15 16 38 fd 7e 34 f0 ba ce c3 31 e5 2c 8d 8a dd f4 c4 3b 9b 44 2f 20 d1 54

O uso de nmeros aleatrios de /dev/random em um programa fcil, u o e a tambm. A Listagem 6.1 mostra uma funo que gera um nmero aleatrio e ca u o
Nota do tradutor:/dev/random e /dev/urandom. Usamos od aqui ao invs do programa hexdump mostrado na Listagem B.4, mesmo e apesar dele fazer muito lindamente a mesma coisa, pelo fato de hexdump encerra quando esgota os dados, enquanto od espera por mais dados para torn-los dispon a veis. A opo ca -t x1 informa ao comando od para imprimir o contedo do arquivo em hexadecimal. u
11 10

174

usando bytes lidos a partir de /dev/random. Lembrando que /dev/random bloqueia uma leitura at que exista suciente aleatoriedade dispon e vel para satisfaz-la; voc pode usar /dev/urandom ao invs de /dev/random e e e se execuo rpida for mais importante e se voc puder conviver com baixa ca a e qualidade em gerao de nmeros aleatrios. ca u o Listagem 6.1: Aleatrio o
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include #include #include #include #include

(random number.c) Funo para Gerar um Nmero ca u

< a s s e r t . h> <s y s / s t a t . h> <s y s / t y p e s . h> < f c n t l . h> <u n i s t d . h> inclusive . Obtain

/ R e t u r n a random i n t e g e r b e t w e e n MIN and MAX, r a n d o m n e s s f r o m / d e v / random . /

i n t random number ( i n t min , i n t max ) { / S t o r e a f i l e d e s c r i p t o r o p e n e d t o / d e v / random i n a s t a t i c variable . That way , we don t n e e d t o o p e n t h e f i l e e v e r y this function is called . / s t a t i c i n t d e v r a n d o m f d = 1; char n e x t r a n d o m b y t e ; int b y t e s t o r e a d ; unsigned r a n d o m v a l u e ; / Make s u r e MAX i s a s s e r t ( max > min ) ; / greater t h a n MIN . /

time

I f t h i s i s the f i r s t time t h i s f u n c t i o n i s c a l l e d , d e s c r i p t o r t o / d e v / random . / i f ( d e v r a n d o m f d == 1) { d e v r a n d o m f d = open ( / dev / random , O RDONLY) ; a s s e r t ( d e v r a n d o m f d != 1) ; }

open a

file

/ Read e n o u g h random b y t e s t o f i l l an i n t e g e r v a r i a b l e . / n e x t r a n d o m b y t e = ( char ) &r a n d o m v a l u e ; b y t e s t o r e a d = s i z e o f ( random value ) ; / Loop u n t i l we v e r e a d e n o u g h b y t e s . S i n c e / d e v / random i s f i l l e d f r o m u s e r g e n e r a t e d a c t i o n s , t h e r e a d may b l o c k , and may o n l y r e t u r n a s i n g l e random b y t e a t a t i m e . / do { int bytes read ; b y t e s r e a d = read ( dev random fd , next random byte , b y t e s t o r e a d ) ; b y t e s t o r e a d = b y t e s r e a d ; n e x t r a n d o m b y t e += b y t e s r e a d ; } while ( b y t e s t o r e a d > 0 ) ; / Compute a random number i n t h e c o r r e c t r a n g e . return min + ( r a n d o m v a l u e % ( max min + 1 ) ) ; } /

6.5.5

Dispositivos Dentro de Dispositivos

Um dispositivo dentro de um dispositivo 12 habilita a voc simular um dispoe sitivo de bloco usando um arquivo de disco comum. Imagine um acionador de disco para o qual dados so escritos para ele e lidos dele em um arquivo a chamado imagem-disco em lugar de escritos para e lidos de trilhas e setores de um acionador de disco f sico atual ou partio de disco. (Certamente, o ca
12

Nota do tradutor:loopback.

175

arquivo imagem-disco deve residir sobre o disco atual, o qual deve ser maior que o disco simulado.) Um dispositivo simulador habilita voc usar um are quivo dessa maneira.

Dispositivos simuladores so chamados /dev/loop0, /dev/loop1, e assim a por diante. Cada um desses dispositivos simuladores pode ser usado para simular um unico dispositivo de bloco por vez. Note que somente o supe rusurio pode denir um dispositivo simulador. a

Um dispositivo simulador pode ser usado da mesma forma que qualquer outro dispositivo de bloco. Em particular, voc pode construir um sistema e de arquivos sobre o dispositivo simulador e ento montar aquele sistema de a arquivo como voc montaria o sistema de arquivos sobre um disco comum e ou uma partio comum. Da mesma forma que um sistema de arquivos, que ca reside inteiramente dentro de um arquivo de disco comum, chamado um e sistema de arquivos virtual.

Para construir um sistema de arquivos virtual e mont-lo como um disa positivo simulado, siga os passos abaixo: 176

1. Crie um arquivo vazio para conter o sistema de arquivos virtual. O tamanho do arquivo ir ser o tamanho aparente do dispositivo a simulado aps esse mesmo dispositivo ser montado. Um caminho o conveniente para construir um arquivo de um tamanho xo com o e comando dd . Esse comando copia blocos (por padro, o tamanho a de bloco 512 bytes cada) de um arquivo para outro. O dispositivo e /dev/zero uma fonte conveniente de bytes para serem copiados. e Para construir um arquivo de 10MB chamado imagem-disco, use o comando seguinte:
% dd if=/dev/zero of=/tmp/disco-imagem count=20480 20480+0 records in 20480+0 records out % ls -l /tmp/imagem-disco -rw-rw---1 root root 10485760 Mar

8 01:56 /tmp/imagem-disco

2. O arquivo que voc criou preenchido com 0 bytes. Antes de voc e e e montar o referido arquivo, voc deve construir um sistema de arquie vos. Isso ajusta vrias estruturas de controle necessrias a organizar a a e armazenar arquivos, e construir o diretrio principal. Voc pode o e construir qualquer tipo de sistema de arquivos que voc quiser na e sua imagem de disco. Para construir um sistema de arquivos ext2 (o tipo mais comumente usado em discos GNU/Linux)a , use o comando mke2fs. Pelo fato de o mke2fs comumente executar sobre um dispositivo de bloco, no sobre um arquivo comum, o mke2fs a solicita uma conrmao: ca % mke2fs -q /tmp/imagem-disco mke2fs 1.18, 11-Nov-1999 for EXT2 FS 0.5b, 95/08/09 imagem-disco is not a block special device. Proceed anyway? (y,n) y A opo -q omite informao de sumrio sobre o sistema de arquivos ca ca a recentemente criado. Retire essa opo caso voc desejar ver as ca e informaes de sumrio. Agora imagem-disco contm um sistema co a e de arquivos novinho em folha, como se esse sistema de arquivos tivesse sido suavemente incializado em um acionador de disco de 10MB.
Nota do tradutor: o slackware vem atualmente com o ext4 por padro embora a possa-se escolher entre outros como o prprio ext2 e o reiserfs. o
a

177

3. Monte o sistema de arquivos usando um dispositivo simulador. Para fazer isso, use o comando mount, especicando a imagem de disco como o dispositivo a ser montado. Tambm especique e loop=dispositivo-simulador como uma opo de montagem, usando ca a opo de montagem -o para dizer ao mount qual dispositivo ca simulador usar. Por exemplo, para montar nosso sistema de arquivos imagem-disco, use os comandos adiante. Lembrando, somente o superusurio pode a usar um dispositivo simulador. O primeiro comando cria um diretrio, /tmp/virtual-sa, a ser usado como ponto de montagem do o sistema de arquivos virtual.
% mkdir /tmp/virtual-sa % mount -o loop=/dev/loop0 /tmp/imagem-disco /tmp/virtual-sa

Agora sua imagem de disco est montada como se fosse um acioa nador comum de disco de 10MB.
% df -h /tmp/virtual-sa Filesystem Size Used Avail Use% Mounted on /tmp/imagem-disco 9.7M 13k 9.2M

0% /tmp/virtual-sa

Voc pode usar essa imagem de disco como se fosse outro disco: e
% cd /tmp/virtual-sa % echo Al\^o, mundo! > teste.txt % ls -l total 13 drwxr-xr-x 2 root root -rw-rw---1 root root 14 Mar % cat teste.txt Al\^o, mundo!

12288 Mar 8 02:00 lost+found 8 02:12 teste.txt

Note que lost+found um diretrio que foi adicionado automatie o camente pelo mke2fs.a Ao terminar, desmote o sistema de arquivos virtual.
% cd /tmp % umount /tmp/virtual-sa

Voc pode apagar imagem-disco se voc desejar, ou voc pode mone e e tar imagem-disco mais tarde para acessar os arquivos no sistema de arquivos virtual. Voc pode tambm copiar imagem-disco para e outro computador e montar imagem-disco nesse mesmo outro computador o completo sistema de arquivos que voc criou pois ele e estar intacto. a
Se o sistema de arquivos for danicado, e algum dado for recuperado mas no a associado a um arquivo, esse dado recuperado colocado no lost+found. e
a

178

Ao invs de criar um sistema de arquivos a partir do zero, voc pode e e copiar um sistema de arquivos diretamente de um dispositivo. Por exemplo, voc pode criar uma imagem do contedo de um CD-ROM simplesmente e u copiando esse mesmo CD-ROM a partir do dispositivo de CD-ROM. Se voc tiver um acionador de CD-ROM IDE, use o correspondente nome e de dispositivo, tal como /dev/hda, descrito anteriormente. Se voc tiver um e acionador de CD-ROM SCSI, o nome de dispositivo ir ser /dev/scd0 ou a similar. Seu sistema pode tambm ter um link simblico /dev/cdrom que e o aponta para o dispositivo apropriado. Consulte seu arquivo /etc/fstab para determinar qual dispositivo corresponde ao acionador de CD-ROM de seu computador. Simplesmente copie o dispositivo para um arquivo. O arquivo resultante ir ser uma imagem de disco completa do sistema de arquivos sobre o CDa ROM no acionador por exemplo: % cp /dev/cdrom /tmp/imagem-cdrom Esse comando pode demorar muitos minutos, dependendo do CD-ROM que voc estiver copiando e da velocidade de seu acionador de CD/DVD. O e arquivo imagem resultante ir ser to grande quanto grande for o contedo a a u do CD-ROM/DVD. Agora voc pode montar essa imagem de CD-ROM/DVD sem ter o CDe ROM/DVD original no acionador. Por exemplo, para montar a imagem gravada no diretrio /media/cdrom, use a seguinte linha: o % mount -o loop=/dev/loop0 /tmp/imagem-cdrom /media/cdrom Pelo fato de a imagem estar armazenada em um acionador de disco r gido, a referida imagem ir funcionar mais rapidamente que o acionador de disco a de CD-ROM. Note que a maioria dos CD-ROMs usam o sistema de arquivos do tipo iso9660.

6.6

PTYs

Se voc executar o comando mount sem argumentos de linha de comando, e o que mostrar os sistemas de arquivos montados em seu sistema, voc ir a e a 13 notar uma linha semelhante ` seguinte : a none on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620)
13

Nota do tradutor: atualizada usando ubunto 10.04.

179

Isso indica que um tipo especial de sistema de arquivos, devpts, est a montado em /dev/pts. Esse sistema de arquivos, que no est associado a a a nenhum dispositivo de hardware, um sistema de arquivos mgico que e a e criado pelo kernel do GNU/Linux. Esse sistema de arquivos mgico similar a e ao sistema de arquivos /proc; veja Cap tulo 7 para maiores informaes sobre co como esse sistema de arquivos mgico trabalha. a Da mesma forma que o diretrio /dev, o diretrio /dev/pts contm entrao o e das correspondentes a dispositivos. Mas diferentemente do /dev, que um die retrio comum, /dev/pts um diretrio especial que criado dinmicamente o e o e a pelo kernel do GNU/Linux. O contedo do diretrio varia com o tempo e u o reete o estado do sistema que est sendo executado. a As entradas em /dev/pts correspondem a pseudo-terminais (ou pseudoTTYs, ou PTYs). GNU/Linux cria um PTY para toda nova janela de terminal que voc abre e mostra uma entrada correspondente em /dev/pts. O e dispositivo PTY atua como um dispositivo de terminal aceita entradas a partir do teclado e mostra sa no formato texto dos programas que da executam nele. PTYs so numerados, e o nmero do PTY o nome da a u e correspondente entrada no /dev/pts. Voc pode mostrar o dispositivo de terminal associado a um processo e usando o comando ps. Especique tty como um dos campos de um formato personalizado com a opo -o. Para mostrar o ID do processo, o TTY ca associado, e a linha de comando de cada processo compartilhando o mesmo terminal, use o comando ps -o pid,tty,cmd .

6.6.1

Uma Demonstrao de PTY ca

Por exemplo, voc pode determinar o PTY associado a uma janela de termie nal especicada chamando na janela respectiva o comando abaixo: % ps -o pid,tty,cmd PID TT CMD 28832 pts/4 bash 29287 pts/4 ps -o pid,tty,cmd Essa janela particular de terminal est executando em PTY 4. a O PTY tem uma correspondente entrada em /dev/pts: % ls -l /dev/pts/4 crw--w---1 samuel

tty

136,

4 Mar

8 02:56 /dev/pts/4

Note que o referido PTY um dispositivo de caractere, e seu dono o e e dono do processo para o qual ele foi criado. 180

Voc pode ler de ou escrever para o dispositivo PTY. Se voc l do dise e e positivo PTY, voc ir desviar a entrada do teclado que seria de outra forma e a enviada para o programa executando no PTY. Se voc escreve para o dispoe sitivo PTY, os dados iro aparecer naquela janela. a Tente abrir uma nova janela de terminal, e determine seu nmero de PTY u digitando ps -o pid,tty,cmd . De outra janela, escreva algum texto para o dispositivo do PTY. Por exemplo, se o nmero da nova janela de terminal u for 7, use o comando abaixo de outra janela: % echo Al\^o, outra janela! > /dev/pts/7 A sa aparece na nova janela de terminal. Se voc fecha a nova janela da e de terminal, a entrada 7 em /dev/pts desaparece. Se voc usar o comando ps para determinar o TTY de um terminal virtual e de modo texto (pressione Ctrl+Alt+F1 para mudar para o primeiro terminal virtual, por exemplo), voc ir ver que esse primeiro terminal virtual est e a a executando em um dispositivo de terminal comum ao invs de em um PTY: e % ps -o pid,tty,cmd PID TT CMD 29325 tty1 -bash 29353 tty1 ps -o pid,tty,cmd

6.7

A chamada de sistema ioctl

A chamada de sistema ioctl uma interface de propsito geral para controlar e o dispositivos de hardware. O primeiro argumento a ioctl um descritor de e arquivo, o qual deve ser aberto para o dispositivo que voc deseja controlar. e O segundo argumento um cdigo de requisio que indica a operao que e o ca ca voc deseja executar. Vrios cdigos de requisio esto dispon e a o ca a veis para diferentes dispositivos. Dependendo do cdigo de requisio, pode existir o ca argumentos adicionais fornecendo dados a ioctl. Muitos desses cdigos de requisio dispon o ca veis para vrios dispositivos a 14 esto listados na pgina de manual de ioctl list . O uso de ioctl geralmente a a requer um entendimento detalhado do acionador de dispositivo correspondente ao dispositivo de hardware que voc deseja controlar. A maioria desses e dispositivos um pouco especializado e esto alm do objetivo desse livro. e a e Todavia, iremos mostrar um exemplo para dar a voc uma degustao de e ca como ioctl usada. e
14

Nota do tradutor:man ioctl list.

181

Listagem 6.2: (cdrom-eject.c) Ejeta um CD-ROM/DVD


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include #include #include #include #include #include < f c n t l . h> <l i n u x / cdrom . h> <s y s / i o c t l . h> <s y s / s t a t . h> <s y s / t y p e s . h> <u n i s t d . h>

i n t main ( i n t a r g c , char a r g v [ ] ) { / Open a f i l e d e s c r i p t o r t o t h e d e v i c e i n t f d = open ( a r g v [ 1 ] , O RDONLY) ; / E j e c t t h e CD ROM. / i o c t l ( f d , CDROMEJECT) ; / C l o s e t h e f i l e d e s c r i p t o r . / c l o s e ( fd ) ; return 0 ; }

specified

on t h e command l i n e .

A Listagem 6.2 mostra um programa curto que ejeta o disco em um acionador de CD-ROM/DVD (se o acionador suportar isso). O programa recebe um unico argumento de linha de comando, o acionador de dispositivo do CD-ROM. O programa abre um descritor de arquivo para o dispositivo e chama ioctl com o cdigo de requisio CDROMEJECT. Essa requisio, o ca ca denida no arquivo de cabealho <linux/cdrom.h>, instrui o dispositivo a c ejetar o disco. Por exemplo, se seu sistema tiver um acionador de CD-ROM/DVD IDE conectado como dispositivo mestre na placa controladora IDE secundria, o a dispositivo correspondente /dev/hdc. Para ejetar o disco do acionador, use e o comando adiante: % ./cdrom-eject /dev/hdc

182

Cap tulo 7 O Sistema de Arquivos /proc


CHAMAR O COMANDO mount SEM ARGUMENTOS ir mostrar os a sistemas de arquivo montados atualmente em seu computador GNU/Linux. Voc ir ver uma linha que se parece com a seguinte1 : e a none on /proc type proc (rw) Esse o sistema de arquivo especial /proc. Note que o primeiro campo, e none, indica que esse sistema de arquivo no associado com um dispositivo a e de hardware tal como um acionador de disco. Ao invs disso, /proc uma e e janela para dentro do kernel do GNU/Linux que est executando. Arquivos a no sistema de arquivo /proc no correspondem a arquivos atuais em um a dispositivo f sico. Ao invs disso, eles so objetos mgicos que comportame a a se como arquivos mas fornecem acesso a parmetros, estruturas de dados, e a estat sticas no kernel. O contedo desses arquivos no so sempre blocos u a a xos de dados, como os contedos dos arquivos comuns. Ao invs disso, eles u e so gerados instantneamente pelo kernel do GNU/Linux quando voc l de a a e e um arquivo. Voc tambm pode mudar a congurao do kernel que est e e ca a sendo executado escrevendo em certos arquivos no sistema de arquivo /proc. Vamos olhar um exemplo:
% ls -l /proc/version -r--r--r-1 root root 0 Jan 17 18:09 /proc/version

Note que o tamanho do arquivo zero; pelo fato de os contedos dos e u arquivos serem gerados pelo kernel, o conceito de tamanho de arquivo no a e aplicvel. Tambm, se voc tentar esse comando propriamente dito, voc ir a e e e a notar que a hora de modicao corresponde ` hora atual. ca a Qual o contedo desse arquivo? O contedo de /proc/version consiste u u de uma sequncia de caracteres descrevendo o nmero de verso do kernel e u a
1

Nota do tradutor: no slackware 13.1 padro a linha proc on /proc type proc (rw). a e

183

do GNU/Linux. O /proc/version contm a informao de verso que pode e ca a ser obtida por meio da chamada de sistema uname, descrita no Cap tulo 8,Chamadas de Sistema do GNU/Linux na Seo 8.15, A chamada de ca Sistema uname acrescentando informaes adicionais tais como a verso do co a compilador que foi usado para compilar o kernel. Voc pode ler de /proc/vere sion como voc leria de qualquer outro arquivo. Por exemplo, um caminho e fcil para mostrar o contedo do /proc/version com o comando cat 2 . a u e
% cat /proc/version Linux version 2.2.14-5.0 (root@porky.devel.redhat.com) (gcc version egcs-2.91. 66 19990314/Linux (egcs-1.1.2 release)) \#1 Tue Mar 7 21:07:39 EST 2000

As vrias entradas no sistema de arquivo /proc so descritas extensivaa a mente na pgina de manual do proc (Seo 5). Para visualizar a descrio, a ca ca chame o comando: % man 5 proc Nesse cap tulo, ns iremos descrever alguns dos recursos do sistema de o arquivo /proc os quais esto em sua maioria feitos para serem uteis a proa gramadores de aplicaes, e ns iremos fornecer exemplos de como us-los. co o a Alguns dos recursos do /proc esto dispon a veis para depurao, tambm. ca e Se voc est interessado em exatamente como /proc trabalha, d uma e a e olhada nos cdigos fonte kernel do GNU/Linux, no diretrio /usr/src/lio o nux/fs/proc/.

7.1

Extraindo Informao do /proc ca

A maioria das entradas no /proc fornece informaes formatadas para seco rem leg veis a humanos, mas os fomatos so simples o suciente para serem a facilmente fornecidos a programas. Por exemplo, /proc/cpuinfo contm ine 3 formao sobre a CPU do sistema (ou CPUs, para uma mquina com vrios ca a a processadores). A sa uma tabela de valores, um valor por linha, com da e uma descrio do valor e um dois pontos precedendo cada valor. ca Por exemplo, a sa pode se parecer como segue4 : da
Nota do tradutor: no slackware 13.1 temos: Linux version 2.6.33.4-smp (root@midas) (gcc version 4.4.4 (GCC) ) #2 SMP Wed May 12 22:47:36 CDT 2010 3 Nota do tradutor: Central Processing Unit. 4 Nota do tradutor: veja o Apndice G na Seo G.1 para maiores detalhes. e ca
2

184

% cat /proc/cpuinfo processor :0 vendor_id : GenuineIntel cpu family :6 model :5 model name : Pentium II (Deschutes) stepping :2 cpu MHz : 400.913520 cache size : 512 KB fdiv_bug : no hlt_bug : no sep_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level :2 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 mmx fxsr bogomips : 399.77

Iremos descrever a interpretao de alguns desses campos na Seo 7.3.1, ca ca Informaes sobre a CPU. co Um caminho simples para extrair um valor dessa sa ler o arquivo e coda e loc-lo em uma rea de armazenamento temporrio e analis-lo em memria a a a a o usando sscanf. A Listagem 7.1 mostra um exemplo disso. O programa inclui a funo get cpu clock speed que l de /proc/cpuinfo que est na memria e ca e a o extrai a primeira velocidade do clock da CPU. 185

Listagem 7.1: (clock-speed.c) Extraindo a Velocidade de Clock da CPU de /proc/cpuinfo


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <s t d i o . h> #include < s t r i n g . h> / R e t u r n s t h e c l o c k s p e e d o f t h e s y s t e m s CPU i n MHz , a s r e p o r t e d b y / proc / cpuinfo . On a m u l t i p r o c e s s o r machine , r e t u r n s t h e s p e e d o f t h e f i r s t CPU . On e r r o r r e t u r n s z e r o . / float get cpu clock speed { FILE f p ; char b u f f e r [ 1 0 2 4 ] ; s i z e t bytes read ; char match ; float clock speed ; ()

/ Read t h e e n t i r e c o n t e n t s o f / p r o c / c p u i n f o i n t o t h e fp = fopen ( / proc / cpuinfo , r ) ; bytes read = fread ( buffer , 1 , sizeof ( b u f f e r ) , fp ) ; f c l o s e ( fp ) ; / B a i l i f r e a d f a i l e d o r i f b u f f e r i s n t b i g e n o u g h . i f ( b y t e s r e a d == 0 | | b y t e s r e a d == s i z e o f ( b u f f e r ) ) return 0 ; / NUL e r m i n a t e t h e t e x t . t / b u f f e r [ b y t e s r e a d ] = \0 ; / L o c a t e t h e l i n e t h a t s t a r t s w i t h c p u MHz . / match = s t r s t r ( b u f f e r , cpu MHz ) ; i f ( match == NULL) return 0 ; / P a r s e t h e l i n e t o e x t r a c e t h e c l o c k s p e e d . / s s c a n f ( match , cpu MHz : %f , &c l o c k s p e e d ) ; return c l o c k s p e e d ; }

buffer .

i n t main ( ) { p r i n t f ( CPU c l o c k return 0 ; }

s p e e d : %4.0 f MHz\n ,

get cpu clock speed

() ) ;

Seja informado, todavia, que os nomes, as semnticas, e formatos de a entradas no sistema de arquivo /proc podem mudar em novas revises de o kernel do GNU/Linux. Se voc us-lo em um programa, voc deve garantir e a e que o comportamento do programa se desatualiza se a entrada do /proc for retirada ou estiver formatada de forma inesperada.

7.2

Entradas dos Processos

O sistema de arquivo /proc contm uma entrada de diretrio para cada proe o cesso executando no sistema GNU/Linux. O nome de cada diretrio o ID de o e 5 processo do processo correspondente . Esses diretrios aparecem e desapareo cem dinmicamente ` medida que processos iniciam e encerram no sistema. a a Cada diretrio contm muitas entradas fornecendo acesso a informaes soo e co bre o precsso que est executando. Foi a partir desses diretrios de processos a o que o sistema de arquivos /proc recebeu seu nome.
Em alguns sistemas UNIX, os IDs de processo so completados com zeros. a GNU/Linux, eles no so. a a
5

No

186

Cada diretrio de processo contm as seguintes entradas6 : o e cmdline contm a lista de argumentos para o processo. A entrada e cmdline descrita na Seo 7.2.2, Lista de Argumentos do Proe ca cesso. cwd um link simblico que aponta para o diretrio atual de trae o o balho do processo (como escolhido, por exemplo, com a chamada chdir ). environ contm o ambiente do processo. A entrada environ dese e crita na Seo 7.2.3, Ambiente de Processo. ca exe um link simblico que aponta para a imgem executvel roe o a a dando no processo. A entrada exe descrita na Seo 7.2.4, Exee ca cutvel do Processo. a fd um subdiretrio que contm entradas para os descritores abere o e tos pelo processo. Essas entradas so descritas na Seo 7.2.5, a ca Descritores de Arquivo do Processo. maps mostra informao sobre arquivos mapeados dentro da rea ca a de endereamento de memria do processo. Veja o Cap c o tulo 5, Comunicao Entre Processos Seo 5.3, Arquivos Mapeados em ca ca Memria para detalhes de como arquivos mapeados em memria o o trabalham, como mapas mostram o intervalo de endereamento no c espao de endereamento do processo dentro do qual o arquivo c c e mapeado, as permisses desses endereos, o nome do arquivo, e o c outras informaes. co A tabela de mapeamento para cada processo mostra o executvel a rodando no processo, qualquer biblioteca compartilhada carregada, e outros arquivos que o processo tenha mapeado. root um link simblico para o diretrio principal desse processo. o o Comumente, esse link aponta para o diretrio / o diretrio ra o o z do sistema. O diretrio principal de um processo pode ser modio cado usando a chamada de sistema chroot ou o comando chroot a .
a A chamada chroot e o comando chroot esto fora do escopo desse livro. Veja a a pgina de manual dochroot na seo 1 para informao sobre o comando (chame man a ca ca 1 chroot), ou a pgina de manual na Seo 2 (chame man 2 chroot) para informaes a ca co sobre a chamada de sistema. 6

Nota do tradutor: veja o Apndice G na Seo G.2 para a listagem de outras entradas. e ca

187

stat contm muitas informaes de stuao atual e estat e co ca stica sobre o processo. Esses dados so os mesmos dados apresentados na a entrada status, mas no formato de linha numrada, todos em uma e unica linha. O formato dif para ler mas pode ser mais adequado e cil para informar a programas. Se voc desejar usar a entrada stat em e seus programas, veja a pgina de manual do proc a qual descreve a seu contedo, chamando man 5 proc. u statm contm informao sobre a memria usada pelo processo. A e ca o entrada statm descrita na Seo 7.2.6, Estat e ca sticas da Memria o do Processo. status contm grande quantidade de informao sobe a situao e ca ca atual e informao estat ca stica sobre o processo, formatados para serem compreens veis a humanos. A Seo 7.2.7, Estat ca sticas de Processo contm uma descrio da entrada status. e ca cpu aparece somente em kernels GNU/Linux SMP. A entrada cpu contm um fracionamento de tempo de processo (usurio e sistema) e a pela CPU. Note que por razes de segurana, as permisses de algumas entradas so o c o a posicionadas de forma que somente o usurio que dono do processo ou o a e super-usurio) pode acess-las. a a

7.2.1

/proc/self

Uma entrada adicional no sistema de arquivo /proc torna fcil para um proa grama usar /proc para encontrar informao sobre seu prprio processo. A ca o entrada /proc/self um link simblico para o diretrio do /proc correspone o o dente ao processo atual. O objetivo do link /proc/self depende de qual processo olha para o link simblico /proc/self : Cada processo v seu prprio o e o diretrio de processo como alvo do link. o Por exemplo, o programa na Listagem 7.2 l o alvo do link /proc/self e para determinar seu ID de processo. (Estamos fazendo isso dessa maneira para propsitos ilustrativos somente; chamando a funo getpid, descrita no o ca Cap tulo 3, Processos na Seo 3.1.1, Identicadores de Processos est ca a uma forma muito fcil para fazer a mesma coisa.) O programa a seguir usa a a chamada de sistema readlink, descrita na Seo 8.11, readlink: Lendo Links ca Simblicos para extrair o alvo do link simblico. o o 188

Listagem 7.2: (get-pid.c) Obtendo o ID de Processo de /proc/self


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <s t d i o . h> #include <s y s / t y p e s . h> #include <u n i s t d . h> / R e t u r n s t h e p r o c e s s i d o f t h e the / proc / s e l f symlink . / calling processes , as d e t e r m i n e d from

pid t get pid from proc self () { char t a r g e t [ 3 2 ] ; int pid ; / Read t h e t a r g e t o f t h e s y m b o l i c l i n k . / r e a d l i n k ( / proc / s e l f , target , sizeof ( t a r g e t ) ) ; / The t a r g e t i s a d i r e c t o r y named f o r t h e p r o c e s s s s c a n f ( t a r g e t , %d , &p i d ) ; return ( p i d t ) p i d ; } i n t main ( ) { p r i n t f ( / p r o c / s e l f r e p o r t s p r o c e s s i d %d\n , ( int ) g e t p i d f r o m p r o c s e l f ( ) ) ; p r i n t f ( g e t p i d ( ) r e p o r t s p r o c e s s i d %d\n , ( i n t ) return 0 ; }

id .

getpid

() ) ;

7.2.2

Lista de Argumentos do Processo

A entrada cmdline contm a lista de argumentos de um processo (veja o e Cap tulo 2,Escrevendo Bom Software GNU/Linux Seo 2.1.1,A Lista de ca Argumentos). Os argumentos so mostrados como uma unica sequncia de a e caracteres, com os argumentos separados por NULs. A maioria das funes co de sequncia de caractere esperam que toda a sequncia de caracteres seja e e terminada por um NUL unico e no ir manipular NULs embutidos dentro da a a sequncia de caracteres, de forma que voc ir ter que manipular o contedo e e a u especialmente. 189

NUL vs. NULL NUL um caractere com valor inteiro 0. Esse caractere diferente do caractere e e NULL, que um apontador com valor 0. Na linguagem C, uma sequncia de e e caracteres comumente terminada com um caratere NUL. Por exemplo, a e sequncia de caracteres Hello, world! ocupa 14 bytes a pelo fato de existir e um NUL impl cito aps o ponto de exclamao indicando o nal da sequncia o ca e de caracteres. NULL, por outro lado, um valor de apontador que voc pode estar certo que e e nunca corresponder a um endereo de memria real em seu programa. a c o Em C e em C++, NUL representado como a constante do tipo caractere e \0, ou (char) 0. A denio de NULL difere entre sistemas operacionais; em ca GNU/Linux, o caractere NULL denido como ((void*)0) em C e simplese mente 0 em C++.
Nota do tradutor: o espao, a v c rgula e a exclamao contam como letras ca e cada letra ocupa um byte. Se seu computador tiver um processador de 32 bits cada byte tem o tamanho de 32 bits, idem para o computador de 64 bits. Cada bit corresponde ao d gito binrio e s pode assumir dois valores: 0 e 1. a o
a

Na Seo 2.1.1, mostramos um programa na Listagem 2.1 que mostrava ca na tela sua prpria lista de argumentos. Usando as entradas de cmdline no o sistema de arquivo /proc, podemos implementar um programa que mostra os argumentos de outro processo. A Listagem 7.3 o tal programa; A Listagem e 7.3 mostra na tela a lista de argumentos do processo com o ID de processo especicado. Pelo fato de poderem existir muitos NULs no contedo da enu trada cmdline em lugar de um unico NUL no nal, podemos determinar o comprimento da sequncia de caracteres com a funo strlen (que sime ca plesmente conta o nmero de caracteres at encontrar um NUL). Ao invs u e e disso, determinamos o comprimento da da leitura da entrada cmdline, o qual retorna o nmero de bytes que foram lidos. u 190

Listagem 7.3: (print-arg-list.c) Mostra na Tela a Lista de Arguentos de um Processo que est Executando a
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include #include #include #include #include #include < f c n t l . h> <s t d i o . h> < s t d l i b . h> <s y s / s t a t . h> <s y s / t y p e s . h> <u n i s t d . h> list , one a r g u m e n t to a line , of the process

/ P r i n t s t h e a r g u m e n t g i v e n b y PID . /

void p r i n t p r o c e s s a r g l i s t { int fd ; char f i l e n a m e [ 2 4 ] ; char a r g l i s t [ 1 0 2 4 ] ; s i z e t length ; char n e x t a r g ;

( pid t

pid )

/ G e n e r a t e t h e name o f t h e c m d l i n e f i l e f o r t h e p r o c e s s . / s n p r i n t f ( f i l e n a m e , s i z e o f ( f i l e n a m e ) , / p r o c/%d/ c m d l i n e , ( i n t ) p i d ) ; / Read t h e c o n t e n t s o f t h e f i l e . / f d = open ( f i l e n a m e , O RDONLY) ; l e n g t h = read ( fd , a r g l i s t , s i z e o f ( a r g l i s t ) ) ; c l o s e ( fd ) ; / r e a d d o e s n o t NUL e r m i n a t e t h e b u f f e r , s o do i t h e r e . / t a r g l i s t [ l e n g t h ] = \0 ; / Loop o v e r a r g u m e n t s . A r g um e n t s a r e s e p a r a t e d b y NULs . / next arg = a r g l i s t ; while ( n e x t a r g < a r g l i s t + l e n g t h ) { / P r i n t t h e a r g u m e n t . Each i s NUL e r m i n a t e d , s o j u s t t r e a t i t t l i k e an o r d i n a r y s t r i n g . / p r i n t f ( %s \n , n e x t a r g ) ; / Advance t o t h e n e x t a r g u m e n t . Since each argument i s NUL e r m i n a t e d , s t r l e n c o u n t s t h e l e n g t h o f t h e n e x t a r g u m e n t , t not t h e e n t i r e argument l i s t . / n e x t a r g += s t r l e n ( n e x t a r g ) + 1 ; } } i n t main ( i n t a r g c , char a r g v [ ] ) { p i d t pid = ( p i d t ) a t o i ( argv [ 1 ] ) ; p r i n t p r o c e s s a r g l i s t ( pid ) ; return 0 ; }

Por exemplo, suponhamos que o processo 372 seja o programa que trabalha em segundo plano chamado system logger, isto , o syslogd. e

% ps 372 PID TTY STAT TIME COMMAND 372 ? S 0:00 syslogd -m 0 % ./print-arg-list 372 syslogd -m 0 Nesse caso, syslogd foi chamado com os argumentos -m 0 . 191

7.2.3

Ambiente de Processo

A entrada environ contm uma descrio do ambiente do processo (veja a e ca Seo 2.1.6, O Ambiente). Da mesma forma que a entrada cmdline, as ca variveis de memria que descrevem o ambiente individual so separadas a o a por NULs. O formato de cada elemento o mesmo que o formato usado na e varivel de ambiente, isto , VARIAVEL=valor. a e A listagem 7.4 mostra uma generalizao do programa na Listagem 2.4 na ca Seo 2.1.6. Essa verso recebe um nmero de ID de processo em sua linha ca a u de comando e mostra o ambiente para aquele processo lendo essa informao ca a partir do /proc. Listagem 7.4: (print-environment.c) Mostra o Ambiente de um Processo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include #include #include #include #include #include < f c n t l . h> <s t d i o . h> < s t d l i b . h> <s y s / s t a t . h> <s y s / t y p e s . h> <u n i s t d . h> variable to a line , of the

/ P r i n t s t h e e n v i r o n m e n t , one e n v i r o n m e n t p r o c e s s g i v e n b y PID . / void p r i n t p r o c e s s e n v i r o n m e n t { int fd ; char f i l e n a m e [ 2 4 ] ; char e n v i r o n m e n t [ 8 1 9 2 ] ; s i z e t length ; char n e x t v a r ; ( pid t pid )

/ G e n e r a t e t h e name o f t h e e n v i r o n f i l e f o r t h e p r o c e s s . / s n p r i n t f ( f i l e n a m e , s i z e o f ( f i l e n a m e ) , / p r o c/%d/ e n v i r o n , ( i n t ) p i d ) ; / Read t h e c o n t e n t s o f t h e f i l e . / f d = open ( f i l e n a m e , O RDONLY) ; l e n g t h = read ( fd , environment , s i z e o f ( environment ) ) ; c l o s e ( fd ) ; / r e a d d o e s n o t NUL e r m i n a t e t h e b u f f e r , s o do i t h e r e . / t e n v i r o n m e n t [ l e n g t h ] = \0 ; / Loop o v e r v a r i a b l e s . V a r i a b l e s a r e s e p a r a t e d b y NULs . / n e x t v a r = environment ; while ( n e x t v a r < e n v i r o n m e n t + l e n g t h ) { / P r i n t t h e v a r i a b l e . Each i s NUL e r m i n a t e d , s o j u s t t r e a t i t t l i k e an o r d i n a r y s t r i n g . / p r i n t f ( %s \n , n e x t v a r ) ; / Advance t o t h e n e x t v a r i a b l e . Since each v a r i a b l e i s NUL e r m i n a t e d , s t r l e n c o u n t s t h e l e n g t h o f t h e n e x t v a r i a b l e , t not the e n t i r e v a r i a b l e l i s t . / n e x t v a r += s t r l e n ( n e x t v a r ) + 1 ; } } i n t main ( i n t a r g c , char a r g v [ ] ) { p i d t pid = ( p i d t ) a t o i ( argv [ 1 ] ) ; p r i n t p r o c e s s e n v i r o n m e n t ( pid ) ; return 0 ; }

7.2.4

O Executvel do Processo a

A entrada exe aponta para o arquivo executvel sendo rodado em um proa cesso. a Seo 2.1.1, explanamos que tipicamente o nome do programa execa 192

cutvel informado como o primeiro elemento da lista de argumentos. Note, a e apesar disso, que isso puramente uma conveno; um programa pode ser e ca chamado com qualquer lista de argumentos. Usando a entrada exe no sistema de arquivo /proc um caminho mais seguro para determinar qual executvel e a est rodando. a Uma tcnica util extrair o caminho contendo o executvel a partir do e e a sistema de arquivo /proc. Para muitos programas, arquivos auxiliares so insa talados em diretrios com caminhos conhecidos relativamente ao executvel o a do programa principal, de forma que necessrio determinar onde aquele e a executvel principal atualmente est. A funo get executable path na Lisa a ca tagem 7.5 determina o caminho do executvel que est rodando no processo a a que est chamando examinando a link simblico /proc/self/exe. a o Listagem 7.5: (get-exe-path.c) Pega o Caminho do Programa Executando Atualmente
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include #include #include #include < l i m i t s . h> <s t d i o . h> < s t r i n g . h> <u n i s t d . h>

/ F i n d s t h e p a t h c o n t a i n i n g t h e c u r r e n t l y r u n n i n g p r o g r a m e x e c u t a b l e . The p a t h i s p l a c e d i n t o BUFFER, w h i c h i s o f l e n g t h LEN . Returns t h e number o f c h a r a c t e r s i n t h e p a t h , o r 1 on e r r o r . / s i z e t g e t e x e c u t a b l e p a t h ( char b u f f e r , s i z e t l e n ) { char p a t h e n d ; / Read t h e t a r g e t o f / p r o c / s e l f / e x e . / i f ( r e a d l i n k ( / p r o c / s e l f / e x e , b u f f e r , l e n ) <= 0 ) return 1; / F i n d t h e l a s t o c c u r e n c e o f a f o r w a r d s l a s h , t h e p a t h s e p a r a t o r . / path end = s t r r c h r ( b u f f e r , / ) ; i f ( p a t h e n d == NULL) return 1; / Advance t o t h e c h a r a c t e r p a s t t h e l a s t s l a s h . / ++p a t h e n d ; / O b t a i n t h e d i r e c t o r y c o n t a i n i n g t h e p r o g r a m b y t r u n c a t i n g t h e path a f t e r the l a s t s l a s h . / p a t h e n d = \0 ; / The l e n g t h o f t h e p a t h i s t h e number o f c h a r a c t e r s up t h r o u g h t h e last slash . / return ( s i z e t ) ( p a t h e n d b u f f e r ) ; } i n t main ( ) { char path [PATH MAX ] ; g e t e x e c u t a b l e p a t h ( path , s i z e o f ( path ) ) ; p r i n t f ( t h i s program i s i n t h e d i r e c t o r y %s \n , path ) ; return 0 ; }

7.2.5

Descritores de Arquivo do Processo

A entrada fd um subdiretrio que contm entradas para os descritores de e o e arquivo abertos por um processo. Cada entrada um link simblico para o e o arquivo ou dispositivo aberto indicado pelo respectivo descritor de arquivo. Voc pode escrever para ou ler desses links simblicos; esses descritores de e o 193

arquivo escrevem para ou leem do correspondente arquivo ou dispositivo aberto no processo alvo. As entradas no subdiretrio fd so chamadas pelos o a nmeros dos descritores de arquivo. u Aqui est um artif que voc pode tentar com entradas fd no /proc. a cio e Abra uma nova janela, e encontre o ID de processo do processo que est a rodando o shell usando o comando ps.

% ps PID TTY 1261 pts/4 2455 pts/4

TIME CMD 00:00:00 bash 00:00:00 ps

Nesse caso, o shell (bash) est rodando no processo 1261. Agora abra uma a segunda janela, e olhe o contedo do subdiretrio fd para aquele processo. u o
% ls -l /proc/1261/fd total 0 lrwx-----1 samuel lrwx-----1 samuel lrwx-----1 samuel

samuel samuel samuel

64 Jan 30 01:02 0 -> /dev/pts/4 64 Jan 30 01:02 1 -> /dev/pts/4 64 Jan 30 01:02 2 -> /dev/pts/4

(Pode haver outras linhas de sa correspondendo a outros descritores da de arquivos abertos tambm.) Relembrando o que mencionamos na Seo e ca 2.1.4, E/S Padro que descritores de arquivo 0, 1, e 2 so inicializados a a para entrada padro, sa padro, e sa de erro, respectivamente. Dessa a da a da forma, por meio de escrita para /proc/1261/fd/1, voc pode escrever para o e 7 dispositivo anexado a stdout para o processo do shell nesse caso, o pseudo TTY na primeira janela. Na segunda janela, tente escrever uma mensagem para aquele arquivo:

% echo "Al\^o, mundo." >> /proc/1261/fd/1 O texto aparece na primeira janela. Descritores de arquivo ao lado de entrada padro, sa padro, e sa a da a da de erro aparecem no subdiretrio fd, tambm. A Listagem 7.6 mostra um o e programa que simplesmente abre um descritor de arquivo para um arquivo especicado na linha de comando e ento entra em um lao para sempre. a c
7

Nota do tradutor: sa padro da a

194

Listagem 7.6: (open-and-spin.c) Abre um Arquivo para Leitura


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include #include #include #include #include < f c n t l . h> <s t d i o . h> <s y s / s t a t . h> <s y s / t y p e s . h> <u n i s t d . h>

i n t main ( i n t a r g c , char a r g v [ ] ) { const char const f i l e n a m e = a r g v [ 1 ] ; i n t f d = open ( f i l e n a m e , O RDONLY) ; p r i n t f ( i n p r o c e s s %d , f i l e d e s c r i p t o r %d i s ( int ) g e t p i d ( ) , ( int ) fd , f i l e n a m e ) ; while ( 1 ) ; return 0 ; }

open t o %s \n ,

Tente executar o programa em uma janela: % ./open-and-spin /etc/fstab in process 2570, file descriptor 3 is open to /etc/fstab Em outra janela, d uma olhada no subdiretrio fd que corresponde a e o esse processo no /proc.
% ls -l /proc/2570/fd total 0 lrwx-----1 samuel lrwx-----1 samuel lrwx-----1 samuel lr-x-----1 samuel

samuel samuel samuel samuel

64 Jan 30 01:30 0 64 Jan 30 01:30 1 -> 64 Jan 30 01:30 2 -> 64 Jan 30 01:30 3 ->

-> /dev/pts/2 /dev/pts/2 /dev/pts/2 /etc/fstab

Note a entrada para o descritor de arquivo 3, apontando para o arquivo /etc/fstab aberto sobre esse descritor. Descritores de arquivo podem ser abertos sobre sockets ou sobre pipes, tambm (veja Cap e tulo 5 para maiores informaes sobre isso). Em tal caso, co o alvo do link simblico correspondente ao descritor de arquivo ir para o o a estado socket ou pipe ao invs de apontar para um arquivo comum ou e dispositivo.

7.2.6

Estat sticas de Memria do Processo o

A entrada statm contm uma lista de sete nmeros, separados por espaos. e u c Cada nmero um contador do nmero de pginas de memria usadas pelo u e u a o processo em uma categoria em particular. As categorias, na ordem em que os nmeros aparecem, so listadas aqui: u a O tamanho total do processo O tamanho do processo residente em memria f o sica 195

A memria compartilhada com outros processos, isto , memria mao e o peada ambas por esse processo e ao menos um outro (tais como bibliotecas compartilhadas ou pginas de memria intocadas do tipo copiea o 8 na-escrita) O tamanho do texto do processo, isto , o tamanho do cdigo do exee o cutvel carregado a O tamanho das bibliotecas compartilhadas mapeadas dentro do espao c de memria desse processo o A memria usada por esse processo para sua pilha o O nmero de pginas sujas, isto , pginas de memria que tenham u a e a o sido modicadas pelo programa

7.2.7

Estat sticas de Processo

A entrada status contm uma variedade de informao sobre o processo, e ca formatada para ser compreens por humanos. Entre essa variedade est vel a o ID do processo e o ID do processo pai, os IDs reais e os IDs efetivos de usurio e do grupo, uso de memria, e mscaras de bits especicando quais a o a sinais so capturados, ignorados, e bloqueados. a

7.3

Informaoes de Hardware c

Muitas das outras entradas no sistema de arquivo /proc fornecem acesso a informaes sobre o hardware do sistema. Embora esses sejam tipicamente de co interesse a conguradores do sistema e a administradores, a informao pode ca ocasionalmente ser do interesse para programadores de aplicao tambm. ca e Iremos mostrar algumas das entradas mais uteis aqui.

7.3.1

Informaes sobre a CPU co

Como mostrado anteriormente, /proc/cpuinfo contm informaes a CPU e co ou CPUs que esto executando o sistema GNU/Linux. O campo Processor a lista o nmero do processador; esse campo 0 para sistemas de um unico u e processador. O fabricante, a Fam da CPU, o Modelo, e os campos Stepping lia habilitam voc a determinar o exato modelo e a reviso da CPU. Mais util, e a os campos Flags mostram quais sinalizadores de CPU esto escolhidos, o a
8

Nota do tradutor: relembrando a Subseo 5.3.4 Mapeamentos Privados. ca

196

que indica os recursos dispon veis nessa CPU. Por exemplo, mmx indica a disponibilidade das instrues extendidas MMX. 9 co A maioria das informaes retornadas por /proc/cpuinfo derivada da co e instruo assembly x86 cpuid. Essa instruo o mecanismo de baixo n ca ca e vel por meio do qual um programa obtm informao sobre a CPU. Para um e ca grande entendimento da sa de /proc/cpuinfo, veja a documentao da da ca instruo cpuid no Manual do Desenvolvedor de Software da Arquitetura ca Intel IA-32, Volume 2: Instruction Set Reference. Esse manual et dispon a vel 10 em http://developer.intel.com/design . O ultimo elemento, bogomips, um valor espec e co do GNU/Linux. Esses bogomips so uma medida da velocidade do processador em torno de um lao a c restrito e sendo portanto um indicador um pouco pobre da velocidade global do processador.

7.3.2

Informao de Dispositivos ca

O arquivo /proc/devices lista os nmeros de dispositivo principal para disu positivos de bloco e de caractere dispon veis para o sistema. Veja o Cap tulo 6, Dispositivos para informaes sobre tipos de dispositivos e nmeros de co u dispositivo.

7.3.3

Informao de Barramento ca

O diretrio /proc/bus abriga as informaes dos dispositivos anexados ao siso co tema via placas de expanso e portas usb e pode tambm incluir dispositivos a e localizados na placa me. Os comando hal-device, lspci e o lsusb, fornecem a as informaes dos dispositivos pci, pci-express e usb anexados ao sistema11 . co

7.3.4

Informaes de Porta Serial co

O arquivo /proc/tty/driver/serial lista informaes de congurao e esco ca tat sticas sobre portas seriais. Portas seriais so numeradas a partir de 012 . a Informao de congurao sobre portas seriais podem tambm ser obtidas, ca ca e
Veja o Manual do Desenvolvedor de Software da Arquitetura Intel IA-32 para documentao sobre instrues MMX, e veja o Cap ca co tulo 9, Cdigo Assembly Embutido nesse o livro a t tulo de fornecer informao sobre como usar essas e outras instrues especiais ca co assembly em programas GNU/Linux. 10 Nota do tradutor:http://www.intel.com/Assets/PDF/manual/253668.pdf 11 Nota do tradutor: esse trecho foi completamente reescrito uma vez que o arquivo /proc/pci no existe nas verses mais recentes do kernel a o 12 Note que sob e Windows, portas seriais so numeradas a partir de 1, de forma que a COM1 corresponde a prota serial nmero 0 em GNU/Linux. u
9

197

bem como modicadas, usando o comando setserial. Todavia, /proc/tty/driver/serial mostra estat sticas adicionais sobre cada contagem de iterrupo ca de porta serial. Por exemplo, a linha a seguir de /proc/tty/driver/serial pode descrever a porta serial 1 (que deve ser a COM2 em Windows): 1: uart:16550A port:2F8 irq:3 baud:9600 tx:11 rx:0 Isso indica que a porta serial est executando atravs de um chip tipo a e 16550A UART, usa a porta de entrada e sa 0x2f8 e a IRQ 3 para coda municaes, e possui a velocidade de 9,600 baud. Atravs da porta serial co e trafegou 11 interrupes de transmisso e 0 interrupes de recepo. co a co ca Veja a seo 6.4, Dispositivos de Hardware para informaes sobre ca co dispostivos seriais.

7.4

Informao do Kernel ca

Muitas das entradas no /proc fornecem acesso a informaes sobre a conco gurao e o estado do kernel que est sendo executado. Algumas dessas ca a entradas esto no n mais alto do /proc; outras entradas encontram-se em a vel /proc/sys/kernel.

7.4.1

Informao de verso ca a

O arquivo /proc/version contm uma longa sequncia de caracteres descree e vendo o nmero de verso do kernel e a verso de compilao. O /proc/veru a a ca sion tambm inclui informao sobre como o kernel foi constru e ca do: o usurio a que o compilou, a mquina na qual foi compilado, a data em que foi feita a a compilao, e a verso do compilador que foi usado para fazer a compilao ca a ca 13 por exemplo :
%cat /proc/version Linux version 2.2.14-5.0 (root@porky.devel.redhat.com) (gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)) \#1 Tue Mar 7 21:07:39 EST 2000

A sa acima indica que o sistema est executando um release 2.2.14 da a do kernel do GNU/Linux, que foi compilado com o EGCS release 1.1.2. (EGCS, Experimental GNU Compiler System, que foi o precursos do atual projeto GCC.) Os mais importantes itens nessa sa da, o nome do sistema operacional e a verso do kernel e a reviso do mesmo, esto dispon a a a veis em entradas
13

Nota do tradutor: veja um outro exemplo no Apndice G Seo G.3. e ca

198

separadas do /proc tambm. As entradas do /proc so respectivamente: e a /proc/sys/kernel/ostype, /proc/sys/kernel/osrelease, e /proc/sys/kernel/version.

% cat /proc/sys/kernel/ostype Linux % cat /proc/sys/kernel/osrelease 2.2.14-5.0 % cat /proc/sys/kernel/version #1 Tue Mar 7 21:07:39 EST 2000

7.4.2

Nome do Host e Nome de Dom nio

As entradas /proc/sys/kernel/hostname e /proc/sys/kernel/domainname carregam o nome de host do computador e o nome de dom nio, respectivamente. Essa informao a mesma retornada pela chamada de sistema uname, descca e crita na Seo 8.15. ca

7.4.3

Utilizao da Memria ca o

A entrada /proc/meminfo contm informao sobre o uso da memria do e ca o sistema. A informao est presente para ambos memria f ca a o sica e espao c swap. Por exemplo: 199

$ cat /proc/meminfo MemTotal: 1995692 MemFree: 1341280 Buffers: 120888 Cached: 289868 SwapCached: 0 Active: 263144 Inactive: 285124 Active(anon): 141712 Inactive(anon): 16 Active(file): 121432 Inactive(file): 285108 Unevictable: 0 Mlocked: 0 HighTotal: 1187464 HighFree: 729740 LowTotal: 808228 LowFree: 611540 SwapTotal: 5277304 SwapFree: 5277304 Dirty: 80 Writeback: 0 AnonPages: 137516 Mapped: 52728 Shmem: 4212 Slab: 46616 SReclaimable: 37868 SUnreclaim: 8748 KernelStack: 2088 PageTables: 4108 NFS_Unstable: 0 Bounce: 0 WritebackTmp: 0 CommitLimit: 6275148 Committed_AS: 518892 VmallocTotal: 122880 VmallocUsed: 76848 VmallocChunk: 34812 HardwareCorrupted: 0 HugePages_Total: 0 HugePages_Free: 0 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 4096 DirectMap4k: 12280 DirectMap4M: 897024

kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB kB

kB kB kB

A sa acima mostra 1948MB de memria f da o sica, dos quais 1309MB esto a livres, e 5153MB de espao swap, todo livre. Relacionado a memria f c o sica trs outros valores so mostrados: e a Shmem mostra o total de memria compartilhada atualmente alocada o no sistema (veja a Seo 5.1, Memria Compartilhada). ca o Buers mostra a memria alocada pelo GNU/Linux para buers de o dispositivos de bloco. Esses buers so usados por acionadores de a dispositivo para manter blocos de dados sendo lidos do e escritos para o disco. Cached mostra a memria alocada pelo GNU/Linux para cache de o pgina. Essa memria usada para acessos de cache para arquivos a o e mapeados. Voc pode usar o comando free para mostrar a mesma informao de e ca memria. o 200

7.5

Acionadores, Montagens, e Sistemas de Arquivos

O sistema de arquivo /proc tambm contm informao sobre os acionadores e e ca de disco presentes no sistema e os sistemas de arquivo montados nesse mesmo sistema.

7.5.1

Sistemas de Arquivo

A entrada /proc/lesystems mostra os tipos de sistema de arquivo conhecidos do kernel. Note que essa lista no muito util pelo fato de no ser completa: a e a Sistemas de arquivo podem ser carregados e descarregados dinamicamente como mdulos do kernel. O contedo do /proc/lesystems lista somente o u tipos de sistema de arquivo que ou so estat a sticamtente linkados para dentro do kernel ou so atualmente carregados. Outros sistema de arquivo podem a estar dispon veis no sistema como mdulos mas podem no ter sido chamados o a ainda.

7.5.2

Acionadores e Parties co

O sistema de arquivo /proc inclui informaes sobre dispositivos conectados co a ambas as controladoras IDE e SCSI (se estiverem inclu das). Em sistemas t picos, o subdiretrio /proc/ide pode conter um ou amo bos dos dois subdiretrios, ide0 e ide1, correspondentes ` controladora IDE o a primria e ` controladora IDE secundria no sistema14 . A esses subdiretrios a a a o contero adicionais subdiretrios correspondendo aos dispositivos f a o sicos conectados `s controladoras. Os diretrios de dispositivos ou controladoras a o podem estar ausentes se GNU/Linux no tiver reconhecido quaisquer disa positivos conectados. Os caminhos completos correspondentes aos quatro poss veis dispositivos IDE so listados na tabela 9.1. a Veja a Seo 6.4, Dispositivos de Hardware para mais informao sobre ca ca nomes de dispositivos IDE. Cada diretrio de dispositivo IDE contm muitas entradas fornecendo o e acesso a identicao e informao de congurao para o dispositivo. Alguca ca ca mas das mais uteis esto listadas aqui: a model contm a sequncia de caracteres com a identicao do modelo e e ca do dispositivo.
Se adequadamente congurado, o kernel do GNU/Linux pode suportar controladoras IDEs adicionais. Essas IDEs adicionais devem ser numeradas sequncialmente a partir de e ide2.
14

201

Tabela 7.1: Caminhos Completos para os Quatro Poss veis Dispositivos IDE Controladora Dispositivo Subdiretrio o Primria a Mestre /proc/ide/ide0/hda/ Primria a Escravo /proc/ide/ide0/hdb/ Secundria a Mestre /proc/ide/ide1/hdc/ Secundria a Escravo /proc/ide/ide1/hdd/ media contm o tipo de m do dispositivo. Poss e dia veis valores so disk, a cdrom, tape, oppy, e UNKNOWN. capacity contm a capacidade do dispositivo, em blocos de 512-byte. e Note que para dispositivos de CD-ROM, o valor ir ser 231 1, no a a a capacidade do disco no acionador. Note que o valor em capacidade representa a capacidade do disco f sico inteiro; a capacidade dos sistemas de arquivo contidos em parties do disco ir ser menor. co a Por exemplo, os comandos abaixo mostram como determinar o tipo de m dia e a identicao do dispositivo para o dispositivo mestre conectado ca a ` controladora IDE secundria. Nesse caso, verica-se ser um acionador de a CD-ROM Toshiba. % cat /proc/ide/ide1/hdc/media cdrom % cat /proc/ide/ide1/hdc/model TOSHIBA CD-ROM XM-6702B Se dispositivos SCSI estiverem presentes no sistema, /proc/scsi/scsi contm e um sumrio de seus valores de identicao. Por exemplo, o contedo pode a ca u se parecer com o que segue 15 : % cat /proc/scsi/scsi Attached devices: Host: scsi0 Channel: 00 Id: 00 Lun: 00 Vendor: QUANTUM Model: ATLAS_V__9_WLS Rev: 0230 Type: Direct-Access ANSI SCSI revision: 03 Host: scsi0 Channel: 00 Id: 04 Lun: 00 Vendor: QUANTUM Model: QM39100TD-SW Rev: N491 Type: Direct-Access ANSI SCSI revision: 02
15

Nota do tradutor: veja a Seo G.4 do Apndice G para um exemplo adicional. ca e

202

Esse computador contm uma controladora SCSI de canal simples (desige nada scsi0), na qual dois acionadores de discos da marca Quantum esto a conectados, com IDs de dispositivo SCSI 0 e 4. A entrada /proc/partitions mostra as parties dos dispositivos de disco co reconhecidos. Para cada partio, a sa inclui o nmero de dispositivo princa da u cipal e secundrio, o nmero de blocos de 1024-byte, e o nome de dispositivo a u correspondente a aquela partio. ca A entrada /proc/sys/dev/cdrom/info mostra informaes diversar sobre co a capacidade dos acionadores de CD-ROM/DVD. Os campos explicam-se a s mesmos 16 : % cat /proc/sys/dev/cdrom/info CD-ROM information, Id: cdrom.c 2.56 1999/09/09 drive name: hdc drive speed: 48 drive \# of slots: 0 Can close tray: 1 Can open tray: 1 Can lock tray: 1 Can change speed: 1 Can select disk: 0 Can read multisession: Can read MCN: 1 Reports media changed: Can play audio: 1

1 1

7.5.3

Montagens

O arquivo /proc/mounts fornece um sumrio dos sistemas de arquivo mona tados. Cada linha corresponde a um unico descritor de montagem e mostra o dispositivo montado, o ponto de montagem, e outra informao. Note que ca /proc/mounts contm a mesma informao que o arquivo comum /etc/mtab, e ca o qual automaticamente atualizado pelo comando mount. e Segue addiante os elementos de um descritor de montagem: O primeiro elemento na linha o dispositivo montado (veja Cap e tulo 6). Para sistemas de arquivo especiais tais como o sistema de arquivo /proc, esse elemento none. e
16

Nota do tradutor: veja a Seo G.5 do Apndice G para um exemplo adicional. ca e

203

O segundo elemento o ponto de montagem, o local no sistema de e arquivo ra no qual o contedo do sistema de arquivo montado aparece. z u Para o sistema de arquivo ra propriamente dito, o ponto de montagem z listado com /. Para acionadores swap, o ponto de montagem listado e e como swap. O terceiro elemento o tipo do sistema de arquivo. Atualmente17 ,a e maioria dos sistemas GNU/Linux usam o sistema de arquivo ext2 para acionadores de disco, mas acionadores DOS ou Windows podem ser montados com outros tipos de sistema de arquivo, tais como fat ou vfat. A maioria dos CD-ROMs/DVDs possuem um sistema de arquivo iso9660. Veja a pgina de manual do comando mount para uma lista a de tipos de sistema de arquivo. O quarto elemento mostra sinalizadores de montagem. esses sinalizadores de montagem so opes que foram especicadas quando o comando a co mount foi chamado. Veja a pgina de manual do comando mount para a uma explanao de sinalizadores para os vrios tipos de sistema de ca a arquivo. No /proc/mounts, os dois ultimos elementos so sempre 0 e no possuem a a signicado. Veja a pgina de manual do fstab para detalhes sobre o formato dos a descritores de montagem 18 . GNU/Linux inclui funes para ajudar voc a co e informar descritores de montagem; veja a pgina de manual para a funo a ca getmntent para informao de como us-la. ca a

7.5.4

Travas

A Seo 8.3, A chamada de Sistema fcntl : Travas e Outras Operaes em ca co Arquivos descreve como usar a chamada de sistema fcntl para manipular travas de leitura e escrita sobre arquivos. A entrada /proc/locks descreve todas as travas de arquivo atualmente funcionando no sistema. Cada linha na sa corresponde a uma trava. da Para travas criadas com fcntl, as primeiras duas entradas na linha so a POSIX ADVISORY 19 . A terceira entrada na linha pode ser ou WRITE ou READ, dependendo do tipo da trava. O prximo nmero o ID de processo o u e do processo mantendo a trava. Os seguintes trs nmeros, separados por dois e u
Nota do tradutor:2001 O arquivo /etc/fstab lista a congurao esttica de montagem do sistema ca a GNU/Linux. 19 Nota do tradutor: veja G.7 para um exemplo adicional
18 17

204

pontos, so os nmeros de dispositivo principal e secundrio do dispositivo a u a sobre o qual o arquivo reside e o nmero do inode, que localiza o arquivo no u sistema de arquivo. O restante da linha mostra valores internos ao kernel que geralmente no so de utilidade. a a O ajuste do contedo de /proc/locks dentro das informaes uteis precisa u co um pouco de trabalho de detetive. Voc pode assistir o /proc/locks em ao, e ca por exemplo, rodando o programa na Listagem 8.2 para criar uma trava de escrita sobre o arquivo /tmp/test-le. % touch /tmp/test-file % ./lock-file /tmp/test-file file /tmp/test-file opening /tmp/test-file locking locked; hit enter to unlock... Em outra janela, olhe o contedo do /proc/locks. u cat /proc/locks 1: POSIX ADVISORY WRITE 5467 08:05:181288 0 2147483647 d1b5f740 00000000 dfea7d40 00000000 00000000 Podem existir outras linhas de sa da, tambm, correspondendo a travas e mantidas por outros programas. Nesse caso, 5467 o ID do processo do e programa lock-le. Use o comando ps para mostrar o que esse pprocesso est a rodando. ps 5467 PID TTY 5467 pts/28 STAT S TIME COMMAND 0:00 ./lock-file /tmp/test-file

O arquivo de trava, /tmp/test-le, reside sobre o dispositivo que tem nmeros de dispositivo principal e secundrio 8 e 5, respectivamente. Esses u a nmeros correspondem ao /dev/sda5. u
% df /tmp Filesystem 1k-blocks /dev/sda5 8459764 % ls -l /dev/sda5 brw-rw---1 root disk Used Available Use% Mounted on 5094292 2935736 63% / 8, 5 May 5 1998 /dev/sda5

O arquivo /tmp/test-le prpriamente dito est no inode 181,288 sobre o a aquele dispositivo. % ls --inode /tmp/test-file 181288 /tmp/test-file Veja a Seo 6.2, Nmeros de Dispositivo para maiores informaes ca u co sobre nmeros de dispositivo. u 205

7.6

Estat sticas de Sistema

Duas entradas no /proc possuem estat sticas uteis do sistema. O arquivo /proc/loadavg contm informao sobre a carga do sistema. Os primeiros e ca trs nmeros represetnam o nmero de tarefas ativas no sistema processos e u u que esto atualmente executando em termos mdios sobre os ultimos 1, 5, a e e 15 minutos. A entrada seguinte mostra o nmero instantneo corrente de u a tarefas rodveis processos que esto atualmente agendados para executar a a mas no sendo bloqueados em uma chamada de sistema e o nmero total a u de processos no sistema. A entrada nal o ID do processo que executou e mais recentemente. O arquivo /proc/uptime contm contagem de tempo desde quando o sise tema foi inicializado, bem como o montante do tempo desde ento que o a sistema tenha estado ocioso. Ambos so fornecidos como valores em ponto a utuante, em segundos20 . % cat /proc/uptime 3248936.18 3072330.49 O programa na Listagem 7.7 extrai o tempo total de funcionamento e o tempo de ociosidade estando ligado a partir do sistema e mostra-os em unidades amigveis. a Listagem 7.7: (print-uptime.c) Mostra o Tempo Ligado e o Tempo Ocioso
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <s t d i o . h> / Summarize a d u r a t i o n o f t i m e t o s t a n d a r d o u t p u t . amount o f t i m e , i n s e c o n d s , and LABEL i s a s h o r t TIME i s t h e descriptive label . /

void p r i n t t i m e ( char l a b e l , long t i m e ) { / C o n v e r s i o n c o n s t a n t s . / const long minute = 6 0 ; const long hour = minute 6 0 ; const long day = hour 2 4 ; / P r o d u c e o u t p u t . / p r i n t f ( %s : %l d days , %l d :%02 l d :%02 l d \n , l a b e l , t i m e / day , ( t i m e % day ) / hour , ( t i m e % hour ) / minute , t i m e % minute ) ; } i n t main ( ) { FILE f p ; double uptime , i d l e t i m e ; / Read t h e s y s t e m u p t i m e and a c c u m u l a t e d i d l e f p = f o p e n ( / p r o c / uptime , r ) ; f s c a n f ( f p , % l f % l f \n , &uptime , &i d l e t i m e ) ; f c l o s e ( fp ) ; / Summarize i t . / p r i n t t i m e ( uptime , ( long ) uptime ) ; p r i n t t i m e ( i d l e t i m e , ( long ) i d l e t i m e ) ; return 0 ; }

t i m e from / p r o c / uptime .

20

Nota do tradutor: aqui temos uma tima indicao de uso de um servidor por exemo ca

plo.

206

O comando uptime e a chamada de sistema sysinfo (veja a Seo 8.14, ca A Chamada de Sistema sysinfo: Obtendo Estat sticas do Sistema) tambm e pode obter o uptime do sistema. O comando uptime tambm mostra a carga e mdia encontrada em /proc/loadavg. e

207

208

Cap tulo 8

Chamadas de Sistema do GNU/Linux

ATE AGORA, APRESENTAMOS UMA VARIEDADE DE FUNCOES que seu programa pode chamar para executar tarefas relacionadas ao sistema, tais como informar opes de linha de comando, manipular processos, e mapeaco mento de memria. Se voc olhar sob a tampa do compartimento do motor, o e ir encontrar que essas funes se encaixam em duas categorias, baseado em a co como elas so implementadas. a 209

Funo de biblioteca que uma funo comum que reside em uma ca e ca biblioteca externa ao seu programa. A maioria das funes de biblico oteca que mostramos at agora esto na biblioteca C GNU padro, e a a a libc. Por exemplo, getopt long e mkstemp so funes fornecidas a co na biblioteca C GNU padro. a Uma chamada a uma funo de biblioteca apenas como qualca e quer outra chamada de funo. Os argumentos so colocados em ca a registros de processador ou em uma pilha, e a execuo transfeca e rida ao in do cdigo da funo, que tipicamente reside em uma cio o ca biblioteca compartilhada que foi carregada. Chamada de sistema que implementada no kernel do GNU/Linux. e Quando um programa faz uma chamada de sistema, os argumentos so empacotados e manipulados para o kernel, o qual assume a a execuo do programa at que a chamada se complete. Uma ca e chamada de sistema no uma chamada de funo comum, e um a e ca procedimento especial requerido para transferir o controle ao kere nel. Todavia, a biblioteca C GNU padro(a implementao da a ca biblioteca C GNU padro fornecida com sistemas GNU/Linux) ena volve chamadas de sistema do GNU/Linux com funes de forma co que voc pode cham-las facilmente. Funes de entrada e sa e a co da de baixo n tais como open e read so exemplos de chamadas de vel a sistema em GNU/Linux. O conjunto de chamadas de sistema do GNU/Linux forma a mais bsica interface entre programas e o kernel do GNU/Linux. Cada a chamada mostra uma operao bsica ou capacidade bsica. Alca a a gumas chamadas de sistema so mutio poderosas e podem exercer a grande inuncia no sistema. Por exemplo, algumas chamadas de e sistema habilitam voc a desligar o sistema GNU/Linux ou a alocar e recursos do sistema e prevenir que outros usurios o acessem. Essas a chamadas possuem a restrio que somente processos executando ca com privilgios de superusurio (programas executando pela conta e a root) podem cham-las. Essas chamadas falham se chamadas por a um processo comum. Note que uma funo de biblioteca pode chamar uma ou mais outras ca funes de biblioteca ou chamadas de sistema como parte de sua impleco mentao. ca GNU/Linux atualmente fornece cerca de 200 chamadas de sistema diferentes1 . Uma listagem de chamadas de sistema para sua verso do kernel do a
1

Nota do tradutor: mais de 300 nos kernels 2.6.

210

GNU/Linux encontra-se em /usr/include/asm/unistd.h 2 . Algumas dessas chamadas de sistema so de uso interno pelo sistema, e outras so usadas a a somente em implementao de funes de bibliotecas especializadas. Nesse ca co cap tulo, mostraremos uma seleo de chamadas de sistema que so mais ca a sucet veis de serem uteis a aplicaes e a programadores de sistemas. co A maioria dessas chamadas de sistema esto declaradas em <unistd.h>. a

8.1

Usando strace

Antes de iniciarmos discutindo chamadas de sistema, ir ser util mostrar a um comando com o qual voc pode aprender sobre chamadas de sistema e e a depurar programas que contenham chamadas de sistema. O comando strace rastreia a execuo de outro programa, listando quaisquer chamadas ca de sistema que o programa faz e qualquer sinal que o programa recebe. Para ver as chamadas de sistema e os sinais em um programa, simplesmente chame strace, seguido pelo programa e seus argumentos de linha de comando. Por exemplo, veja as chamadas de sistema que so chamadas pelo a comando hostname 3 , use a linha abaixo: % strace hostname Isso produz algumas telas de sa da. Cada linha corresponde a uma unica chamada de sistema. Para cada chamada, o nome da chamada de sistema listado, seguido por seus argumentos (ou argmentos abreviados, se eles e forem muito longos) e seus valores de retorno. Onde poss vel, strace convenientemente mostra nomes simblicos ao invs de valores numricos para o e e argumentos e valores de retorno, e strace mostra os campos de estruturas informados por um apontador dentro da chamada de sistema. Note que strace no mostra chamadas a funes comuns. a co Na sa do comando strace hostname, a primeira linha mostra a chamada da de sistema execve que chama o programa hostname 4 5 : execve("/bin/hostname", ["hostname"], [/* 49 vars */]) = 0
Nota do tradutor: no arquivo unistd.h atual tem uma condio que redireciona conca forme a arquitetura seja 32 ou 64 bits. Se for 32 o arquivo o unistd 32.h. Se for 64 o e arquivo o unistd 64.h. e 3 o comando hostname chamado sem quaisquer sinalizadores simplesmente mostra o nome de host do computador para a sa padro. da a 4 Em GNU/Linux, a fam de funes exec implementada usando a chamada de lia co e sistema execve. 5 Nota do tradutor: veja no Apndice H toda a sa na Seo H.1 e da ca
2

211

O primeiro argumento o nome do programa a executar; o segundo sua e e lista de argumentos, consistindo de somente um unico elemento; e o terceiro argumento sua lista de ambiente, a qual strace omite por brevidade. As e seguintes 30 ou mais linhas so parte do mecanismo que carrega a biblioteca a C GNU padro a partir de um arquivo de biblioteca compartilhada. a Mais para o nal esto chamadas de sistema que atualmente ajudam a a fazer o programa trabalhar. A chamada de sistema uname usada para e obter o nome do host do sistema reportado pelo kernel, uname({sys="Linux", node="computador", ...}) = 0 Observe que strace prestativamente rotula os campos (sys e node) do argumento estrutura. Essa estrutura preenchida pela chamada de sistema e GNU/Linux ajusta o campo sys para o nome do sistema operacional e o campo node para o nome do host do sistema. A chamada de sistema uname ser discutida mais detalhadamente na Seo 8.15, A Chamada de Sistema a ca uname. Finalmente, a chamada de sistema write produz a sa da. Relembrando que o descritor de arquivo 1 corresponde ` sa padro. O terceiro argua da a mento o nmero de caracteres a escrever, e o valor de retorno o nmero e u e u de caracteres que foram atualmente escritos. write(1, "computador\n", 11)= 11 Isso pode parecer truncado quando voc executa strace pelo fato de a e sa do programa hostname propriamente dita estar misturada com a sa da da do strace. Se o programa que voc est rastreando produz grande quantidade de e a sa da, algumas vezes mais conveniente redirecionar a sa de strace para e da dentro de um arquivo. Use a opo -o nomearquivo para fazer isso. ca Entender toda a sa de strace requer familiaridade detalhada com o da desenho do kernel do GNU/Linux e tambm do ambiente de execuo. A e ca maioria dessa familiaridade detalhada de interesse limitado para prograe madores de aplicao. Todavia, algum entendimento util para depurar ca e problemas complicados ou entender como outros programas trabalham.

8.2

A Chamada access: Testando Permisses o de Arquivos

A chamada de sistema access determina se o processo que a chamou tem permisso de acesso a um arquivo. A chamada de sistema access pode veria 212

car qualquer combinao de permisso de leitura, escrita e execuo, e access ca a ca pode tambm vericar a existncia de um arquivo. e e A chamada de sistema access recebe dois argmentos. O primeiro o cae minho para o arquivo a ser vericado. O segundo argumento uma operao e ca bit a bit do tipo entre R OK, W OK, e X OK, correspondendo a permisso a de leitura, escrita e execuo. O valor de retorno 0 se o processo tiver toca e das as permisses especicadas. Se o arquivo existe mas o processo chamador o no tem as permisses especicadas, a chamada de sistema access retorna a o -1 e ajusta errno para EACCES (ou EROFS, se permisso de escrita for a requisitada para um arquivo sobre um sistema de arquivo somente leitura). Se o segundo argumento for F OK, access simplesmente verica pela existncia do arquivo. Se o arquivo existir, o valor de retorno 0; se o e e arquio no existir, o valor de retorno -1 e errno ajustada para ENOENT. a e e Note que errno pode ao contrrio ser ajustada para EACCES se um diretrio a o no caminho do arquivo estiver inacess vel. O programa mostra na Listagem 8.1 usos de access para vericar a existncia de um arquivo e para determinar permisses de leitura e escrita. e o Especique o nome do arquivo a ser vericado na linha de comando. Listagem 8.1: (check-access.c) Check File Access Permissions
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <e r r n o . h> #include <s t d i o . h> #include <u n i s t d . h> i n t main ( i n t a r g c , char a r g v [ ] ) { char path = a r g v [ 1 ] ; int r v a l ; / Check f i l e e x i s t e n c e . / r v a l = a c c e s s ( path , F OK) ; i f ( r v a l == 0 ) p r i n t f ( %s e x i s t s \n , path ) ; else { i f ( e r r n o == ENOENT) p r i n t f ( %s d o e s n o t e x i s t \n , path ) ; e l s e i f ( e r r n o == EACCES) p r i n t f ( %s i s n o t a c c e s s i b l e \n , path ) ; return 0 ; } / Check r e a d a c c e s s . / r v a l = a c c e s s ( path , R OK) ; i f ( r v a l == 0 ) p r i n t f ( %s i s r e a d a b l e \n , path ) ; else p r i n t f ( %s i s n o t r e a d a b l e ( a c c e s s

d e n i e d ) \n , path ) ;

/ Check w r i t e a c c e s s . / r v a l = a c c e s s ( path , W OK) ; i f ( r v a l == 0 ) p r i n t f ( %s i s w r i t a b l e \n , path ) ; e l s e i f ( e r r n o == EACCES) p r i n t f ( %s i s n o t w r i t a b l e ( a c c e s s d e n i e d ) \n , path ) ; e l s e i f ( e r r n o == EROFS) p r i n t f ( %s i s n o t w r i t a b l e ( r e a do n l y f i l e s y s t e m ) \n , path ) ; return 0 ; }

Por exemplo, para vericar as permisses de acesso para um arquivo o 213

chamado LEIAME gravado em um CD-ROM, chame o programa da listagem 8.1 como segue: % ./check-access /mnt/cdrom/LEIAME /mnt/cdrom/LEIAME exists /mnt/cdrom/LEIAME is readable /mnt/cdrom/LEIAME is not writable (read-only filesystem)

8.3

A Chamada de Sistema fcntl : Travas e Outras Operaoes em Arquivos c

A chamada de sistema fcntl o ponto de acesso para muitas operaes e co avanadas sobre descritores de arquivos. O primeiro argumetno a fcntl c e um descritor j aberto, e o segundo um valor que indica qual operao a e ca para ser executada. Para algumas operaes, fcntl recebe um argumento e co adicional. Iremos descrever aqui uma das mais uteis operaes de fcntl, o tra co vamento de um arquivo. Veja a pgina de manual de fcntl para informao a ca sobre as outras operaes que podem ser feitas sobre arquivos por fcntl. co A chamada de sistema fcntl permite a um programa colocar uma trava de leitura ou uma trava de escrita sobre um arquivo, at certo ponto anloga a e a travas de mutex discutidas no Cap tulo 5, Comunicao Entre Porcessos. ca Uma trava de leitura colocada sobre um descritor que pode ser lido, e e uma trava de escrita colocada sobre um descritor de arquivo que pode e ser escrito. Mais de um processo pode manter uma trava de leitura sobre o mesmo arquivo ao mesmo tempo, mas somente um processo pode manter uma trava de leitura, e o mesmo arquivo no pode ser simultneamente travado a a para leitura e escrita. Note que colocando uma trava no previne atualmente a outros processos de abrirem o arquivo, ler a partir dele, ou escrever para ele, a menos que esses outros processos adquiram travas com fcntl tambm. e Para colocar uma trava sobre um arquivo, primeiro crie uma varivel a struct ock com todos os seus campos zerados. Ajuste o campo l type da estrutura para F RDLCK para uma trava de leitura ou para F WRLCK para uma trava de escrita. Ento chame fcntl, informando um descritor de a arquivo para o arquivo, o cdigo de operao F SETLKW, e um apontador o ca para a varivel struct ock. Se outro processo mantm uma trava que evita a e que uma nova trava seja adquirida, fcntl bloqueia at que aquela trava seja e liberada. O programa na Listagem 8.2 abre um arquivo para escrita cujo nome e fornecido pela linha de comando, e ento coloca uma trava de escrita nesse a 214

mesmo arquivo aberto. O programa espera pelo usurio pressionar Enter e a ento destrava e fecha o arquivo. a Listagem 8.2: (lock-le.c) Create a Write Lock with fcntl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include #include #include #include < f c n t l . h> <s t d i o . h> < s t r i n g . h> <u n i s t d . h>

i n t main ( i n t a r g c , char a r g v [ ] ) { char f i l e = a r g v [ 1 ] ; int fd ; struct f l o c k l o c k ; p r i n t f ( o p e n i n g %s \n , f i l e ) ; / Open a f i l e d e s c r i p t o r t o t h e f i l e . f d = open ( f i l e , O WRONLY) ; p r i n t f ( l o c k i n g \n ) ; / I n i t i a l i z e t h e f l o c k s t r u c t u r e . / memset (& l o c k , 0 , s i z e o f ( l o c k ) ) ; l o c k . l t y p e = F WRLCK; / P l a c e a w r i t e l o c k on t h e f i l e . / f c n t l ( f d , F SETLKW, &l o c k ) ; p r i n t f ( locked ; hit / Wait f o r t h e u s e r getchar () ; enter to unlock . . . to h i t enter . /

) ;

p r i n t f ( u n l o c k i n g \n ) ; / R e l e a s e t h e l o c k . / l o c k . l t y p e = F UNLCK ; f c n t l ( f d , F SETLKW, &l o c k ) ; c l o s e ( fd ) ; return 0 ; }

Compile e rode o programa sobre um arquivo de teste digamos, /tmp/testle como segue: % cc -o lock-file lock-file.c % touch /tmp/test-file % ./lock-file /tmp/test-file opening /tmp/test-file locking locked; hit Enter to unlock... Agora, em outra janela, tente rodar o mesmo programa novamente sobre o mesmo arquivo. % ./lock-file /tmp/test-file opening /tmp/test-file locking Note que a segunda instncia ca bloqueada enquanto tenta travar o a arquivo. Volte ` primeira janela e pressione Enter : a 215

unlocking O programa rodando na segunda janela imediatamente adquire a trava. Se voc prefere que fcntl no bloqueie se a chamada no puder pegar a e a a trava que voc requisitou, use F SETLK ao invs de F SETLKW. Se a trava e e no puder ser adquirida, fcntl retorna -1 imediatamente. a GNU/Linux fornece outra implementao de travamento de arquivo com ca a chamada ock. A verso fcntl tem uma vantagem importante: a verso a a 6 fcntl trabalha com arquivos no sistema de arquivos NFS (contanto que o servidor NFS seja razoavelmente recente e corretamente congurado). Ento, a se voc tiver acesso a duas mquinas que ambas montem o mesmo sistema de e a arquivos via NFS, voc pode repetir o exemplo prvio usando duas diferentes e e mquinas. Rode lock-le em uma mquina, especicando um arquivo em a a um sistema de arquivo NFS, e ento rode o programa lock-le novamente a em outra mquina, especicando o mesmo arquivo. NFS acorda o segundo a programa quando a trava liberada pelo primeiro programa. e

8.4

As Chamadas fsync e fdatasync: Descarregando para o Disco

Na maioria dos sistemas operacionais, quando voc escreve em um arquivo, os e dados no so imediatamente escritos no disco. Ao invs disso, o sistema opea a e racional oculta os dados escritos em uma rea de armazenamento temporria a a da memria, para reduzir o nmero de requisies de escrita para o disco e o u co diminuir o tempo de resposta do programa. Quando a rea temporria de a a armazenamento enche ou alguma outra condio ocorrer (por exemplo, inca tervalo de tempo satisfatria para se fazer a escrita), o sistema escreve os o dados ocultos para o disco todos de uma s vez. o GNU/Linux fornece essa otimizao de acesso ao disco tambm. Normalca e mente, essa ocultao apresenta um grande ganho de performace. Todavia, ca esse compartamento pode fazer programas que dependem da integridade de gravaes baseadas em disco no serem conveis. Se o sistema para de funco a a cionar bruscamente por exemplo, devido a um travamento do kernel ou interrupo no fornecimento de energia quaisquer dados escritos por um ca programa que est na memria cache mas no tiver sido ainda escrito no a o a disco perdido. e Por exemplo, suponhamos que voc est escrevendo um programa para e a efetuar uma transao que mantm um arquivo de um sistema de arquivos ca e
Network File System (NFS) uma tecnologia comum de compartilhamento de arquie vos em rede, comparvel aos acionadores de rede e compartilhamentos do Windows. a
6

216

com jornal. O arquivo de jornal do sistema de arquivos contm registros e de todas as transaes que tenham sido processadas de forma que se uma co falha no sistema vier a ocorrer, o estado dos dados da transao pode ser ca reconstru do. Isso obviamente importante para preservar a integridade do e arquivo de jornal toda vez que uma transao processada, sua entrada de ca e jornal deve ser enviada para o acionador de disco imediatamente. Para ajudar voc a implementar esse arquivo de jornal, GNU/Linux fore nece a chamada de sistema fsync. A chamada de sistema fsync recebe um argumento, um descritor de arquivo que pode ser escrito, e descarrega para o disco quaisquer dados escritos para esse arquivo de jornal. A chamada fsync no retorna at que os dados tenham sido sicamente escritos. a e A funo na Listagem 8.3 ilustra o uso de fsync. A funo da listagem ca ca escreve uma entrada de linha unica para um arquivo de jornal. Listagem 8.3: (write journal entry.c) Write and Sync a Journal Entry
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include #include #include #include #include < f c n t l . h> < s t r i n g . h> <s y s / s t a t . h> <s y s / t y p e s . h> <u n i s t d . h>

const char j o u r n a l f i l e n a m e = j o u r n a l . l o g ; void w r i t e j o u r n a l e n t r y ( char e n t r y ) { i n t f d = open ( j o u r n a l f i l e n a m e , O WRONLY | O CREAT | O APPEND, w r i t e ( fd , entry , s t r l e n ( e n t r y ) ) ; w r i t e ( f d , \n , 1 ) ; fsync ( fd ) ; c l o s e ( fd ) ; }

0660) ;

Outra chamada de sistema, fdatasync faz a mesma coisa. Todavia, embora fsync garanta que a hora de modicao de arquivo ir ser atualizada, ca a fdatasync no garante; fdatasync garante somente que os dados do arquivo a iro ser escritos. Isso signica que princ a pio, fdatasync pode executar mais rapidamente que fsync pelo fato de fdatafsync precisar forar somente uma c escrita ao disco ao invs de duas. e Todavia, nas verses correntes do GNU/Linux, essas duas chamadas de o sistema atualmente fazem a mesma coisa, ambas atualizam a hora de modicao do arquivo7 . ca A chamada de sistema fsync habilita voc a forar um descarregamento de e c a rea temporria de armazenamento explicitamente. Voc pode tambm abrir a e e um arquivo para E/S sincronizada, o que faz com que todas as escritas sejam imediatamente enviadas ao disco. Para fazer isso, especique o sinalizador O SYNC ao abrir o arquivo com a chamada de sistema open.
Nota do tradutor:a armao refere-se a kernels 2.2. Nos kernels ps-2.2 fdatasync ca o e mais rpida pelo fato de no atualizar a hora de modicao do arquivo. a a ca
7

217

8.5

As Chamadas getrlimit e setrlimit: Limites de Recurso

As chamadas de sistema getrlimit e setrlimit permitem a um processo ler e ajustar limites sobre recursos de sistema que o processo chamador pode consumir. Voc pode estar familiarizado com o comando shell ulimit, o qual e habilita voc a restringir o uso de recurso de programas que voc roda;8 essa e e chamadas de sistema permite a um programa fazer isso programaticamente9 .

Para cada recurso existe dois limites, o limite inegocivel e o limite nea gocivel. O limite negocivel jamais pode exceder o limite inegocivel, e a a a somente processos com privilgio de superusurio podem mudar o limite e a inegocivel. Tipicamente, um programa de aplicao ir reduzir o limite a ca a negocivel para colocar um controle sobre os recursos que usa. a

As chamadas getrlimit e setrlimit recebem como argumentos um cdigo o especicando o tipo de limite de recurso e um apontador a uma varivel a do tipo struct rlimit. A chamada getrlimit preenche os campos dessa estrutura, enquanto a chamada setrlimit muda o limite basedo no contedo da u struct rlimit. A estrutura rlimit tem dois campos: rlim cur que o limite e negocivel, e rlim max que o limite r a e gido mximo. a

Alguns dos limites de recursos mais uteis que podem ser mudados so a listados aqui, com seus cdigos: o

Veja a pgina de manual para seu shell para maior informao sobre ulimit. a ca . Nota do tradutor: programaticamente quer dizer a partir do ou no ou usando o cdigo fonte ou funo de biblioteca de um programa na linguagem C. o ca
9

218

RLIMIT CPU O tempo mximo de CPU, em segundos, usado a por um programa. Esse o total de tempo que o programa est e a atualmente executando sobre a CPU, que no necessariamente a e o mesmo que mostra em horas no relgio comum. Se o programa o excede esse limite de tempo, o programa terminado com um sinal e SIGXCPU. RLIMIT DATA O total mximo de memria que um programa a o pode alocar para seus dados. Alocao adicional alm desse limite ca e ir falhar. a RLIMIT NPROC O nmero mximo de processos lhos que pode u a ser rodados para esse usurio. Se o processo chama fork e muitos a processos pertencentes a esse usurio esto rodando so sistema, a a a chamada a fork ir falhar. a RLIMIT NOFILE O nmeo mximo de descritores de arquivo u a que o processo pode ter aberto ao mesmo tempo. Veja a pgina de manual de setrlimit para se informar sobre a lista coma pleta de recursos do sistema.

Listagem 8.4: (limit-cpu.c) Demonstrao do Tempo Limite de Uso da ca CPU


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <s y s / r e s o u r c e . h> #include <s y s / t i m e . h> #include <u n i s t d . h> i n t main ( ) { struct r l i m i t

rl ;

/ O b t a i n t h e c u r r e n t l i m i t s . / g e t r l i m i t ( RLIMIT CPU , & r l ) ; / S e t a CPU l i m i t o f one s e c o n d . rl . rlim cur = 1; s e t r l i m i t ( RLIMIT CPU , & r l ) ; / Do b u s y w o r k . / while ( 1 ) ; return 0 ; }

Quando o programa encerra por SIGXCPU, o shell prestativamente mostra uma mensagem intepretando o sinal: % ./limit_cpu CPU time limit exceeded 219

8.6

a Chamada getrusage: Estat sticas de Processo

A chamada de sistema getrusage recupera estat sticas de processo a partir do kernel. A chamada de sistema getrusage pode ser usada para obter estat sticas ou para o processo atual informando RUSAGE SELF como o primeiro argumento, ou para todos os processos lhos encerrados que foram forkados pelo processo chamador e seus lhos informando RUSAGE CHILDREN. O segundo argumento a rusage um apontador para uma varivel do tipo e a struct rusage, a qual preenchida com as estat e sticas. Alguns dos campos mais interessantes em struct rusage so listados aqui: a ru utime Um campo do tipo struct timeval contendo o total de tempo de usrio, em segundos, que o processo tenha usado. Tempo a de usrio o tempo de CPU investido executando o programa do a e usurio, ao invs de em chamadas de sistema do kernel. a e ru stime Um campo do tipo struct timeval contendo o total de tempo do sistema, em segundos, que o processo tenha usado. Tempo do sistema o tempo de CPU investido executando chamae das de sistema na conta do processo. ru maxrss O maior total de memria f o sica ocupada pelos dados do processo de uma s vez ao longo de sua execuo. o ca A pgina de manual de getrusage lista todos os campos dispon a veis. Veja Seo 8.7, A Chamada gettimeofday: Hora Relgio Comum para ca o informao sobre struct timeval. ca A funo na Listagem 8.5 mostra o usurio atual do processo e a hora do ca a sistema. Listagem 8.5: (print-cpu-times.c) Mostra Usurio de Processo e Horas do a Sistema
1 2 3 4 5 6 7 8 9 10 11 12 13 #include #include #include #include <s t d i o . h> <s y s / r e s o u r c e . h> <s y s / t i m e . h> <u n i s t d . h>

void p r i n t c p u t i m e ( ) { struct rusage usage ; g e t r u s a g e (RUSAGE SELF , &u s a g e ) ; p r i n t f ( CPU t i m e : %l d .%06 l d s e c u s e r , %l d .%06 l d s e c s y s t e m \n , usage . ru utime . tv sec , usage . ru utime . tv usec , usage . ru stime . tv sec , usage . ru stime . t v u s e c ) ; }

220

8.7

A Chamada gettimeofday : Hora Relgio o Comum

A chamada de sistema gettimeofday pega a hora relgio comum do sistema. o A chamada de sistema gettimeofday pega um apontador para uma varivel a struct timeval. Essa estrutura representa uma hora determinada, em segundos, quebrada em dois campos. O campo tv sec contm o nmero total de e u segundos, e o campo tv usec contm um nmero adicional de micro-segundos. e u Essa valor de varivel do tipo struct timeval representa o nmero de seguna u dos que se passaram desde o in da poca UNIX, na meia noite UTC de cio e primeiro de Janeiro de 197010 . A chamada gettimeofday tambm recebe um e segundo argumento, que deve ser NULL. Include <sys/time.h> se voc usa e essa chamada de sistema. O nmero de segundos na poca UNIX no usualmente um caminho conu e a e veniente de representar datas. As funes de biblioteca localtime e strftime co ajudam a manipular o valor de retorno de gettimeofday. A funo localtime ca pega um apontador ao nmero de segundos (o campo tv sec de struct timeu val ) e retorna um apontador a um objeto struct tm. Essa estrutura contm e campos mais uteis, os quais so preenchidos conforme o fuso horrio local: a a tm hour, tm min, tm sec A hora do dia, em horas, minutos, e segundos. tm year, tm mon, tm day O dia, mes e ano da data. tm wday O dia da semana. Zero representa Domingo. tm yday O dia do ano. tm isdst Um sinalizador indicando se o horrio de vero est a a a vigorando. A funo strftime adicionalmente pode produzir a partir do apontador a ca struct tm uma sequncia de caracteres personalizada e formatada mostrando e a data e a hora. o formato especicado de uma maneira similar a printf, e como uma sequncia com cdigos embutidos indicando quais campos de hora e o incluir. Por exemplo, ess formato de sequncia de caracteres: e "%Y-%m-%d %H:%M:%S" especica a data e hora na seguinte forma:
Nota do tradutor: veja em H.3 um resumo histrico do ano de 1970 no Brasil e no o mundo.
10

221

2001-01-14 13:09:42 Informe a strftime um espao temporrio de armazenamento do tipo cac a ractere para receber a sequncia de caracteres, o comprimento daquele espao e c temporrio de armazenamento, a sequncia de caracteres que exprime o fora e mato esperado, e um apontador a uma varivel do tipo struct tm. Veja pgina a a de manual da strftime para uma lista completa de cdigos que podem ser o usados na sequncia de caracteres indicadora de formato. Note que nem a e localtime e nem a strftime manipulam a parte fracionria da hora atual mais a precisa que 1 segundo (o campo tv usec da struct timeval ). Se voc deseja e isso em sua sequncia de caracteres formatada indicadora da hora, voc ter e e a de incluir isso por sua prpria conta. o Include <time.h> se voc chama localtime ou strftime. e A funo na Listagem 8.6 mostra a data atual e hora do dia, arredondando ca para baixo nos milsimos de segundo. e Listagem 8.6: (print-time.c) Mostra a Data e a Hora
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include #include #include #include <s t d i o . h> <s y s / t i m e . h> <t i m e . h> <u n i s t d . h>

void p r i n t t i m e ( ) { struct timeval tv ; s t r u c t tm ptm ; char t i m e s t r i n g [ 4 0 ] ; long m i l l i s e c o n d s ; / O b t a i n t h e t i m e o f day , and c o n v e r t i t t o a tm s t r u c t . / g e t t i m e o f d a y (& tv , NULL) ; ptm = l o c a l t i m e (& t v . t v s e c ) ; / Format t h e d a t e and t i m e , down t o a s i n g l e s e c o n d . / s t r f t i m e ( t i m e s t r i n g , s i z e o f ( t i m e s t r i n g ) , %Y m % %d % H:%M:%S , ptm ) ; / Compute m i l l i s e c o n d s f r o m m i c r o s e c o n d s . / m i l l i s e c o n d s = tv . t v u s e c / 1000; / P r i n t t h e f o r m a t t e d t i m e , i n s e c o n d s , f o l l o w e d b y a d e c i m a l p o i n t and t h e m i l l i s e c o n d s . / p r i n t f ( %s .%03 l d \n , t i m e s t r i n g , m i l l i s e c o n d s ) ; }

8.8

A Fam mlock : Travando Memria lia o F sica

A fam mlock de chamadas de sistema permite a um programa travar lia alguma parte ou todo o seu espao dentro da memria f c o sica. Isso evita que o GNU/Linux faa a paginao dessa memria para um espao swap, mesmo c ca o c se o programa no tenha acessado esse espao em algum momento. a c Um programa onde intervalo de tempo muito importante pode travar e memria f o sica pelo fato de a defasagem de paginao de memria saindo ca o e voltando pode ser muito longa ou muito imprevis vel.Aplicaes de alta co 222

segurana podem tambm desejar prevenir que dados importantes sejam rec e tirados da memria para um arquivo de swap, o qual pode ser recuperado o por um invasor aps o programa terminar. o Travar uma regio de memria to simples quanto chamar mlock com a o e a um apontador para o in da regio e o comprimento da regio. GNU/Linux cio a a divide a memria em paginas e pode travar somente pginas inteiras de uma o a vez; cada pgina que contm parte da regio de memria especicada a mlock a e a o travada. A funo getpagesize retorna o tamanho da pgina do sistema, o e ca a 11 qual 4KB no GNU/Linux x86 . e Por exemplo, para alocar 32MB de espao de endereo e travar esse espao c c c dentro da RAM, voc pode usar esse cdigo: e o const int alloc\_size = 32 * 1024 * 1024; char* memory = malloc (alloc\_size); mlock (memory, alloc\_size); Note que simplesmente alocando um pgina de memria e travando-a a o com mlock no reserva memria f a o sica para o processo que est fazendo a a requisio pelo fato de as pginas poderem ser do tipo copie-na-escrita12 . ca a Portando, voc deve escrever um valor sem importncia para cada pgina e a a tambm: e size_t i; size_t page_size = getpagesize (); for (i = 0; i < alloc\_size; i += page_size) memory[i] = 0; A escrita para cada pgina fora GNU/Linux a atribuit uma pgina de a c a memria unica, no compartilhada para o processo para aquela pgina. o a a Para destravar uma regio, chame munlock, a qual recebe os mesmos a argumentos que mlock. Se voc desejar todo o espao de endereamento de memria de seu proe c c o grama travado em memria f o sica, chame mlockall. Essa chamada de sistema mlockall recebe um unico argumento sinalizador: MCL CURRENT trava toda a memria atualmente alocada para processo que fez a chao mada a mlockall, mas alocaes futuras no so travadas; MCL FUTURE co a a trava todas as pginas que forem alocadas aps a chamada a mlockall. Use a o
Nota do tradutor: outros comandos relacionados a memria so free, top vmsat. o a Copie-na-escrita signica que GNU/Linux faz uma cpia privada de uma pgina de o a memria para um processo somente quando o processo escreve um valor em algm lugar o dentra da pgina. a
12 11

223

MCL CURRENT|MCL FUTURE para travar dentro da memria f o sica ambos os tipos de alocao: as atuais e as subsequntes. ca e O travamento de grandes quantidade de memria, especialmente usando o mlockall, pode ser perigoso para todo o sistema GNU/Linux. Travamento indiscriminado da memria um bom mtodo de trazer seu sistema para um o e e travamento pelo fato de outros processos que esto rodando serem forados a c a competir por recursos menores de memria e swap rapidamente dentro da o memria e voltando para a memria (isso conhecido como thrashingNota o o e do tradutor: debulhamento.). Se voc trava muita memria, o sistema ir e o a executar fora da memria inteiramente e GNU/Linux ir encerrar processos. o a Por essa razo, somente processos com privilgios de superusurio podem a e a travar memria com mlock ou com mlockall. Se um processo de usurio coo a mum chama uma dessas funes, a chamada ir falhar, retornar -1, e ajustar co a errno para EPERM. A chamada munlockall destrava toda a memria travada pelo processo o atual, incluindo memria travada com mlock e mlockall. o Um meio conveniente para monitorar o uso de memria de seu programa o usar o comando top. Na sa de top, a coluna SIZE13 mostra o tamanho do e da espao de endereo virtual de cada programa (o tamanho total de seu cdigo c c o de programa, dados, e pilha, alguns dos quais podem ser paginadas para o espao swap). A coluna RSS14 (para resident set size) mostra o tamanho de c memria f o sica que cada programa atualmente ocupa. O somatrio de todos o os valores RSS para todos os programas que esto rodando no pode exceder a a o tamanho da memria f o sica de seu computador, e o somatrio de todos os o tamanhos de espao de endereamento est limitado a 2GB15 (para verses c c a o de 32-bit do GNU/Linux). Include <sys/mman.h> se voc usa qualquer das chamadas de sistema e mlock.

8.9

mprotect: Ajustando as Permisses da o Memria o

Na Seo 5.3, Arquivos Mapeados em Memria foi mostrado como usar a ca o chamada de sistema mmap para mapear um arquivo para dentro da memria. o Relembrando que o terceiro argumentos a mmap uma operao bit-a-bit e ca ou de sinalizadores de proteo de memria PROT READ, PROT WRITE, ca o
13 14

Nota do tradutor: no kernel 2.6 essa coluna VIRT. e Nota do tradutor: no kernel 2.6 essa coluna RES. e 15 Nota do tradutor: vericar esse valor.

224

e PROT EXEC para permisso de leitura, escrita, e execuo, respectivaa ca mente, ou de PROT NONE para nenhum acesso de memria. Se um proo grama tenta executar uma operao em uma localizao de memria que ca ca o no permitida por essas permisses, o programa encerrado com um sinal a e o e SIGSEGV (violao de segmento). ca Aps a memria ter sido mapeada, essas permisses podem ser modicao o o das com a chamada de sistema mprotect. Os argumentos a mprotect so um a endereo de uma regio de memria, o tamanho da regio, e um conjunto c a o a de sinalizadores de proteo. A regio de memria deve consistir de pginas ca a o a completas: O endereo da regio deve ser alinhado com o tamanho de pgina c a a do sistema, e o comprimento da regio deve ser um mltiplo do tamanho de a u pgina. Os sinalizadores de proteo para essas pginas so substitu a ca a a dos com o valor especicado.
Obtendo Pgina de Memria Alinhada a o Note que regies de memria retornadas por malloc so tipicamente pginas o o a a no alinhadas, mesmo se o tamanho da memria seja um mltiplo do tamanho a o u da pgina. Se voc deseja proteger a memria obtida a partir de malloc, voc a e o e ir ter que alocar uma regio de memria maior e encontrar uma regio ajusa a o a tada ao tamanho da pgina dentro da regio alocada. Alternativamente, voc a a e pode usar a chamada de sistema mmap para evitar malloc e alocar memria o ajustada ao tamanho da pgina diretamente do kernel do GNU/Linux. Veja a a Seo 5.3, Arquivos Mapeados em Memria para detalhes. ca o

Por exemplo, suponhamos que seu programa faa a alocao de uma c ca pgina de memria mapeando /dev/zero, como descrito na Seo 5.3.5, Oua o ca tros Usos para Arquivos Mapeados em Memria. A memria inicialmente o o e ser alvo de ambas as operaes de leitura e escrita. co
int fd = open ("/dev/zero", O\_RDONLY); char* memory = mmap (NULL, page\_size, PROT\_READ | PROT\_WRITE, MAP\_PRIVATE, fd, 0); close (fd);

Mais tarde, seu programa poder vir a tornar a memria somente para a o leitura chamando mprotect: mprotect (memory, page\_size, PROT\_READ); Uma tcnica avanada para monitorar acessos a memria proteger e c o e regies de memria usando mmap ou mprotect e ento manipular o sinal o o a SIGSEGV que GNU/Linux envia ao programa quando esse mesmo programa tenta acessar aquela memria. O exemplo na Listagem 8.7 ilustra o essa tcnica. e 225

Listagem 8.7: (mprotect.c) Detecta Acesso ` Memria Usando mprotect a o


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #include #include #include #include #include #include #include #include < f c n t l . h> < s i g n a l . h> <s t d i o . h> < s t r i n g . h> <s y s /mman . h> <s y s / s t a t . h> <s y s / t y p e s . h> <u n i s t d . h>

static int a l l o c s i z e ; s t a t i c char memory ; void s e g v h a n d l e r ( i n t s i g n a l n u m b e r ) { p r i n t f ( memory a c c e s s e d ! \ n ) ; m p r o t e c t ( memory , a l l o c s i z e , PROT READ | PROT WRITE) ; } i n t main ( ) { int fd ; struct s i g a c t i o n

sa ; f o r SIGSEGV . /

/ I n s t a l l s e g v h a n d l e r a s t h e h a n d l e r memset (& sa , 0 , s i z e o f ( s a ) ) ; s a . s a h a n d l e r = &s e g v h a n d l e r ; s i g a c t i o n (SIGSEGV , &sa , NULL) ;

/ A l l o c a t e one p a g e o f memory b y mapping / d e v / z e r o . Map t h e memory a s w r i t e o n l y , i n t i a l l y . / a l l o c s i z e = getpagesize () ; f d = open ( / dev / z e r o , O RDONLY) ; memory = mmap (NULL, a l l o c s i z e , PROT WRITE, MAP PRIVATE, f d , 0 ) ; c l o s e ( fd ) ; / W r i t e t o t h e p a g e t o o b t a i n a p r i v a t e c o p y . / memory [ 0 ] = 0 ; / Make t h e t h e memory u n w r i t a b l e . / m p r o t e c t ( memory , a l l o c s i z e , PROT NONE) ; / W r i t e t o t h e memory [ 0 ] = 1 ; / A l l printf munmap return } a l l o c a t e d memory r e g i o n . /

d o n e ; unmap t h e memory . ( a l l done \n ) ; ( memory , a l l o c s i z e ) ; 0;

O programa segue os seguintes passos: 226

1. O programa instala um manipulador de sinal para SIGSEGV. 2. O programa aloca uma pgina de memria mapeando /dev/zero e a o escrevendo um valor para a pgina alocada para obter uma cpia a o privada. 3. O programa protege a memria chamando mprotect com a pero misso PROT NONE. a 4. Quando o programa sequncialmente escreve para a memria, e o GNU/Linux envia seu SIGSEGV, o qual manipulado por e segv handler. O manipulador de sinal retira a proteo da memria, ca o o que permite que o acesso ` memria continue. a o 5. Quando o manipulador de sinal cumpre sua funo, o controle reca torna para main, onde o programa desaloca a memria usando o munmap.

8.10

A Chamada nanosleep: Temporizador de Alta Preciso a

A chamada de sistema nanosleep uma verso em alta preciso da chamada e a a padro UNIX sleep. Ao invs de temporizar um nmero inteiro de segundos, a e u nanosleep recebe como seu argumento um apotador para um objeto struct timespec, o qual pode expressar hora com preciso de nanosegundos. Todavia, a devido a detalhes de como o kernel do GNU/Linux trabalha, a atual preciso a 16 fornecida por nanosleep de 10 milisegundos ainda melhor que aquela e oferecida por sleep. Essa preciso adicional pode ser util, por exemplo, para a agendar operaes frequntes com intervalos de tempo curtos entre elas. co e A estrutura struct timespec tem dois campos: tv sec, o nmero de segunu dos inteiros, e tv nsec, um nmero adicional de nanosegundos. O valor de u tv nsec deve ser menor que 109. A chamada nanosleep fornece outra vantagem sobre a chamada sleep. Da mesma forma que sleep, a entrega de um sinal interrompe a execuo de naca nosleep, a qual ajusta errno para EINTR e retorna -1. Todavia, nanosleep recebe um segundo argumento, outro apontador para um objeto struct timespec, o qual, se no for null , preenchido com o total dos tempos restantes a e (isto , a diferena entre o tempo do sleep da requisio e o tempo do sleep e c ca atual). Isso torna fcil continuar a operao de temporizao. a ca ca A funo na Listagem 8.8 fornece uma implementao alternativa de sleep. ca ca
16

Nota do tradutor: vericar esse valor.

227

Ao contrrio da chamada de sistema comum, essa funo recebe um valor em a ca ponto utuante para o nmero de segundos a temporizar e rinicia a operao u ca de temporizao se for interrompida por um sinal. ca

Listagem 8.8: (better sleep.c) High-Precision Sleep Function


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <e r r n o . h> #include <t i m e . h> i n t b e t t e r s l e e p ( double s l e e p t i m e ) { struct timespec tv ; / C o n s t r u c t t h e t i m e s p e c f r o m t h e number o f w h o l e s e c o n d s . . . tv . t v s e c = ( t i m e t ) s l e e p t i m e ; / . . . and t h e r e m a i n d e r i n n a n o s e c o n d s . / t v . t v n s e c = ( long ) ( ( s l e e p t i m e t v . t v s e c ) 1 e +9) ;

while ( 1 ) { / S l e e p f o r t h e t i m e s p e c i f i e d i n t v . I f i n t e r r u p t e d by a s i g n a l , p l a c e the remaining time l e f t to s l e e p back i n t o t v . i n t r v a l = n a n o s l e e p (& tv , &t v ) ; i f ( r v a l == 0 ) / C o m p l e t e d t h e e n t i r e s l e e p t i m e ; a l l d o n e . / return 0 ; e l s e i f ( e r r n o == EINTR) / I n t e r r u p e d b y a s i g n a l . Try a g a i n . / continue ; else / Some o t h e r e r r o r ; b a i l o u t . / return r v a l ; } return 0 ; }

8.11

readlink: Lendo Links Simblicos o

A chamada de sistema readlink recupera o alvo de um link simblico. A o chamada de sistema readlink recebe trs argumentos: o caminho para o link e simblico, uma rea temporria de armazenamento para receber o alvo do o a a link, e o comprimento da rea temporria de armazenamento. Desafortua a nadamente, readlink no coloca NUL para encerrar o caminho do alvo que a readlink coloca na rea temporria de armazenamento. A readlink, todavia, a a retorna o nmero de caracteres no caminho do alvo, de forma que terminar u a sequncia de caracteres com NUL simples. e e Se o primeiro argumento a readlink apontar para um arquivo que no for a um link simblico, readlink ajusta errno para EINVAL e retorna -1. o O pequeno programa na Listagem 8.9 mostra o alvo do link simblico o especicado em sua linha de comando. 228

Listagem 8.9: (print-symlink.c) Mostra o Alvo de um Link Simblico o


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include <e r r n o . h> #include <s t d i o . h> #include <u n i s t d . h> i n t main ( i n t a r g c , char a r g v [ ] ) { char t a r g e t p a t h [ 2 5 6 ] ; char l i n k p a t h = a r g v [ 1 ] ; / A t t e m p t t o r e a d t h e t a r g e t o f t h e s y m b o l i c l i n k . / int len = r e a d l i n k ( link path , target path , sizeof ( t a r g e t p a t h ) 1) ; if ( l e n == 1) { / The c a l l f a i l e d . / i f ( e r r n o == EINVAL) / I t s n o t a s y m b o l i c l i n k ; r e p o r t t h a t . / f p r i n t f ( s t d e r r , %s i s n o t a s y m b o l i c l i n k \n , l i n k p a t h ) ; else / Some o t h e r p r o b l e m o c c u r r e d ; p r i n t t h e g e n e r i c m e s s a g e . / perror ( readlink ) ; return 1 ;

} else { / NUL e r m i n a t e t h e t a r g e t p a t h . t t a r g e t p a t h [ l e n ] = \0 ; / P r i n t i t . / p r i n t f ( %s \n , t a r g e t p a t h ) ; return 0 ; } }

Por exemplo, aqui est como voc poder vir a fazer um link simblico e a e a o usar print-symlink para recupera o caminho do referido link: % ln -s /usr/bin/wc meu_link % ./print-symlink meu_link /usr/bin/wc

8.12

A Chamada sendle: Transferncia de e Dados Rpida a

A chamada de sistema sendle fornece um eciente mecanismo para copiar dados de um descritor de arquivos para outro. Os descritores de arquivo podem ser abertos para arquivos em disco, sockets, ou outros dispositivos. Tipicamente, para copiar de um descritor de arquivo para outro, um programa aloca uma rea temporria de armazenamento de tamanho xo, a a copia algum dado de um descritor de arquivo para a rea temporria, escreve a a o contedo da rea temporria para o outro descritor, e repete essa operao u a a ca at que todos os dados tenham sido copiados. Isso ineciente de ambas e e as formas, demora e espao, pelo fato de essa operao requerar memria c ca o adicional para o espao de armazenamento temporrio e executar um cpia c a o extra de dados na rea temporria. a a Usando sendle, a rea de armazenamento pode ser eliminada. Chame a sendle, informando o descritor de arquivo no qual deve ser feita a cpia; o o 229

descritor que deve ser lido; um apontador para uma varivel do tipo oset; a e o nmero de bytes a serem transferidos. A varivel do tipo oset contm o u a e oset no arquivo de entrada do qual a leitura deve iniciar (0 indica o in cio do arquivo) e atualizado para a posio no arquivo aps a transferncia. O e ca o e valor de retorno o nmero de bytes transferidos. Include <sys/sendle.h> e u em seu programa se ele for usar sendle. O programa na Listagem 8.10 uma implementao simples mas exe ca tremamente eciente de uma cpia de arquivo. Quando chamada com dois o nomes de arquivo pela linha de comando, o programa da Listagem 8.10 copia o contedo do primeiro arquivo dentro de um arquivo nomeado pelo segundo. u O programa usa fstat para determinar o tamanho, em bytes, do arquivo de or gem. Listagem 8.10: (copy.c) Cpia de Arquivo Usando sendle o
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include #include #include #include #include #include #include < f c n t l . h> < s t d l i b . h> <s t d i o . h> <s y s / s e n d f i l e . h> <s y s / s t a t . h> <s y s / t y p e s . h> <u n i s t d . h>

i n t main ( i n t a r g c , char a r g v [ ] ) { int r e a d f d ; int w r i t e f d ; struct s t a t s t a t b u f ; o f f t offset = 0; / Open t h e i n p u t f i l e . / r e a d f d = open ( a r g v [ 1 ] , O RDONLY) ; / S t a t t h e i n p u t f i l e t o o b t a i n i t s f s t a t ( r e a d f d , &s t a t b u f ) ; / Open t h e o u p u t f i l e f o r w r i t i n g , source f i l e . / w r i t e f d = open ( a r g v [ 2 ] , O WRONLY | / B l a s t t h e b y t e s f r o m one f i l e t o s e n d f i l e ( w r i t e f d , r e a d f d , &o f f s e t / C l o s e up . / close ( read fd ) ; close ( write fd ) ; return 0 ; }

size . with

/ as the

t h e same p e r m i s s i o n s

O CREAT, s t a t b u f . s t m o d e ) ; the other . / , stat buf . st size ) ;

A chamada sendle pode ser usada em muitos lugares para fazer cpias o mais ecientes. Um bom exemplo em um servidor web ou outro programa e que trabalha em segundo plano dentro de uma rede, que oferece o contedo u de um arquivo atravs de uma rede para um programa cliente. Tipicamente, e uma requisio recebida de um socket conectado ao computador cliente. O ca e programa servidor abre um arquivo no disco local para recuperar os dados a serem servidos e escrever o contedo do arquivo para o socket de rede. O u uso sendle pode aumentar a velocidade dessa operao considervelmente. ca a Outros passos perecisam ser seguidos para fazer a transferncia de rede to e a eciente quanto poss vel, tais como ajustar os parmetros do socket corretae mente. Todavia, esses passo esto fora do escopo desse livro. a 230

8.13

A Chamada setitimer : Ajustando Intervalos em Temporizadores

A chamada de sistema setitimer uma generalizao da chamada alarm. A e ca chamada de sistema setitimer agenda a entrega de um sinal em algum ponto no futuro aps um intervalo xo de tempo ter passado. o Um programa pode ajustar trs diferentes tipos de temporizadores com e setitimer : e Se o cdigo do temporizador for ITIMER REAL, ao processo o enviado um sinal SIGALRM aps o tempo de relgio normal espeo o cicado ter passado. Se o cdigo do temporizador for ITIMER VIRTUAL, ao processo o e enviado um sinal SIGVTALRM aps o processo ter executado por o um tempo espec co. Tempo no qual o processo no est execua a tando (isto , quando o kernel ou outro processo est rodando) no e a a contado. e Se o cdigo do temporizador for ITIMER PROF, ao processo eno e viado um sinal SIGPROF quando o tempo especicado tiver passado ou durante a execuo prpria do processo ou da execuo de ca o ca uma chamada de sistema por parte do processo. O primeiro argumento a setitimer o cdigo do temporizador, especie o cando qual o tipo de temporizador a ser ajustado. O segundo argumento e um apontador a um objeto struct itimerval especicando o novo ajuste paa aquele temporizador. O terceiro argumento, se no for vazio, um apontador a e outro objeto struct itimerval que recebe os antigos ajustes de temporizador. Uma varivel struct itimerval tem dois campos: a it value um campo struct timeval que contm o tempo at a e e e prxima ativao do temporizador e o sinal enviado. Se esse o ca e valor for 0, o temporizador est desabilitado. a it interval outro campo struct timeval contendo o valor para o e qual o temporizador ir ser zerado aps esse tempo passar. Se esse a o valor for 0, o temporizador ir ser desabilitado aps esse valor exa o pirar. Se esse valor for diferente de zero, o temporizador ajustado e para expirar repetidamente aps esse intrevalo. o O tipo struct timeval descrito na Seo 8.7, A Chamada gettimeofday: e ca Hora relgio Comum. o 231

O programa na Listagem 8.11 ilustra o uso de setitimer para rastrear o tempo de execuo de um programa. Um temporizador congurado para ca e expirar a cada 250 milisegundos e enviar um sinal SIGVTALRM. Listagem 8.11: (itimer.c) Exemplo de Temporizador
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include #include #include #include < s i g n a l . h> <s t d i o . h> < s t r i n g . h> <s y s / t i m e . h>

void t i m e r h a n d l e r ( i n t signum ) { s t a t i c int count = 0 ; p r i n t f ( t i m e r e x p i r e d %d t i m e s \n , ++c o u n t ) ; } i n t main ( ) { struct s i g a c t i o n struct i t i m e r v a l

sa ; timer ; handler f o r SIGVTALRM . /

/ I n s t a l l t i m e r h a n d l e r a s t h e s i g n a l memset (& sa , 0 , s i z e o f ( s a ) ) ; s a . s a h a n d l e r = &t i m e r h a n d l e r ; s i g a c t i o n (SIGVTALRM, &sa , NULL) ;

/ C o n f i g u r e t h e t i m e r t o e x p i r e a f t e r 250 msec . . . timer . i t v a l u e . t v s e c = 0; timer . i t v a l u e . tv usec = 250000; / . . . and e v e r y 250 msec a f t e r t h a t . / timer . i t i n t e r v a l . t v s e c = 0; timer . i t i n t e r v a l . tv usec = 250000; / S t a r t a v i r t u a l t i m e r . I t c o u n t s down w h e n e v e r executing . / s e t i t i m e r ( ITIMER VIRTUAL , &t i m e r , NULL) ; / Do b u s y w o r k . while ( 1 ) ; } /

this

process

is

8.14

A Chamada de Sistema sysinfo: Obtendo Estat sticas do Sistema

A chamada de sistema sysinfo preenche uma estrutura com estat sticas do sistema. O unico argumento da chamada de sistema sysinfo um apontador e para uma struct sysinfo. Alguns dos mais interessantes campos de struct sysinfo que so preenchidos incluem os seguintes: a uptime Tempo decorrido desde o boot do sistema, em segundos totalram Total de memria RAM f o sica dispon vel freeram Memria RAM livre o procs Nmero de processos no sistema u Veja a pgina de manual da sysinfo para uma completa descrio da a ca struct sysinfo. Include <linux/kernel.h>, <linux/sys.h>, e <sys/sysinfo.h> se voc usa sysinfo. e 232

O programa na Listagem 8.12 mostra algumas estat sticas sobre o sistema atual. Listagem 8.12: (sysinfo.c) Mostra Estat sticas do Sistema
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include #include #include #include <l i n u x / k e r n e l . h> <l i n u x / s y s . h> <s t d i o . h> <s y s / s y s i n f o . h>

i n t main ( ) { / C o n v e r s i o n c o n s t a n t s . / const long minute = 6 0 ; const long hour = minute 6 0 ; const long day = hour 2 4 ; const double megabyte = 1024 1 0 2 4 ; / O b t a i n s y s t e m s t a t i s t i c s . / struct s y s i n f o s i ; s y s i n f o (& s i ) ; / Summarize i n t e r s t i n g v a l u e s . / p r i n t f ( s y s t e m uptime : %l d days , %l d :%02 l d :%02 l d \n , s i . uptime / day , ( s i . uptime % day ) / hour , ( s i . uptime % hour ) / minute , s i . uptime % minute ) ; p r i n t f ( t o t a l RAM : %5.1 f MB\n , s i . t o t a l r a m / megabyte ) ; p r i n t f ( f r e e RAM : %5.1 f MB\n , s i . f r e e r a m / megabyte ) ; p r i n t f ( p r o c e s s c o u n t : %d\n , s i . p r o c s ) ; return 0 ; }

8.15

A Chamada de Sistema uname

A chamada de sistema uname preenche uma estrutura com vrias informaes a co do sistema, incluindo o nome de rede computador e o nome de dom nio, e a verso do sistema operacional que est rodando. Informe a uname um a a unico argumento, um apontador para um objeto struct utsname. Include <sys/utsname.h> se voc usa uname. e A chamada a uname preenche os campos abaixo: sysname O nome do sistema operacional (tal como GNU/Linux). release, version O nmero de release do kernel do GNU/Linux e u n da verso. vel a machine Alguma informao sobre a plantaforma do hardware ca rodando GNU/Linux. Para x86 GNU/Linux, a plantaforma i386 e ou i686, dependendo do processador. node O nome de host no qualicado do computador. a domain O nome de dom nio do computador.

Cada um desses campos sequncia de caracteres. e e O pequeno programa na Listagem 8.13 mostra o release do GNU/Linux e o nmero de verso e a informao de hardware. u a ca 233

Listagem 8.13: (print-uname.c) Mostra o nmero de Verso do u a GNU/Linux e Informao de Hardware ca


1 2 3 4 5 6 7 8 9 10 11 #include <s t d i o . h> #include <s y s / utsname . h> i n t main ( ) { s t r u c t utsname u ; uname (&u ) ; p r i n t f ( %s r e l e a s e %s ( v e r s i o n %s ) on %s \n , u . sysname , u . r e l e a s e , u . v e r s i o n , u . machine ) ; return 0 ; }

234

Cap tulo 9 Cdigo Assembly Embutido o


HOJE, POUCOS PROGRAMADORES USAM A LINGUAGEM ASSEMBLY. Linguagens de alto n tais C e C++ rodam sobre praticamente todas vel as arquiteturas e retornam alta produtividade em escrita e manuteno de ca cdigo. Para ocasies em que programadores precisam usar instrues assemo o co bly em seus programas, a Coleo de Compiladores GNU (GNU Compiler ca Collection) permite aos programadores adicionar instrues em linguagem co assembly independentes da arquitetura a seus programas. As declaraes em assembly embutido da GCC no deve ser usado indisco a criminadamente. Instrues em linguagem assembly so dependentes da arco a quitetura, de forma que, por exemplo, programas usando instrues x86 no co a podem ser compilados sobre computadores PowerPC. Para usar instrues co em assembly, voc ir precisar de uma facilidade na linguagem assembly e a para sua arquitetura. Todavia, declaraes em assembly embutido permitem co a voc acessar o hardware diretamente e pode tambm retornar cdigo de e e o execuo mais rpido. ca a Uma instruo asm permite a voc inserir instrues da linguagem asca e co sembly dentro de seus programas C e C++. Por exemplo, essa instruo ca asm ("fsin" : "=t" (resposta) : "0" (angulo)); uma forma espec e ca da arquitetura x86 de codicar a seguinte de1 clarao em C : ca resposta = sin (angulo);
A expresso sin (angulo) comumente implementada como uma chamada de funo a e ca dentro da biblioteca math, mas se voc especicar o sinalizador de otimizao -O1 ou e ca maior, o GCC esperto o suciente para substituir a chamada de funo com uma unica e ca instruo fsin na linguagem assembly. ca
1

235

Observe que diferentemente das instrues em cdigo assembly comum, co o declaraes asm permitem a voc especicar operandos de entrada e sa co e da usando sintaxe em C2 . Para ler mais sobre o conjunto de instrues da arquitetura x86, que ireco mos usar nesse cap tulo, veja http://developer.intel.com/design/pent iumii/manuals/3 e http://www.x86-64.org/documentation.html4 .

9.1

Quando Usar Cdigo em Assembly o

Embora declaraes asm possam ser abusadas, elas permitem a seus proco gramas acessar um hardware do computador diretamente, e as instrues co asm podem produzir programas que executam rapidamente. Voc pode usar e as instrues asm quando estiver escrevendo cdigo de sistema operacional co o que precisa interagir diretamente com hardware. Por exemplo, /usr/include/asm/io.h 5 contm instrues em assembly para acessar portas de entrae co da/sa diretamente. O arquivo de cdigo fonte do GNU/Linux /usr/src/lida o nux/arch/i386/kernel/process.s fornece outro exemplo, usando hlt no cdigo o 6 do lao idle . Veja outros arquivos de cdigo fonte do GNU/Linux no c o /usr/src/linux/arch/ e /usr/src/linux/drivers/ 7 . Instrues assembly podem tambm aumentar a velocidade do lao mais co e c 8 interno de programas de computadores . Por exemplo, Se a maior parte
2 3

No slackware existem o assembler as86 que o mesmo as, o nasm e o yasm e Nota do tradutor:http://www.intel.com/products/processor/manuals/index.

htm. Nota do tradutor. Outras fontes: O Assembly-HOWTO que acompanha sua distribuio GNU/Linux ca http://asm.sourceforge.net/resources.html#tutorials http://download.savannah.gnu.org/releases/pgubook/ ProgrammingGroundUp-1-0-booksize.pdf http://homepage.mac.com/randyhyde/webster.cs.ucr.edu/www.artofasm.com/ index.html http://www.drpaulcarter.com/pcasm http://www.iaik.tugraz.at/ content/teaching/bachelor courses/rechnernetze und organisation/downloads/ 02 LinuxAssembly.pdf http://heather.cs.ucdavis.edu/matloff/50/LinuxAssembly.html http://gcmuganda.faculty.noctrl.edu/classes/Winter10/220/gasmanual.pdf http://gcmuganda.faculty.noctrl.edu/classes/Winter10/220/asm.pdf http://fileadmin.cs.lth.se/cs/Education/EDA180/tools/intel.pdf http://asm.sourceforge.net/ 5 Nota do tradutor: esse arquivo localiza-se em /usr/include/sys no kernel 2.6. 6 Nota do tradutor: nos fontes do kernel 2.6 temos dois arquivos .s o /usr/src/linux/arch/x86/kernel/asm-osets.s e o /usr/src/linux/kernel/bounds.s. 7 Nota do tradutor: veja a nota 4 para outros exemplos. 8 Nota do tradutor: o lao mais interno o que executa mais vezes. c e
4

236

do tempo de execuo de um programa calculando o seno e o cosseno ca e dos mesmos ngulos, esse lao mais interno pode ser recodicado usando a a c instruo x86 fsincos 9 . Veja, por exemplo, /usr/include/bits/mathinline.h, ca que empacota dentro de macros algumas sequncia de assembly embutido e que aumentam a velocidade de clculo de funes transcedentes10 . a co Voc deve uar assembly embutido para fazer cdigos mais rpidos somente e o a em ultimo caso. Atualmente os compiladores esto bastante sosticados e co a nhecem muito sobre os detalhes dos processadores para os quais eles geram cdigo. Portanto, compiladores podem muitas vezes mudar sequncias de o e cdigo que podem ser vistas como no intuitivas ou que voltam ao mesmo o a lugar mas que no momento executam mais rpido que outras sequncias de a e instruo. A menos que voc entenda o conjunto de instrues e os atrica e co butos de agendamento de tarefas de seu processador alvo muito bem, voc e est provavelmente melhor pegando o cdigo assembly otimizado gerado pelo a o compilador para voc na maioria das operaes. e co Ocasionalmente, uma ou duas instrues em assembly podem substituir co muitas linhas de cdigo de uma linguagem de alto n o vel. Por exemplo, a determinao da posio do bit mais signicativo diferente de zero de um ca ca inteiro no nulo usando a linguagem de programao C requer um lao de a ca c computaes em ponto utuante. Muitas arquiteturas, incluindo a x86, posco suem uma unica instruo assembly (bsr ) para calcular a posio desse bit. ca ca Iremos demonstrar o uso de uma dessas na Seo 9.4, Exemplo. ca

9.2

Assembly Embutido Simples

Aqui introduziremos a sintaxe das intrues do assembler asm com um exemco plo x86 para deslocar um valor de 8 bits para a direita:
asm ("shrl $8, %0" : "=r" (resposta) : "r" (operando) : "cc");

A palavra chave asm seguida por uma expresso entre parntesis cone a e sistindo de sees separadas por dois pontos. A primeira seo contm uma co ca e instruo em assembler e seus operandos. Nesse exemplo, shrl desloca para ca a direita os bits em seu primeiro operando. Seu primeiro operando repree sentado por %0. Seu segundo operando a constante imediata $8. e A segunda seo especica as sa ca das. A sa de uma instruo ir ser da ca a colocada na varvel C resposta, que deve ser um lvalue. A sequncia de a e
Algor tmos ou modicaes em estruturas de dados podem ser mais efetivos em reco duzir um tempo de execuo de programa que usar instrues assembly. ca co 10 Nota do tradutor: veja [Djairo (1985)] para mais informaes sobre nmeros transco u cendentes.
9

237

caracteres =r contm um sinal de igual indicando um operando de sa e da e uma letra r indicando que a resposta est armazenada em um registrador. a A terceira seo especica as entradas. O operando da varvel C especica ca a o valor para deslocar. A sequncia de caractere r indica que esse valor a e deslocar est armazenado em um registro mas omite um sinal de igualdade a pelo fato de esse operando ser um operando de entrada, no um operando de a sa da. A quarta seo indica que a instruo muda o valor na condio de cdigo ca ca ca o de registrador cc.

9.2.1

Convertendo Instrues asm em Instrues Asco co sembly

O tratamento do GCC de declaraes asm muito simples. O GCC proco e duz instrues assembly para tratar os operandos asm, e o GCC substitui a co declarao asm com a instruo que voc especica. O GCC no analiza a ca ca e a instruo de nenhuma forma. ca Por exemplo, GCC converte esse fragmento de programa11 double foo, bar; asm ("mycool_asm %1, %0" : "=r" (bar) : "r" (foo)); para essas intrues assembly x86 : co movl -8(%ebp),%edx movl -4(%ebp),%ecx #APP mycool_asm %ecx, %edx #NO_APP movl %edx,-16(%ebp) movl %ecx,-12(%ebp) Lembrando que foo e bar cada um requer duas palavras de armazenamento de pilha sob a arquitetura 32-bit x86. O registrador ebp aponta para dados na pilha. As primeiras duas instrues copiam foo para os registradores EDX e co ECX nos quais mycool asm opera. O compilador decide usar os mesmos registradores para para armazenar a resposta, a qual copiada para bar pelas e duas instrues nais. O compilador escolhe os registradores apropriados, co inclusive reutilizando os mesmos registradores, e copia operandos para e das localizaes apropriadas automaticamente. co
11

Nota do tradutor: veja I.1 para outro exemplo.

238

9.3

Sintaxe Assembly Extendida

Nas subsees que seguem, descrevemos as regras de sintaxe para declaraes co co asm. Suas sees so separadas por dois pontos. co a Iremos referir-nos ` seguinte declarao asm ilustrativa, que calcula a a ca expresso booleana x > y: a asm ("fucomip %%st(1), %%st; seta %%al" : "=a" (result) : "u" (y), "t" (x) : "cc", "st"); Primeiro, fucomip compara seus dois operandos x e y, e armazena valores indicando o resultado dentro do registrador de cdigo de condio cc. o ca Ento seta converte esses valores em um resultado 0 ou em um resultado 1. a

9.3.1

Instrues Assembler co

A primeira seo contm as instrues assembler, envolvidas entre aspas duca e co plas. O exemplo asm contm duas instrues assembly, fucomip e seta, sepae co radas por um ponto e v rgula. Se o assembler no permitir ponto e v a rgula, use caracteres de nova linha (\n) para separar instrues. co O compilador ignora o contedo dessa primeira seo, a menos que um u ca n de sinal de porcentagem seja removido, de forma que %% seja mudado vel para %. O signicado de %%st(1) e outros termos semelhantes dependente e da arquitetura. GCC ir reclamar se voc especicar a opo -traditional ou a opo a e ca ca -ansi ao compilar um programa contendo declaraes asm. Para evitar a co produo desses erros, como ocorre em arquivos de cabealho, use a palavra ca c chave alternativa asm .

9.3.2

Sa das

A segunda seo especica os operandos das instrues de sa usando a ca co da sintaxe do C. Cada operando especicado por um sequncia de caracteres e e abreviada de operando seguida por uma expresso em C entre parentesis. a Para operandos de sa os quais devem ser lvalues, a sequncia de caracteres da, e abreviada deve comear com um sinal de igual. O compilador verica que a c expresso em C para cada operando de sa seja de fato um lvalue. a da Letras especicando registradores para uma arquitetura em particular podem ser encontrados no cdigo fonte do GCC, na macro REG CLASS FROM o 239

Tabela 9.1: Letras de registradores para a Arquitetura x86 Intel. Letra de Registrador Registrador Que GCC Pode Usar R Registrador geral (EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP) q Registrador geral para dados (EAX, EBX, ECX, EDX) f Registrador de ponto utuante t Primeiro registrador de n mais alto em ponto vel utuante u Segundo registrador de n mais alto em ponto vel utuante a Registrador EAX b Registrador EBX c Registrador ECX d Registrador EDX x Registrador SSE (Registrador de extenso de uso a de SIMD) y Registrador MMX registradores multimedia A Um valor de 8-byte formado a partir de EAX e de EDX D Apontador de destino para operaes de sequncia co e de caracteres (EDI) S Apontador de or gem para operaes de sequncia co e de caracteres (ESI) LETTER12 . Por exemplo, o arquivo gcc/cong/i386/i386.h13 de congurao ca 14 no GCC lista as letras de registradores para a arquitetura x86 . A Tabela 9.1 sumariza isso. Multiplos operandos em uma declarao asm, cada um especicado por ca uma constante no formato de uma sequncia de caracteres abreviada e uma e expresso C, so separados por v a a rgulas, como ilustrado no exemplo da seo ca de entradas asm. Voc pode especicar at 10 operandos, denotados por %0, e e %1, ..., %9, em sees de sa e em sees de entrada. Se no existirem co da co a operandos de sa mas houverem operandos de entrada ou registradores de da
Nota do tradutor: encontra-se referncia a REG CLASS FROM LETTER em /usr/ e lib64/gcc/x86 64-slackware-linux/4.5.2/plugin/include/defaults.h 13 Nota do tradutor: /usr/lib64/gcc/x86 64-slackware-linux/4.5.2/plugin/ include/config/i386/i386.h. 14 Voc precisar ter alguma familiaridade com a parte interna do GCC para ver algum e a sentido nesse arquivo.
12

240

cr tica, mantenha a seo de sa vazia ou marque a seo de sa como ca da ca da comentrio como /* sa a das vazias */.

9.3.3

Entradas

A terceira seo especica os operandos de entrada para as instrues assemca co bler. A constante de sequncia de caracteres no deve ter um sinal de igual, e a o qual indica um lvalue. De outra forma, a sintaxe de operandos de entrada a mesma para operandos de sa e da. Para indicar que cada registrador ambos de leitura de e escrever e para o mesmo asm, use uma entrada de sequncia de caracteres abrevie ada do nmero de operandos de sa u da. Por exemplo, para indicar que um registrador de entrada o mesmo que o primeiro nmero de registrador de e u sa da, use 0. Operandos de sa so numerados da esquerda para a direita, da a iniciando em 0. Meramente especicando a mesma expresso em C para um a operando de sa e um operando de entrada no garante que os dois valores da a iro ser colocados no mesmo registrador. a Essa seo de entrada pode ser omitida se no houverem operandos de ca a entrada e a subsequnte seo de cr e ca tica estiver vazia.

9.3.4

Cr tica

Se uma instruo modica os valores de um ou mais registradores como ca um efeito colateral, especique os registradores criticados na quarta seo ca do comando asm. Por exemplo, a instruo fucomip modica o registraca dor de cdigo de condio, o qual denotado por cc. Sequncias de cao ca e e ractere separadas representam registradores criticados com v rgulas. Se a instruo pode modicar uma localizao de memria arbitrria, especique ca ca o a a memria. Usando a informao de cr o ca tica, o compilador determina quais os valores que devem ser recarregados aps a linha asm ser executada. Se o voc no especica essa informao corretamente, GCC pode assumir incore a ca retamente que registradores ainda conteem valores que tenham, de fato, sido sobrescritos, o que ir afetar a correo de seu programa. a ca

9.4

Exemplo

A arquitetura x86 inclui instrues que determinam as posies do menos co co signicativo conjunto de bit e do mais signicativo conjunto de bit em uma palavra. O processador pode executar essas instrues muito ecientemente. co 241

Ao contrrio, implementando a mesma operao em C requer um lao e um a ca c deslocamento de bit. Por exemplo, a instruo assembly bsrl 15 calcula a posio do conjunto de ca ca bits mais signicativo em seu primeiro operando, e coloca a posio (contando ca a partir do 0, o bit menos signicativo) dentro do seu segundo operando. Para colocar a posio do bit para nmero dentro da posio, podemos usar essa ca u ca declarao asm: ca

asm ("bsrl %1, %0" : "=r" (posicao) : "r" (numero));

Um caminho atravs do qual voc pode implementar a mesma operao e e ca em C usando o seguinte lao: e c

long i; for (i = (numero >> 1), posicao = 0; i != 0; ++posicao) i >>= 1;

Para testar a velocidad relativa dessas duas verses, iremos coloc-las em o a um lao que calcula as posies de bit para um grande nmero de valores. A c co u Listagem 9.1 faz isso usando o lao na implementao em C. O programa enc ca tra no lao a cada inteiro, de 1 at o valor especicado na linha de comando. c e Para cada valor de nmero, o programa calcula o bit mais signicativo que u escolhido. A Listagem 9.2 faz a mesma coisa usando a instruo em ase ca sembly embutido. Note que em ambas as verses, atribuimos ` posio de o a ca bit calculada a uma varivel de resultado do tipo volatile. Isso para forar a e c a otimizao do compilador de forma que o otimizador do compilador no ca a elimine a computao da posio do bit completamente; se o resultado no ca ca a e usado ou no armazenado na memria, o otimizador elimina a computao a e o ca como cdigo morto. o
15

Nota do tradutor: veja I.2 para maiores detalhes.

242

Listagem 9.1: (bit-pos-loop.c) Encontra a Posio do Bit Usando um Lao ca c


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <s t d i o . h> #include < s t d l i b . h> i n t main ( i n t a r g c , char a r g v [ ] ) { long max = a t o i ( a r g v [ 1 ] ) ; long number ; long i ; unsigned p o s i t i o n ; v o l a t i l e unsigned r e s u l t ; / R e p e a t t h e o p e r a t i o n f o r a l a r g e number o f v a l u e s . / f o r ( number = 1 ; number <= max ; ++number ) { / R e p e a t e d l y s h i f t t h e number t o t h e r i g h t , u n t i l t h e r e s u l t i s zero . Keeep c o u n t o f t h e number o f s h i f t s t h i s r e q u i r e s . / f o r ( i = ( number >> 1 ) , p o s i t i o n = 0 ; i != 0 ; ++p o s i t i o n ) i > >= 1 ; / The p o s i t i o n o f t h e most s i g n i f i c a n t s e t b i t i s t h e number o f s h i f t s we n e e d e d a f t e r t h e f i r s t one . / result = position ; } return 0 ; }

Listagem 9.2: (bit-pos-asm.c) Encontra a posio do Bit Usando bsrl ca


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <s t d i o . h> #include < s t d l i b . h> i n t main ( i n t a r g c , char a r g v [ ] ) { long max = a t o i ( a r g v [ 1 ] ) ; long number ; unsigned p o s i t i o n ; v o l a t i l e unsigned r e s u l t ; / R e p e a t t h e o p e r a t i o n f o r a l a r g e number o f v a l u e s . / f o r ( number = 1 ; number <= max ; ++number ) { / Compute t h e p o s i t i o n o f t h e most s i g n i f i c a n t s e t b i t u s i n g b s r l assembly i n s t r u c t i o n . / asm ( b s r l %1, %0 : =r ( p o s i t i o n ) : r ( number ) ) ; result = position ; } return 0 ; }

the

Compilaremos ambos com otimizao completa: ca % cc -O2 -o bit-pos-loop bit-pos-loop.c % cc -O2 -o bit-pos-asm bit-pos-asm.c Agora vamos executar cada um usando o comando time para medir o tempo de execuo. Especicaremos um valor grande como argumento de ca linha de comando, para garantir que cada verso demore pelo menos alguns a segundos para executar.
% time ./bit-pos-loop 250000000 19.51user 0.00system 0:20.40elapsed 95%CPU (0avgtext+0avgdata 0maxresident)k0inputs+0outputs (73major+11minor)pagefaults 0swaps % time ./bit-pos-asm 250000000 3.19user 0.00system 0:03.32elapsed 95%CPU (0avgtext+0avgdata 0maxresident)k0inputs+0outputs (73major+11minor)pagefaults 0swaps

Note que a verso que usa assembly embutido executa com larga margem a mais rapidamente (seus resultados para esse exemplo podem variar). 243

9.5

Recursos de Otimizao ca

O otimizador do GCC tenta rearranjar e reescrever cdigos de programas o para minimizar o tempo de execuo mesmo na presena de expresses asm. ca c o Se o otimizador determinar que um valor de sa da expresso asm no da a a e usada, a instruo ir ser omitida a menos que a palavra chave volatile ocorra ca a entre asm e seus argumentos. (Como um caso especial, GCC no ir mover a a um asm sem qualquer operandos de sa fora de um lao.) Qualquer asm da c pode ser movido em caminhos que so dif a ceis de prever, mesmo em saltos. O unico caminho para garantir que uma instruo assembly em uma ordem ca em particular incluir todas as instrues em um mesmo asm. e co Usando asms podemos restringir a ecincia do otimizador pelo fato de o e compilador no conhece a semntica dos asms. GCC forado a suposies a a e c co conservadoras que podem prevenir algumas otimizaes. Caveat emptor! 16 co

9.6

Manutenso e Recursos de Portabilidade a

Caso voc resolva usar declaraes asm no portveis e dependentes da are co a a quitetura, encapsulando essas declaraes dentro de macros ou funes pode co co ajudar na manutenso e na portabilidade. Colocando todas essas macros a em um arquivo e documentando-as ir ser fcil port-las para uma arquitea a a tura diferente, alguma coisa que ocorre com surpreendente frequncia mesmo e para programas jogados-longe. Dessa forma, o programador ir precisar a re-escrever somente um arquivo para a arquitetura diferente. Por exemplo, a maioria das declaraes asm em cdigo fonte GNU/Linux co o esto agrupadas nos arquivos de cabealho /usr/src/linux/include/asm e em a c 17 /usr/src/linux/include/asm-i386 , e arquivos fonte em /usr/src/linux/arch/i386/ e /usr/src/linux/drivers/.

Nota do tradutor: expresso latina que quer dizer o risco do comprador. a e Nota do tradutor: no slackware 13.37 64 bits temos trs diretrios asm: o asm (que e o um link) o asm-x86 e o asm-generic e
17

16

244

Cap tulo 10 Segurana c


GRANDE PARTE DO PODER DE UM SISTEMA GNU/LINUX VEM DE seu suporte a mltiplos usurios e a trabalhos em rede. Muitas pessoas u a podem usar o sistema de uma s vez, e essas pessoas podem conectar-se o ao sistema a partir de localizaes remotas. Desafortunadamente, com esse co poder vem riscos, especialmente para sistemas conectados ` Internet . Sob a algumas circunstncias, um hacker 1 pode conectar-se ao sistema e ler, a modicar, ou remover arquivos que esto armazenados na mquina. Ou, a a dois usurios na mesma mquina podem ler, modicar, ou remover arquivos a a do outro quando eles no deveriam ter permisso para fazer isso. Quando a a isso acontece, a segurana do sistema foi comprometida. c O kernel do GNU/Linux fornece uma variedade de facilidades para garantir que esses eventos no tenham lugar. Mas para evitar violaes de a co segurana, aplicaes comuns devem ser cuidadosas tambm. Por exemplo, c co e imagine que voc est desenvolvendo um programa de contabilidade. Embora e a voc possa desejar que todos os usurios sejam capazes de enviar relatrios e a o de despesa com o sistema, voc pode no desejar que todos os usurios sejam e a a capazes de aprovar esses relatrios. Voc pode desejar que usurios sejam o e a capazes de ver suas prprias informaes salariais enquanto funcionrios da o co a empresa, mas voc certamente no ir desejar que eles sejam capazes de ver e a a as informaes salariais de todos os outros funcionrios. Voc pode desejar co a e que gerentes sejam capazes de ver os salrios de empregados de seus departaa mentos respectivos, mas voc no ir desejar que os gerentes vejam os salrios e a a a de empregados de outros departamentos. Para fazer cumprir esses tipos de controle, voc deve ser muito cuidadoso. e surpreendentemente fcil cometer um erro que permite ao usurios fazer E a a alguma coisa que voc no tinha inteno de permitir que eles fossem fazer. A e a ca
Nota do tradutor: as aspas procuram ressaltar a diferena entre o signicado popular c e o verdadeiro signicado da palavra hacker.
1

245

melhor abordagem conseguir ajuda de experts em segurana. No obstante, e c a todo desenvolvedor de aplicao deveria entender o bsico. ca a

10.1

Usurios e Grupos a

A cada usurio GNU/Linux atribu um nmero unico, chamado ID de a e do u usurio, ou UID. Certamente quando voc coloca sua senha, voc usa um a e e nome de usurio em lugar do ID2 . O sistema converte seu nome de usurio a a em um ID particular de usurio, e a partir de ento somente o ID de usurio a a a passa a ser considerado. Voc pode atualmente ter mais de um nome de usurio para o mesmo e a ID de usurio. No que diz respeito ao sistema, os IDs de usurio, no os a a a nomes de usurio, devem coincidir. No existe forma de fornecer um nome a a de usurio mais forte que outro se eles ambos correspondem ao mesmo ID de a usurio. a Voc pode controlar o acesso a um arquivo ou outro recurso associando e esse arquivo ou recurso a um ID de usurio em particular. Ento somente a a o usurio correspondendo `quele ID de usurio pode acessar o recurso. Por a a a exemplo, voc pode criar um arquivo que somente voc pode ler, ou um e e diretrio no qual somente voc pode criar novos arquivos. Isso bom o o e e sucente para muitos casos simples. Algumas vezes, todavia, voc deve compartilhar um recurso entre multie plos usurios. Por exemplo, se voc um gerente, voc pode desejar criar a ee e um arquivo que qualquer gerente pode ler mas que funcionrios comuns no a a possam. GNU/Linux no permite a voc associar multiplos IDs de usurio a e a a um arquivo, de forma que voc no pode apenas criar uma lista de todas e a as pessoas `s quais voc deseja fornecer acesso e anexar a essa lista todo o a e arquivo. Voc pode, no entanto, criar um grupo. A cada grupo atribu um e e do nmero unico, chamado ID de grupo, ou GID. Todo grupo contm um ou u e mais IDs de usurio. Um unico ID de usurio pode ser membro de muia a tos grupos, mas grupos no podem conter outros grupos; os grupos podem a conter somente usurios. Como usurio, grupos possuem nomes. Tambm a a e como nomes de usurios, todavia, os nomes de grupo no precisam realmente a a coincidir; o sistema sempre usa o ID de grupo internamente. Continuando nosso exemplo, voc pode criar um grupo de gerentes e e colocar os IDs de usurio de todos os gerentes nesse grupo. Voc pode ento a e a criar um arquivo que possa ser lido por qualquer um no grupo de gerentes mas
2

Nota do tradutor: IDentication.

246

no por pessoas que estejam fora do grupo. Em geral, voc pode associar a e 3 somente um grupo a um recurso . No existe forma para especicar que a usurios podem acessar um arquivo somente se estiver no grupo 7 ou no a grupo 42, por exemplo. Se voc est curioso para ver qual seu ID de usurio e em quais grupos e a e a voc est inscrito, voc pode usar o comando id. Por exemplo, a sa pode e a e da se parecer como segue:
% id uid=501(mitchell) gid=501(mitchell) groups=501(mitchell),503(csl)

A primeira parte mostra a voc que o ID de usurio para o usurio que e a a executou o comando era 501. O comando tambm mostra qual o correspone dente nome de usurio que est sendo usado entre parntesis. O comando a a e mostra que o ID de usurio 501 est atualmente em dois grupos: grupo 501 a a (chamado mitchell ) e grupo 503 (chamado csl ). Voc est provavelmente mae a ravilhado pelo fato de o grupo 501 aparecer duas vezes: uma vez no campo gid e outra vez no campo de groups. Iremos falar sobre isso mais tarde.

10.1.1

O Superusurio a

Uma conta de usurio muito especial4 . Esse usurio tem ID de usurio 0 a e a a e comumente tem o nome de usurio root. Essa conta especial de usurio a a tambm algumas vezes referida como a conta de superusurio. O usurio e e a a root pode fazer qualquer coisa: ler qualquer arquivo, remover qualquer arquivo, adicionar novos usurios, desligar o acesso ` rede, e assim por diante. a a Grandes quantidades de operaes especiais podem ser executadas somente co por processos executando com privilgio de root isto , executando como e e usurio root. a O problema com esse projeto que uma grande quantidade de prograe mas precisa ser executado pelo root pelo fato de uma grande quantidade de programas precisar executar uma dessas operaes especiais. Se qualquer co desses programas se comporta mal, o caos pode ser o resultado. No existe a uma maneira efetiva para conter um programa quando ele est sendo execua tado pelo root; o root no pode fazer nada. Programas executando pelo root a devem ser escritos muito cuidadosamente.
Nota do tradutor: um arquivo no pode ter dois grupos ou dois donos. a O fato de existir somente um usurio especial deu a AT&T o nome para seu sisa tema operacional UNIX. Ao contrrio, um sistema operacional anterior que tinha diversos a usurios especiais era chamado MULTICS. GNU/Linux, certamente, muito mais coma e pat com UNIX. vel
4 3

247

10.2

IDs de Usurio e IDs de Grupo a

At agora, ns vinhamos falando sobre comandos sendo executados por um e o usurio em particular. Isso no bem verdade pelo fato de o computador a a e nunca realmente saber qual usurio est usando o referido programa que est a a a sendo executado. Se o usurio Eve descobre o nome de usurio e a senha a a do usurio Alice, ento o usurio Eve pode se conectar ao computador como a a a Alice, e o computador ir permitir a Eve fazer tudo que Alice pode fazer. O a sistema sabe somente qual o ID do usurio em uso, no qual o usurio que est a a a a digitando os comandos. Se Alice no pode ser convel em manter sua senha a a somente consigo mesma, por exemplo, ento nada que voc zer enquanto a e desenvolvedor de uma aplicao ir evitar Eve de acessar os arquivos de ca a Alice. A responsabilidade pela segurana do sistema compartilhada entre c e o desenvolvedor da aplicao, os usurios do sistema, e dos administradores ca a do sistema. Todo processo tem um ID de usurio e um ID de grupo associado. Quando a voc chama um comando, esse comando tipicamente executa em um processo e cujos ID de usurio e ID de grupo so iguais aos seus ID de usurio e ID de a a a grupo. Quando dizemos que um usurio executa uma operao, realmente a ca signica que um processo com o correspondente ID de usurio executa aquela a operao. Quando o processo faz uma chamada de sistema, o kernel decide se ca permite que a operao continue. O kernel decide examinando as permisses ca o associadas ao recurso que o processo est tentando acessar e vericando o ID a de usurio e ID de grupo associado ao processo tentando executar a ao. a ca Agora voc sabe o que aquele campo do meio mostrado pelo comando id e signica. Ele est mostrando o ID de grupo do processo atual. Apesar de o a usurio 501 estar em multiplos grupos, o processo atual pode ter um unico a ID de grupo. No exemplo mostrado previamente, o atual ID de grupo 501. e Se voc tem que manipular IDs de usurio e IDs de grupo em seu programa e a (e voc ir, se voc est escrevendo programas que lidam com segurana), e a e a c ento voc deve usar os tipos uid t e gid t denidos em <sys/types.h>5 . a e Apesar de IDs de usurio e IDs de grupo serem essencialmente apenas inteia ros, evite fazer qualquer suposies sobre quantos bits so usados nesses tipos co a ou executar operaes aritmticas sobre eles. Apenas trate os tipos uid t e co e gid t como manipuladores opacos para a identidade de usurio e identidade a de grupo. Para pegar o ID de usurio e o ID de grupo para o processo atual, voc a e 6 pode usar as funes geteuid e getegid, declaradas em <unistd.h> . Essas co
5 6

Nota do tradutor: /usr/include/sys/types.h. Nota do tradutor: /usr/include/unistd.h.

248

funes no recebem parmetros, e funcionam sempre; voc no deve verico a a e a car erros. A Listagem 10.1 mostra um programa simples que fornece um subconjunto de funcionalidades fornecida pelo comando id : Listagem 10.1: (simpleid.c) Mostra ID de usurio e ID de grupo a
1 2 3 4 5 6 7 8 9 10 11 #include <s y s / t y p e s . h> #include <u n i s t d . h> #include <s t d i o . h> i n t main ( ) { u i d t uid = geteuid ( ) ; g i d t gid = getegid () ; p r i n t f ( u i d=%d g i d=%d\n , uid , return 0 ; }

gid ) ;

Quando esse programa executado (pelo mesmo usurio que executou o e a programa id anteriormente) a sa como mostrado abaixo: da e % ./simpleid uid=501 gid=501

10.3

Permisses do Sistema de Arquivos o

Uma boa maneira de ver usurios e grupos em ao olhar em permisses do a ca e o sistema de arquivo. Por meio do exame de como o sistema associa permisses o a cada arquivo e ento vendo como o kernel verica para descobrir quem est a a autorizado a acessar determinados arquivos, os conceitos de ID de usurio e a ID de grupo devem tornar-se claros. Cada arquivo tem exatamente um usurio proprietrio e exatamente um a a grupo proprietrio. Quando voc cria um novo arquivo, o arquivo possu a e e do pelo usurio e pelo grupo do processo que o criou7 . a As coisas bsicas que voc pode fazer com arquivos, no que diz respeito ao a e GNU/Linux, so ler a partir de um arquivo, escrever no arquivo, e executar a um arquivo. (Note que criar um arquivo e remover um arquivo no so a a consideradas coisas que voc pode fazer com o arquivo; criar e remover so e a considerados coisas que voc pode fazer com o diretrio contendo o arquivo. e o Iremos falar sobre isso um pouco mais tarde.) Se voc no tem permisso para e a a ler um arquivo, GNU/Linux no ir permitir a voc examinar o contedo do a a e u arquivo. Se voc no tem permisso para escrever em um arquivo, voc no e a a e a pode mudar seu contedo. Se existe um arquivo de programa cuja permisso u a de execuo voc no tem, voc no pode executar o programa. ca e a e a
Atualmente, existem algumas raras excesses, envolvendo sticky bits, discutidos mais o tarde na Seo 10.3.2, Sticky Bits. ca
7

249

GNU/Linux habilita a voc designar qual dessas trs aes leitura, e e co escrita, e execuo pode ser executada pelo usurio proprietrio, grupo ca a a proprietrio, e todas os outros usurios. Por exemplo, voc poder dizer que a a e a o usurio proprietrio pode fazer qualquer coisa que desejar com o arquivo, a a que qualquer um no grupo proprietrio pode ler e executar o arquivo (mas no a a escrever no arquivo), e que ningum mais fora os especicados anteriormente e pode fazer qualquer coisa com o arquivo. Voc pode ver esses bits de permisso interativamente com o comando e a ls usando as opes -l ou -o e programaticamente como a chamada de co sistema stat. Voc pode ajustar os bits de permisso com o programa chmod 8 e a ou programaticamente com a chamada de sistema chmod. Para olhar as permisses sobre um arquivo chamado hello, use ls -l hello. Aqui est como o a a sa pode se parecer: da
% ls -l hello -rwxr-x--1 samuel csl 11734 Jan 22 16:29 hello

Os campos samuel e csl indicam que o usurio proprietrio samuel e a a e que o grupo proprietrio csl. a e A sequncia de caracteres no in da linha indica as permisses associe cio o adas ao arquivo. O primeiro trao indica que o arquivo hello um arquivo c e normal. Esse primeiro trao poderia ser d para um diretrio, ou esse primeiro c o trao poderia ser outras letras para tipos especiais de arquivos tais como disc positivos (veja Cap tulo 6, Dispositivos) ou pipes nomeados (veja Cap tulo 5, Comunicao Entre Processos Seo 5.4, Pipes). Os trs caracteres ca ca e seguintes mostram permisses para o usurio proprietrio; eles indicam que o a a samuel pode ler, escrever, e executar o arquivo. Os trs caracteres seguintes e mostram as permisses dos membros do grupo csl ; esses membros possuem o permisso para somente ler e executar o arquivo hello. Os ultimos trs caraca e teres mostram as permisses para todos os outros usurios restantes; a esses o a usurios restantes no permitido fazer nada com o arquivo hello. a a e Vamos ver como isso trabalha. Primeiramente, vamos tentar acessar o arquivo como o usurio nobody, que no est no grupo csl : a a a % id uid=99(nobody) gid=99(nobody) groups=99(nobody) % cat hello cat: hello: Permission denied % echo hi > hello
Voc ir algumas vezes ver os bits de permisses de um arquivo sendo referenciados e a o como o modo do arquivo. O nome do comando chmod a forma curta para change e mode.
8

250

sh: ./hello: Permission denied % ./hello sh: ./hello: Permission denied No podemos ler o arquivo, o que causa a falha do comando cat; no a a podemos escrever no arquivo, o que causa a falha no comando echo; e no a podemos executar o arquivo, o que causa a falha em ./hello. As coisas cam melhor se voc estiver acessando o arquivo como mitchell, e que um membro do grupo csl : e
% id uid=501(mitchell) gid=501(mitchell) groups=501(mitchell),503(csl) % cat hello #!/bin/bash echo "Hello, world." % ./hello Hello, world. % echo hi > hello bash: ./hello: Permission denied

Podemos listar o contedo do arquivo, e podemos execut-lo (o executvel u a a um script shell simples), mas ainda no podemos escrever nele. e a Se executamos o script como o proprietrio (samuel ), podemos at mesmo a e sobrescrever o arquivo:
% id uid=502(samuel) gid=502(samuel) groups=502(samuel),503(csl) % echo hi > hello % cat hello hi

Voc pode mudar as permisses associadas a um arquivo somente se voc e o e for o proprietrio do arquivo (ou o superusurio). Por exemplo, se voc a a e desejar permitir a todos executar o arquivo, voc pode fazer isso: e
% chmod o+x hello % ls -l hello -rwxr-x--x 1 samuel csl 3 Jan 22 16:38 hello

Note que existe um x ao nal da primeira sequncia de caracteres. O e bit o+x signica que voc deseja adicionar a permisso de execuo para e a ca outras pessoas (que no o proprietrio do arquivo ou os membros de seu a a grupo proprietrio). Voc pode usar g-w ao invs de o+x, para remover a a e e permisso de escrita para o grupo. Veja a pgina de manual de chmod na a a seo 1 para detalhes sobre essa sintaxe: ca % man 1 chmod Programaticamente, voc pode usar a chamada de sistema stat para ene contrar as permisses associadas a um arquivo. A Funo stat recebe dois o ca parmetros: o nome do arquivo do qual voc deseja encontrar a informao, a e ca 251

e o endereo de uma estrutura de dados que preenchida com a infomao c e ca sobre o arquivo. Veja o Apndice B,E/S de Baixo N e vel Seo B.2, stat ca para uma discusso de outras informaes que voc pode obter com stat. A a co e Listagem 10.2 mostra um exemplo de uso da stat para obter as permisses o do arquivo. Listagem 10.2: (stat-perm.c) Determina se o Proprietrio do Arquivo Tem a Permisso de Escrita a
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <s t d i o . h> #include <s y s / s t a t . h> i n t main ( i n t a r g c , char a r g v [ ] ) { const char const f i l e n a m e = a r g v [ 1 ] ; struct s t a t buf ; / Get f i l e i n f o r m a t i o n . / s t a t ( f i l e n a m e , &b u f ) ; / I f t h e p e r m i s s i o n s a r e s e t s u c h t h a t t h e f i l e s owner can to i t , p r i n t a message . / i f ( b u f . s t m o d e & S IWUSR ) p r i n t f ( Owning u s e r can w r i t e % s . \ n , f i l e n a m e ) ; return 0 ; }

write

Se voc executa o programa acima sobre o nosso programa hello, ele vai e retornar: % ./stat-perm hello Owning user can write hello. A constante S IWUSR corresponde ` permisso de escrita para o usurio a a a proprietrio. Existem outras constantes para todos os outros bits de pera misso. Por exemplo, S IRGRP permisso de leitura para o grupo proa e a prietrio, e S IXOTH permisso de execuo para usurios que no esto a e a ca a a a nem no usurio proprietrio nem no grupo proprietrio. Se voc armazena a a a e permisses em uma varivel, use o typedef mode t para essa varivel. Como o a a a maioria das chamadas de sistema, stat ir retornar -1 e ajustar errno caso a no possa obter informaes sobre o arquivo. a co Voc pode usar a funo chmod para mudar os bits de permisso de um e ca a arquivo existente. Voc chama chmod com o nome do arquivo que voc e e deseja mudar e os bits de permisso que voc deseja ajustar, apresentados a e na forma de conjunto de bits ou na forma das vrias constantes de permisso a a mencionadas previamente. Por exemplo, a linha adiante far o hello leg a vel e executvel pelo seu usurio proprietrio mas desabilitar todas as outras a a a a permisses associadas a hello: o chmod ("hello", S\_IRUSR | S\_IXUSR); 252

Os mesmos bits de permisso aplicam-se a diretrios, mas eles possuem a o outros signicados. Se a um usurio permitido ler um diretrio, ao usurio a e o a permitido ver a lista de arquivos que esto presentes naquele diretrio. Se e a o a um usurio permitido escrever em um diretrio, ao usurio permitido a e o a e adicionar ou remover arquivos no referido diretrio. Note que um usurio o a pode remover arquivos de um diretrio se esse mesmo usurio tem permisso o a a de escrita no diretrio, mesmo se ele no tem permisso para modicar o o a a arquivo que ele est removendo. Se a um usurio permitido executar um a a e diretrio, ao usurio permitido entrar naquele diretrio e acessar os arquivos o a e o dentro dele. Sem acesso de execuo a um diretrio, ao usurio no permica o a a e tido acessar os arquivos naquele diretrio independentemente das permisses o o sobre os arquivos propriamente ditos. Sumarizando, vamos revisar como o kernel decide permitir a um processo acessar um arquivo em particular. O kernel faz vericaes para ver se o co usurio que est acessando o usurio proprietrio, um membro do grupo a a e a a proprietrio, ou algum mais. A categoria dentro da qual o usurio que a e a est acessando falhar usada para determinar qual o conjunto de bits de a e leitura/escrita/execuo que vericado. Ento o kernel verica a operao ca e a ca que est sendo executada contra os bits de permisso que se aplicam a esse a a usurio9 . a Existe uma importante excesso: Processos executando como root (aquea les com ID de usurio 0) possuem sempre permisso de acesso a qualquer a a arquivo, indiferentemente das permisses associadas. o

10.3.1

Falha de Segurana: c Sem Permisso de Execuo a ca

Aqui est o primeiro exemplo de onde a segurana encontra muitas coma c plicaes. Voc pode pensar que se voc desabilita a execuo de um proco e e ca grama, ento ningum pode executa-lo. Anal de contas, isto o que signica a e e deabilitar a execuo. Mas um usurio malicioso pode fazer uma cpia do ca a o programa, mudar as permisses no sentido de tornar esse programa executvel, a e ento executar a cpia! Se voc acredita que os usurios no esto aptos a o e a a a a executar programas que no sejam executveis mas no previne que eles a a a copiem os programas, voc tem uma falha de segurana um meio atravs e c e do qual usurios podem executar qualquer ao que voc no quer que eles a ca e a
O kernel pode tambm proibir o acesso a um arquivo se um diretrio componente no e o caminho do seu arquivo estiver inacess vel. Por exemplo, se um processo no puder acessar a o diretrio /tmp/private/, esse processo no pode ler o diretrio /tmp/private/data, mesmo o a o se as permisses sobre esse ultimo estiverem ajustadas para permitir o acesso. o
9

253

faam. c

10.3.2

Sticky Bits

Adicionalmente a permisses para ler, escrever, e executar, existe um bit o mgico chamado sticky bit 10 . Esse bit aplica-se somente a diretrios. a o Um diretrio que tem o sticky bit ativo permite a voc apagar um arquivo o e somente se voc for o dono do arquivo. Como mencionado previamente, voc e e pode comumente apagar um arquivo se voc tiver acesso de escrita para o e diretrio que o contm, mesmo se voc no for o dono do arquivo. Quando o o e e a sticky bit est ativo, voc ainda deve ter acesso de escrita ao diretrio, mas a e o voc deve tambm ser o dono do arquivo que voc quer apagar. e e e Uns poucos diretrios em um sistema t o pico GNU/Linux possuem o sticky bit. Por exemplo, o diretrio /tmp, no qual qualquer usurio pode colocar aro a quivos temporrios, tem o sticky bit ativado. Esse diretrio especicamente a o e disignado para ser usado por todos os usurios, de forma que o diretrio deve a o ter permisso de escrita para todos os usurios. Mas essa permisso de esa a a crita para todos os usurios pode no vir a ser uma boa coisa se um usurio a a a puder vir a apagar arquivos de outro usurio, de forma que o sticky bit a e ativado sobre aquele diretrio. Ento somente o usurio proprietrio (ou o o a a a root, certamente) pode remover um arquivo. Voc pode ver se o sticky bit est ativo pelo fato de existir uma letra t e a no nal dos bits de permisso quando voc executa o comando ls sobre o a e diretrio /tmp: o
% ls -ld /tmp drwxrwxrwt 12 root root 2048 Jan 24 17:51 /tmp

A constante correspondente a ser usada com as funes de linguagem C co 11 stat e chmod S ISVTX . e Se seu programa cria diretrios que comportam-se como o /tmp, no qual o muitas pessoas colocam coisas l mas no devem estar aptas a remover ara a quivos de outras pessoas, ento voc deve ativar o sticky bit sobre o diretrio. a e o Voc pode ativar o sticky bit sobre um diretrio com o comando chmod da e o seguinte forma: % chmod o+t directory
Esse nome anacron e stico; sticky bit remonta ao tempo quando a ativao do ca sticky bit fazia com que um programa casse retido na memria principal mesmo quando o esse programa terminasse sua execuo. As pginas alocadas para o programa estavam ca a stuck(coladas) na memria. o 11 Nota do tradutor: man 2 chmod e man 2 stat.
10

254

Para ajustar o sticky bit programticamente, chame chmod com o sinalia zador de modo S ISVTX. Por exemplo, para ativar o sticky bit do diretrio o especicado em dir path para as mesmas do /tmp e fornecer leitura completa, escrita completa, e permisso de execuo para todos os usurios, use essa a ca a chamada: chmod (dir_path, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX);

10.4

ID Real e ID Efetivo

At agora, falamos sobre o ID de usurio e o ID de grupo associados a um e a processo como se existisse somente um tal ID de usurio e um tal ID de a grupo. Mas, atualmente, isso no to simples assim. a e a Todo processo realmente tem dois IDs de usurio: o ID efetivo de usurio a a e o ID real de usurio. (Certamente, existe tambm um ID efetivo de grupo a e e um ID real de grupo. Quase tudo que verdadeiro sobre IDs de usurio e a tambm verdadeiro sobre IDs de grupo.) A maioria das vezes, o kernel e e verica somente o ID efetivo de usurio. Por exemplo, se um processo tenta a abrir um arquivo, o kernel verica o ID efetivo de usurio para decidir se a permite que o processo acesse o arquivo. As funes geteuid e getegid descritas previamente retornam o ID efetivo co de usurio e o ID efetivo de grupo. De forma anloga as funes getuid e a a co getgid retornam o ID real de usurio e o ID real de grupo. a Se o kernel cuida somente do ID efetivo de usurio, no parece haver a a muito razo em ter distino entre um ID real de usurio e um ID efetivo a ca a de usurio. Todavia, existe um caso muito importante no qual o ID real a de usurio importante. Se voc deseja mudar o ID efetivo de usurio de a e e a um processo j existente que est executando no presente momento, o kernel a a olha para o ID real de usurio bem como o ID efetivo de usurio. a a Antes de olhar para como voc pode mudar o ID efetivo de usurio de um e a processo, vamos examinar porque voc desejaria fazer a mudana do usurio e c a efetivo olhando de volta para nosso programa de contabilidade. Suponhamos que haja um processo servidor que pode precisar olhar em qualquer arquivo no sistema, indiferentemente do usurio que o criou. Ento o processo deve a a executar como root pelo fato de somente ao root pode ser garantido a capacidade de olhar em qualquer arquivo. Mas agora suponhamos que uma requisio venha de um usurio em particular (digamos, mitchell ) para acesca a sar algum arquivo. O processo servidor poder examinar cuidadosamente as a permisses associadas aos arquivos em questo e tentar decidir se ao mito a chell deve ser permitido acessar aqueles arquivos. Mas isso pode signicar 255

duplicar todo o processo que o kernel pode normalmente fazer para vericar permisses de acesso a arquivo. A implementao dessa lgica pode ser o ca o complexa, propensa a erros, e tediosa. Uma abordagem melhor simplesmente ceder temporariamente o ID efee tivo de usurio do processo de root para mitchell e ento tentar executar as a a operaes requeridas. Se mitchell no tem permisso para acessar os dados, co a a o kernel ir evitar que o processo faa isso e ir retornar a indicao apropria c a ca ada de erro. Aps todas as operaes realizadas em favor de mitchell estarem o co completas, o processo pode devolver o ID efetivo de usurio para o root. a Programas que autenticam usurios quando eles esto usando o coma a putador aproveitam da capacidade de mudar IDs de usurio tambm. Esses a e programas de login executam como root. Quando o usurio informa um nome a de usurio e uma senha, o programa de login verica o nome de usurio e a a a senha na base de dados de senha do sistema. Ento o programa de loa gin muda ambos o ID efetivo de usurio e o ID real de usurio para serem a a aquele do usurio. Finalmente, o programa de login chama a funo exec a ca para iniciar o shell do usurio, deixando o usurio executando um shell cujo a a ID efetivo de usurio e ID real de usurio so arqueles do usurio. a a a a A funo usada para mudar os IDs de usurio para um processo a ca a e setreuid. (Existe, certamente, uma funo correspondente setregid tambm.) ca e Essa funo recebe dois argumentos. O primeiro argumento o ID real de ca e usurio desejado; o segundo o ID efetivo de usurio desejado. Por exemplo, a e a segue adiante como voc pode trocar os IDs real e efetivo de usurio: e a setreuid (geteuid(), getuid ()); Obviamente, o kernel no ir apenas permitir que quaisquer processos a a mudem seus IDs de usurio. Se a um processo for permitido mudar seu ID a efetivo de usurio na hora que ele quiser e bem entender, ento qualquer a a usurio pode facilmente ngir ser qualquer outro usurio, simplesmente mua a dando o ID efetivo de usurio de um de seus processos. O kernel ir permitir a a que um processo executando com um ID efetivo de usurio de valor 0 mude a seus IDs de usurio como lhe aprouver. (Novamente, note quanto poder um a processo executando como root tem! Um processo cujo ID efetivo de usurio a 0 pode fazer absolutamente qualquer coisa que lhe agradar.) Um processo e comum, todavia, pode fazer somente uma das seguintes coisas12 : Ajustar seu ID efetivo de usurio para ser o mesmo que seu ID real de a usurio a
12

Nota do tradutor: considerando o ID real/efetivo de usurio/grupo a

256

Ajustar seu ID real de usurio para ser o mesmo que seu ID efetivo de a usurio a Trocar os dois IDs de usurio a A primeira alternativa pode ser usada pelo nosso processo de contabilidade quando ele tiver terminado de acessar arquivos como mitchell e desejar voltar a ser root. A segunda alternativa pode ser usada por um programa de login aps esse mesmo programa ter ajustado o ID efetivo de usurio para o a aquele do usurio se conectou agora. Ajustando o ID real de usurio garante a a que o usurio nunca ir estar apto a voltar a ser root. Trocar os dois IDs de a a usurio quase um artefato histrico; programas modernos raramente usam a e o essa funcionalidade. Voc pode informar -1 em qualquer argumento a setreuid se voc dee e seja permitir o ID de usurio somente. Existe tambm uma funo de cona e ca venincia chamada seteuid. Essa funo ajusta o ID efetivo de usurio, mas e ca a seteuid no modica o ID real de usurio. As seguintes duas declaraes a a co fazem exatamente a mesma coisa: seteuid (id); setreuid (-1, id);

10.4.1

Programas Setuid

Usando as tcnicas anteriores, voc sabe como fazer um processo com prie e vilgio de superusurio tornar-se outro usurio temporariamente e ento vole a a a tar a ser root. Voc tambm sabe como fazer um processo root levar consigo e e todos os seus privilgios especiais ajustando ambos seu ID real de usurio e e a seu ID efetivo de usurio. a Aqui est uma charada: Pode voc, executando um programa como a e usurio comum, tornar-se root? Isso no parece poss a a vel, usando as tcnicas e anteriores, mas segue uma prova que isso pode ser feito: % whoami mitchell % su Password: ... % whoami root O comando whoami funciona como o comando id, exceto que mostra somente the ID efetivo de usurio, no todas as outras informaes. O comando a a co su habilita voc a tornar-se o superusurio se voc souber a senha de root. e a e 257

Como trabalha o su? Pelo fato de sabermos que o shell estava originalmente executando com ambos seu ID real de usurio e seu ID efetivo de a usurio ajustado para mitchell, setreuid no iria nos permitir mudar qualquer a a ID de usurio. a A complicao que o programa su um programa setuid. Isso signica ca e e que quando o programa executa, o ID efetivo de usurio do processo ir ser a a aquele do dono do arquivo em lugar daquele do ID efetivo de usurio do a processo que executou a chamada exec. (O ID real de usurio ir ainda ser a a aquele do usurio que chamou o programa.) Para criar um programa setuid, a voc usa o comando chmod +s na linha de comando, ou use o sinalizador e S ISUID se chamar a funo chmod programaticamente 13 . ca Por exemplo, considere o programa na Listagem 10.3. Listagem 10.3: (setuid-test.c) Programa de Demonstrao do Setuid ca
1 2 3 4 5 6 7 8 #include <s t d i o . h> #include <u n i s t d . h> i n t main ( ) { p r i n t f ( u i d=%d e u i d=%d\n , ( i n t ) return 0 ; }

getuid

( ) , ( int )

geteuid

() ) ;

Agora suponhamos que esse programa setuid e de propriedade do root. e Nesse caso, a sa do ls ir se parecer com isso: da a
-rwsrws--x 1 root root 11931 Jan 24 18:25 setuid-test

Os bits s indicam que o arquivo no somente executvel (como um bit x a e a pode indicar) mas tambm setuid e setgid. Quando usamos esse programa, e recebemos uma sa como segue: da % whoami mitchell % ./setuid-test uid=501 euid=0 Note que o ID efetivo de usurio ajustado para 0 quando o programa a e est executando. a Voc pode usar o comando chmod com os argumentos u+s ou g+s para e ajustar os bits setuid e setgid sobre um arquivo executvel, rspectivamente a por exemplo:
Certamente, existe uma noo similar de um programa setgid. Quando executa, seu ca ID efetivo de grupo o mesmo daquele do grupo proprietrio do arquivo. A maioria dos e a programas setuid so tambm programas setgid. a e
13

258

% ls -l program -rwxr-xr-x 1 samuel % chmod g+s program % ls -l program -rwxr-sr-x 1 samuel % chmod u+s program % ls -l program -rwsr-sr-x 1 samuel

csl

0 Jan 30 23:38 program

csl

0 Jan 30 23:38 program

csl

0 Jan 30 23:38 program

Voc tambm pode tambm usar a chamada de sistema chmod com os e e e sinalizadores de modo S ISUID ou S ISGID. O comando su tem capacidade de mudar o ID efetivo de usurio atravs a e desse mecanismo. O comando su executa inicialmente com um ID efetivo de usurio de 0. Ento o comando su pergunta a voc por uma senha. Se a a e a senha coincidir com a senha de root, o comando su ajusta seu ID real de usurio para ser root tambm e ento inicia um novo shell. De outra forma, a e a o comando su sai, sem a menor cerimnia deixando voc como um usurio o e a comum. D uma olhada nas permisses do programa su: e o
% ls -l /bin/su -rwsr-xr-x 1 root root 14188 Mar 7 2000 /bin/su

Note que o programa su de propriedade do root e que o bit setuid est e a ativo. Note que su no muda agora o ID de usurio do shell a partir do qual a a ele foi executado. Ao invs disso, o comando su inicia um novo processo de e shell com o novo ID de usurio. O shell original bloqueado at que o novo a e e shell realize todas as suas tarefas e o su termine14 .

10.5

Autenticando Usurios a

Muitas vezes, se voc tem um programa com setuid ativado, voc no deseja e e a disponibiliz-lo para todo mundo. Por exemplo, o programa su permite a a voc tornar-se root somente se voc conhece a senha de root. O programa e e faz com que voc prove que voc est autorizado a tornar-se root antes de ir e e a adiante com suas aes. Esse processo chamado autenticao o programa co e ca su est vericando para comprovar que voc autntico. a ee e Se voc est administrando um sistema muito seguro, voc provavelmente e a e no deseja permitir `s pessoas conectar-se apenas digitando uma senha quala a quer. Usurios tendem a escrever senhas inseguras, e chapus pretos 15 tena e
Nota do tradutor: veja a relao de programas com setuid no debian 6.0.2 no Apndice ca e J Seguraa Seo J.1 Setuid no Debian 6.0.2. c ca 15 Nota do tradutor: os hackers se dividem em dois grupos - os black hats e os white hats. Em http://en.wikipedia.org/wiki/Hacker %28computer security%29 temos que os black
14

259

dem a descobr -las. Usurios tendem a usar senhas que envolvem seus ania versrios, os nomes de seus animaizinhos de estimao, e assim por diante16 . a ca Senhas simples no so nada seguras. a a Por exemplo, muitas organizaes agora requerem o uso de senha especial co de uma unica vezque so geradas por cartes de identicao eletrnicos a o ca o especiais que usurios mantm consigo. A mesma senha no pode ser usada a e a duas vezes, e voc no pode pegar uma senha vlida sem o carto de idene a a a 17 ticao eletrnico sem inserir uma PIN . De forma que, um atacante deve ca o obter ambos o carto f a sico e a PIN para romper a segurana. Em um amc biente realmente seguro, digitalizao de retina ou outros tipos de testes ca biomtricos so usados. e a Se voc est escrevendo um programa que obrigatoriamente executa aue a tenticao, voc deve permitir ao administrador do sistema usar qualquer ca e meio de autenticao que for apropriado para aquela instalao. GNU/Linux ca ca vem com uma biblioteca muito util que faz isso muito facilmente. Essa fa cilidade, chamada Pluggable Authentication Modules, ou PAM, torna muito fcil escrever aplicaes que autenticam seus usurios da mesma forma que a co a o administrador de sistema deseja. E muito fcil ver como PAM trabalha olhando para uma aplicao PAM a ca simples. A Listagem 10.4 ilustra o uso do PAM.

hats seriam os criminosos e os white hats seriam os experts em computadores. Existem muitas controvrsias sobre o signicado do termo hacker. No pesquisei a ligao com o e a ca nome da distribuio Red Hat. ca 16 Vericou-se que administradores de sistema tendem a selecionar a palavra deus como sua senha muitas vezes mais qualquer outra palavra. (Voc ir fazer isso tambm.) De e a e forma que, se voc mesmo precisar de acesso root a uma mquina e o administrador do e a sistema no est por perto, um pouco de inspirao divina pode ser apenas o que voc a a ca e precisa. 17 Nota do tradutor: Personal Identication Number. Veja https://www. pcisecuritystandards.org/security standards/glossary.php.

260

Listagem 10.4: ( pam.c) Exemplo de Uso do PAM


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include < s e c u r i t y / pam appl . h> #include < s e c u r i t y / pam misc . h> #include <s t d i o . h> i n t main ( ) { p a m h a n d l e t pamh ; s t r u c t pam conv pamc ; / S e t up t h e PAM c o n v e r s a t i o n . / pamc . conv = &m i s c c o n v ; pamc . a p p d a t a p t r = NULL ; / S t a r t a new a u t h e n t i c a t i o n s e s s i o n . / p a m s t a r t ( s u , g e t e n v ( USER ) , &pamc , &pamh ) ; / A u t h e n t i c a t e t h e u s e r . / i f ( p a m a u t h e n t i c a t e ( pamh , 0 ) != PAM SUCCESS) f p r i n t f ( s t d e r r , A u t h e n t i c a t i o n f a i l e d ! \ n ) ; else f p r i n t f ( s t d e r r , A u t h e n t i c a t i o n OK. \ n ) ; / A l l d o n e . / pam end ( pamh , 0 ) ; return 0 ; }

Para compilar esse programa, voce tem que link-lo com duas bibliotecas: a a biblioteca libpam e uma biblioteca auxiliar chamada libpam misc: % gcc -o pam pam.c -lpam -lpam_misc Esse programa inicia-se pela construo de um objeto de conversao ca ca PAM. Esse objeto usado pela biblioteca PAM caso seja necessrio perguntar e a alguma informao ao usurio. A funo misc conv usada nesse exemplo ca a ca e uma funo de conversao padro que usa o terminal para entrada e sa ca ca a da. Voc poder escrever sua prpria funo que faz surgir na tela uma caixa de e a o ca dilogo, ou que usa dilogo para entrada e sa a a da, ou que fornece ainda mais exticos mtodos de entrada e sa o e da. ca O programa ento chama pam start. Essa funo inicializa a biblioteca a PAM. O primeiro argumento um nome de servio. Voc deve usar um nome e c e que unicamente identique sua aplicao. Por exemplo, se sua aplicao ca ca se chama whizbang, voc provavelmente deve usar whizbang para o nome e do servio, tambm. Todavia, o programa provavelmente no ir trabalhar c e a a at que o administrador de sistema explicitamente congure o sistema para e trabalhar com seu servio. De forma que, nesse exemplo, usamos o servio c c su, o qual diz que nosso programa deve autenticar usurios da mesma forma a que o comando su faz. Voc no deve usar essa tcnica em um programa real. e a e Selecionar um nome de servio real, e ter seus scripts de instalao ajudam c ca ao administrador do sistema a ajustar uma congurao correta para sua ca aplicao. ca O segundo argumento o nome do usurio que voc deseja autenticar. e a e Nesse exemplo, usamos o valor da varivel de ambiente USER. (Normala mente, o valor dessa varivel o nome de usurio que corresponde ao ID a e a 261

efetivo de usurio do processo atual, mas isso no sempre o que ocorre.) Na a a e maioria dos programas reais, voc deve perguntar por um nome de usurio e a nesse momento. O terceiro argumento indica a conversao PAM, discuca tida anteriormente. A chamada a pam start preenche o manipulador fornecido como o quarto argumento. Informe esse manipulador `s chamadas a subsequntes a rotinas da biblioteca PAM. e A seguir, o programa chama pam authenticate. O segundo argumento habilita voc a informar vrios sinalizadores; o valor 0 signica usar as opes e a co padronizadas. O valor de retorno dessa funo indica se a autenticao foi ca ca efetuada com sucesso. Finalmente, o programa chama pam end para limpar qualquer estruturas de dados alocadas. Vamos assumir que uma senha vlida para o usurio atual seja senha a a (uma senha excepcionalmente pobre). Ento, executando esse programa com a a senha correta produz o esperado: % ./pam Password: senha Authentication OK. Se voc executar esse programa em um terminal, a senha provavelmente e no ir aparecer na hora em que est sendo digitada; a senha escondida a a a e para evitar que leiam sua senha por cima do seu ombro quando voc a tiver e digitando. Todavia, se um hacker tenta usar a senha errada, a biblioteca PAM ir a corretamente indicar falha: % ./pam Password: palpiteerrado Authentication failed! O bsico abrangido aqui suciente para a maioria dos programas sima e ples. Documentao completa sobre como PAM trabalha est dispon em ca a vel /usr/doc/pam na maioria dos sistemas GNU/Linux.

10.6

Mais Falhas de Segurana c

Embora esse cap tulo venha a apontar umas poucas falhas de segurana coc muns, voc no deve de modo algum conar que esse livro abrange todas e a 262

as poss veis falhas de segurana. Uma grande quantidade de falhas de seguc rana j foram descobertas, e muitas outras esto por a afora esperando para c a a serem descobertas. Se voc est tentando escrever cdigo seguro, no existe e a o a seguramente substituto para se ter um especialista em segurana auditando c seu cdigo. o

10.6.1

Sobrecarga no Espao Temporrio de Armazec a nagem

A maioria entre todos os principais programas da Internet que rodam em segundo plano, incluindo o sendmail, o nger, o talk, e outros, possuem algum ponto que foi comprometido atravs de um buer overrun 18 . e Se voc est escrevendo qualquer cdigo que ir alguma vez ser executado e a o a como root, voc absolutamente deve estar atento para esse tipo particular de e falha de segurana. Se voc est escrevendo um programa que executa qualc e a quer tipo de comunicao entre processos, voc deve denitivamente estar ca e atento para esse tipo de falha de segurana. Se voc est escrevendo um c e a programa que l arquivos (ou possivelmente pode vir a ler arquivos) que no e a so de propriedade do usurio que est executando o programa, voc deve a a a e estar atento a esse tipo de falha de segurana. Esse ultimo critrio aplica-se c e a ` maioria de todos os programas. Fundamentalmente, se voc pretendo ese crever programas para GNU/Linux, voc deveria conhecer a falha provocada e pela sobrecarga no espao de armazenagem. c A idia por trs de um ataque de sobrecarga no espao temporrio de e a c a armazenagem induzir um programa a executar algum cdigo que ele no e o a tem a inteno de executar. O mecanismo usual para ter xito nessa proeza ca e sobrescrever alguma poro da pilha do processo do programa. A pilha do e ca processo do programa contm, entre outras coisas, a localizao da memria e ca o na qual o programa ir transferir o controle quando a funo atual retornar. a ca Todavia, se voc puder colocar o cdigo que voc deseja que seja executado e o e dentro da memria em algum lugar e ento mudar o endereo de retorno o a c apontando para aquela pea de memria, voc pode fazer com que o programa c o e que est rodando execute qualquer coisa que voc quiser. Quando o programa a e retornar da funo que est executando, ele ir pular para o novo cdigo ca a a o e executar qualquer coisa que estiver l, executando com os privilgios do a e processo atual. Claramente, se o processo atual estiver executando como root, isso pode ser um desastre. Se o processo estiver rodando como outro usurio, isso ser um desastre somente para aquele usurio e algum mais a a a e que depende do contedo dos arquivos de propriedade daquele usurio, e u a
18

Nota do tradutor: Sobrecarga no Espao Temporrio de Armazenagem. c a

263

assim por diante. Se o programa est executando em segundo plano e esperando por coa neces de rede externas, a situao pior. Um programa em segundo plano co ca e tipicamente executa como root. Se esse programa que est rodando em sea gundo plano como root contiver falhas de sobrecarga do espao de armazec nagem, algum que pode se conectar pela rede a um computador executando e o programa em segundo plano tem a possibilidade de tomar o controle do computador enviando uma sequncia maligna de dados para programa em e segundo plano pela rede. Um programa que no se envolve em comunicaes a co em rede mais seguro pelo fato de somente usurios que j esto habilitae a a a dos a se conectar ao computador executando o programa estarem aptos a atac-lo. a As verses com falha do nger, do talk, e do sendmail todas compartio lham uma falha comum. Cada um deles usa um espao de armazenagem de c sequncias de caractere de comprimento xo, o que implica um constante e limite superior sobre o tamanho da sequncia de caracteres mas ento pere a mitido a clientes de rede fornecer sequncias de caracteres que sobrecarrem e o espao temporrio de armazenamento. Por exemplo, eles possuem cdigo c a o similar ao que segue:
#i n c l u d e <s t d i o . h> i n t main ( ) { / Nobody i n t h e i r r i g h t mind w o u l d h a v e more t h a n 32 c h a r a c t e r s t h e i r u s e r n a m e . P l u s , I t h i n k UNIX a l l o w s o n l y 8 c h a r a c t e r u s e r n a m e s . So , t h i s s h o u l d b e p l e n t y o f s p a c e . / char username [ 3 2 ] ; / Prompt t h e u s e r f o r t h e u s e r n a m e . / p r i n t f ( E n t e r y o u r username : ) ; / Read a l i n e o f i n p u t . / g e t s ( username ) ; / Do o t h e r t h i n g s h e r e . . . / return 0 ; }

in

A combinao do espao temporrio de armazenamento de 32 caracteres ca c a com a funo gets permite uma sobrecarga no espao temporrio de armaca c a zenamento. A funo gets l entradas de usurio at encontrar um caractere ca e a e de nova linha e armazena o resultado inteiro no espao temporrio de armac a zenamento chamado username. Os comentrios nesse cdigo esto corretos a o a em que pessoas geralmente possuem nomes de usurio curtos, ento nenhum a a usurio bem intencionado tem probabilidade de digitar mais que 32 caraca teres. Mas quando voc estiver escrevendo programas seguros, voc deve e e considerar o que um atacante malicioso pode fazer. Nesse caso, o atacante pode deliberadamente digitar um nome de usurio muito longo. Variveis a a locais tais como username esto armazenadas na pilha, de forma que exa trapolando as fronteiras do array, poss colocar bytes arbitrrios dentro e vel a da pilha alm da rea reservada para a varivel username. A username ir e a a a 264

sobrecarregar o espao temporrio de armazenamento e sobrescrever partes c a da pilha vizinha, permitindo o tipo de ataque descrito previamente. Afortunadamente, relativamente fcil evitar sobrecargas do espao teme a c porrio de armazenagem. Ao ler sequncias de caracteres, voc deve sempre a e e usar uma funo, tal como a getline, que ou aloca dinamicamente um espao ca c temporrio de armazenamento suciente grande ou para a leitura da entrada a se o espao temporrio estiver cheio. Por exemplo, voc pode vir a usar c a e 19 isso :
char *username = NULL; size_t username_length = 0; ssize_t characters_read = getline (&username, &username_length, stdin);

Essa chamada automaticamente usa malloc para alocar um espao temc porrio de armazenagem sucientemente grande para manter a linha e rea torn-la para voc. Voc deve se lembrar de chamar free para desalocar o a e e espao temporrio de armazenagem, com certeza, para evitar desperd de c a cio memria. o Sua vida ir ser ainda mais fcil se voc usar C++ ou outra linguagem que a a e fornea primitivas simples para leitura de entradas. Em C++, por exemplo, c voc pode simplesmente usar isso: e string username; getline (cin, username); A sequncia de caracteres contida na varivel username ir ser automae a a ticamente desalocada tambm; voc no tem que lembrar-se de liberar a e e a memria usada para armazenar a varivel pois isso feito automaticamente o a e 20 em C++ . Certamente, sobrecargas do espao temporrio de armazenagem podem c a ocorrer com qualquer array de tamanho denido estaticamente, no apenas a com sequncias de caractere. Se voc deseja escrever cdigo seguro, voc e e o e nunca deve escrever dentro de uma estrutura de dados, dentro da pilha ou em algum outro lugar, sem vericar se voc no est indo escrever alm de e a a e sua regio de memria. a o
Se a chamada falhar, characters read ir ser -1. De outra forma, username ir a a apontar para um espao temporrio de armazenamento alocado com malloc medindo c a username length caracteres. 20 Alguns programadores acreditam que C++ uma linguagem horr e vel e excessivamente complexa. Seus argumentos sobre multiplas heranas e outras tais complicaes c co possuem alguns mritos, mas em C++ mais fcil escrever cdigo que evita sobrecargas e e a o do espao temporrio de armazenagem e outros problemas similares em C++ que em C. c a
19

265

10.6.2

Condioes de Corrida no /tmp c

Outro problema muito comum envolve a criao de arquivos com nomes ca previs veis, tipicamente no diretrio /tmp. Suponhamos que seu programa o prog, executando como root, sempre cria um arquivo temporrio chamado a /tmp/prog e escreve alguma informao vital nele. Um usurio malicioso ca a pode criar um link simblico de /tmp/prog para qualquer outro arquivo no o sistema. Quando seu programa vai criar o arquivo, a chamada de sistema open ir ter sucesso. Todavia, os dados que voc escreve no iro para a e a a /tmp/prog; ao invs disso, esses dados escritos iro ser escritos em algum e a arquivo arbitrrio da escolha do atacante. a Esse tipo de ataque chamado explorar uma condio de corrida. Existe e ca implicitamente uma corrida entre voc e o atacante. Quer quer que consiga e criar o arquivo primeiro vence. Esse ataque muitas vezes usado para destruir partes importantes do sise tema de arquivos. Atravs da criao de links apropriados, o atacante pode e ca enganar um programa executando como root que supostamente escreve um arquivo temporrio de forma que esse programa escreva sobre um importante a arquivo do sistema. Por exemplo, fazendo um link simblico para /etc/paso swd, o atacante pode varrer a base de dados de senhas do sistema. Existe tambm formas atravs das quais um usurio malicioso pode obter acesso de e e a root usando essa tcnica. e Uma tentativa de evitar esses ataques usar um nome aleatorizado para e o arquivo. Por exemplo, voc pode ler em /dev/random alguns bits para usar e no nome do arquivo temporrio. Isso certamente torna as coisas mais dif a ceis para um usurio malicioso deduzir o nome do arquivo temporrio, mas no a a a torna o ataque imposs vel. O atacante pode apenas criar um grande nmero u de links simblicos, usando muitos nomes em potencial. Mesmo se ele tiver o que tentar 10.000 vezes antes de vencer a condio de corrida, mesmo que ca uma unica vez pode ser desastroso. Uma outra abordagem usar o sinalizador O EXCL ao chamar a open. e Esse sinalizador faz com que a open falhe se o arquivo j existir. Desafortua nadamente, se voc est usando o Network File System (NFS), ou se algum e a e que est usando seu programa puder possivelmente vir a usar o NFS, a abora dagem de sinalizador no robusta o suciente pelo fato de O EXCL no a e a ser convel quando NFS estiver em uso. Voc no pode mesmo realmente a e a saber com certeza se seu cdigo ir ser usado sobre um sistema que use NFS, o a de forma que se voc for altamente paranico, no deve de modo algum usar e o a O EXCL. No Cap tulo 2, Escrevendo Bom Software GNU/Linux Seo 2.1.7, ca Usando Arquivos Temporrios mostramos como usar mkstemp para criar a 266

arquivos temporrios. Desafortunadamente, o que mkstemp faz em GNU/Linux a abrir o arquivo com O EXCL aps tentar selecionar um nome que dif e o e cil de prever. Em outras palavras, o uso do mkstemp ainda inseguro se o /tmp e for montado sobre o NFS21 . De forma que, o uso do mkstemp melhor que e nada, mas no completamente seguro. a e

Uma abordagem que funciona chamar lstat sobre o arquivo recentemente e criado (lstat discutida na Seo B.2, stat). A funo lstat como a funo ca ca e ca stat, exceto que se o arquivo referenciado for um link simblico, lstat informa o a voc sobre o link, no sobre o arquivo para o qual ele aponta. Se lstat e a informa a voc que seu novo arquivo um arquivo comum, no um link e e a simblico, e que esse novo arquivo de sua propriedade, ento deve estar o e a tudo bem.

A Listagem 10.5 mostra uma funo tenta seguramente abrir um arquivo ca no /tmp. Os autores desse livro no tiveram o cdigo fonte da funo adiante a o ca auditado prossionalmente, nem so prossionais de segurana, de forma a c que existe uma boa chance que esse cdigo tenha uma fraqueza, tambm. o e No recomendamos que voc use esse cdigo sem que ele seja examinado a e o em alguma auditoria, mas esse cdigo deve ao menos convencer voc de o e que escrever um cdigo seguro complicado. Para ajudar voc a mudar de o e e opinio, zemos deliberadamente a interface dif para usar em programas a cil reais. A vericao de erro uma parte importante da escrita de programas ca e seguros, de forma que inclu mos lgica de vericao de erros nesse exemplo. o ca

Obviamente, se voc for tambm o administrador de sistema, voc no deve montar e e e a o /tmp sobre o NFS.

21

267

Listagem 10.5: (temp-le.c) Cria um Arquivo Temporrio a


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 #include #include #include #include #include < f c n t l . h> <s t d i o . h> < s t d l i b . h> <s y s / s t a t . h> <u n i s t d . h>

/ R e t u r n s t h e f i l e d e s c r i p t o r f o r a n e w l y c r e a t e d t e m p o r a r y f i l e . The t e m p o r a r y f i l e w i l l b e r e a d a b l e and w r i t a b l e b y t h e e f f e c t i v e u s e r ID o f t h e c u r r e n t p r o c e s s b u t w i l l n o t b e r e a d a b l e o r w r i t a b l e by anybody e l s e . R e t u r n s 1 i f the temporary file could not be created . /

int s e c u r e t e m p f i l e ( ) { / T h i s f i l e d e s c r i p t o r p o i n t s t o / d e v / random and a l l o w s u s t o g e t a g o o d s o u r c e o f random b i t s . / s t a t i c i n t r a n d o m f d = 1; / A random i n t e g e r . / unsigned i n t random ; / A b u f f e r , u s e d t o c o n v e r t f r o m a n u m e r i c t o a s t r i n g r e p r e s e n t a t i o n o f random . T h i s b u f f e r h a s f i x e d s i z e , meaning t h a t we p o t e n t i a l l y h a v e a b u f f e r o v e r r u n b u g i f t h e i n t e g e r s on t h i s machine have a l o t o f b i t s . / char f i l e n a m e [ 1 2 8 ] ; / The f i l e d e s c r i p t o r f o r t h e new t e m p o r a r y f i l e . / int fd ; / I n f o r m a t i o n a b o u t t h e n e w l y c r e a t e d f i l e . / struct s t a t s t a t b u f ; I f we h a v e n t o p e n e d / d e v / random , do s o now . ( This i s not threadsafe .) / i f ( r a n d o m f d == 1) { / Open / d e v / random . N o t e t h a t we r e a s s u m i n g t h a t / d e v / random r e a l l y i s a s o u r c e o f random b i t s , n o t a f i l e f u l l o f z e r o s p l a c e d t h e r e b y an a t t a c k e r . / r a n d o m f d = open ( / dev / random , O RDONLY) ; / I f we c o u l d n t o p e n / d e v / random , g i v e up . / i f ( r a n d o m f d == 1) return 1; } / Read an i n t e g e r f r o m / d e v / random . / i f ( r e a d ( random fd , &random , s i z e o f ( random ) ) != s i z e o f ( random ) ) return 1; / C r e a t e a f i l e n a m e o u t o f t h e random number . / s p r i n t f ( f i l e n a m e , /tmp/%u , random ) ; / Try t o o p e n t h e f i l e . / f d = open ( f i l e n a m e , / Use O EXECL , e v e n t h o u g h i t d o e s n t w o r k u n d e r NFS . / O RDWR | O CREAT | O EXCL , / Make s u r e n o b o d y e l s e can r e a d o r w r i t e t h e f i l e . / S IRUSR | S IWUSR ) ; i f ( f d == 1) return 1; / C a l l l s t a t on t h e f i l e , t o make s u r e t h a t i t i s n o t a s y m b o l i c link . / i f ( l s t a t ( f i l e n a m e , &s t a t b u f ) == 1) return 1; / I f t h e f i l e i s n o t a r e g u l a r f i l e , someone h a s t r i e d t o t r i c k us . / i f ( ! S ISREG ( s t a t b u f . s t m o d e ) ) return 1; / I f we don t own t h e f i l e , someone e l s e m i g h t r e m o v e i t , r e a d i t , o r c h a n g e i t w h i l e we r e l o o k i n g a t i t . / i f ( s t a t b u f . s t u i d != g e t e u i d ( ) | | s t a t b u f . s t g i d != g e t e g i d ( ) ) return 1; / I f t h e r e a r e any more p e r m i s s i o n b i t s s e t on t h e f i l e , something s f i s h y . / i f ( ( s t a t b u f . s t m o d e & ( S IRUSR | S IWUSR ) ) != 0 ) return 1; return f d ; } /

Essa funo chama open para criar o arquivo e ento chama lstat umas ca a 268

poucas linhas depois para garantir que o arquivo no um link simblico. a e o Se voc est pensando cuidadosamente, voc ir perceber que existe o que e a e a parece ser uma condio de corrida nesse ponto. Em particular, um atacante ca pode remover o arquivo e substitu com um link simblico no intervalo -lo o de tempo entre a chamada a open e a chamada a lstat. Isso no ir nos a a causar dano diretamente pelo fato de j termos um descritor de arquivo a aberto para o arquivo criado recentemente, mas isso ir nos causar indicar a um erro ao nosso chamador. Esse ataque no traria nenhum preju direto, a zo mas o aproveitamento dessa condio de corrida tornar imposs para o ca a vel nosso programa ver seu trabalho realizado. Tal ataque chamado ataque de e negao de servio denial-of-service (DoS ). ca c Afortunadamente, o sticky bit vem para o salvamento. Pelo fato de o sticky bit estar ativado no /tmp, ningum mais pode remover arquivos dae quele diretrio. Certamente, root pode ainda remover arquivos do /tmp, mas o se o atacante tiver privilgios de root, no existe nada que voc possa fazer e a e para proteger seu programa. Se voc escolhe assumir uma administrao de sistema competente, ento e ca a o /tmp no ir ser montado via NFS. E se o administrador do sistema for a a tolo o suciente para montar o /tmp sob NFS, ento existe uma boa chance a que o sticky bit no esteja ajustado. Ento, para a maioria dos propsitos a a o prticos, pensamos que seguro usar mkstemp. Mas voc deve ser infora e e mado desses recursos, e voc no deve denitivamente conar em O EXCL e a trabalhar corretamente se o diretrio em uso no seja o /tmp nem voc deve o a e conar que o sticky bit esteja ativado em algum outro lugar.

10.6.3

Usando system ou popen

A terceira mais comum falha de segurana que todo programador deve ter em c mente envolve a utilizao do shell para executar outros programas. Como ca um exemplo de brinquedo, vamos considerar um servidor dicionrio. Esse a programa projetado para aceitar coneces via Internet . Cada cliente e co envia uma palavra, e o servidor diz a cada cliente se a referida palavra uma e palavra vlida do Ingls. Pelo fato de todo sistema GNU/Linux vir com um a e lista de mais de 45.000 palavras do Ingls em /usr/dict/words, uma forma e fcil de construir esse servidor chamar o programa grep, como segue: a e % grep -x word /usr/dict/words Aqui, word a palavras que o usurio tem curiosidade de conhecer. e a O cdigo de sa do grep ir dizer a voc se aquela word aparece em o da a e 269

/usr/dict/words 22 . A Listagem 10.6 mostra como voc pode tentar codicar a parte do sere vidor que chama o grep: Listagem 10.6: ( grep-dictionary.c) Busca por uma Palavra no Dicionrio a
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <s t d i o . h> #include < s t d l i b . h> / R e t u r n s a nonz e r o v a l u e / usr / d i c t / words . / int grep for word { s i z e t length ; char b u f f e r ; int e x i t c o d e ; if and o n l y if t h e WORD a p p e a r s in

( const char word )

/ B u i l d up t h e s t r i n g g r e p x WORD / u s r / d i c t / w o r d s . Allocate the s t r i n g dynamically to avoid b u f f e r overruns . / length = s t r l e n ( g r e p x ) + s t r l e n ( word ) + s t r l e n ( / u s r / d i c t / words ) + 1 ; b u f f e r = ( char ) m a l l o c ( l e n g t h ) ; s p r i n t f ( b u f f e r , g r e p x %s / u s r / d i c t / words , word ) ; / Run t h e command . / e x i t c o d e = system ( b u f f e r ) ; / F r e e t h e b u f f e r . / free ( buffer ) ; / I f g r e p r e t u r n e d z e r o , t h e n dictionary . / return e x i t c o d e == 0 ; }

t h e word was p r e s e n t

in

the

Note que para realizar o clculo do nmero de caracteres precisamos e a u ento fazemos a alocao dinmica da rea temporria de armazenagem, a ca a a a garatindo o no aparecimento de sobrecargas do espao temporrio de armaa c a zenagem. Desafortunadamente, o uso da funo system (descrita no Cap ca tulo 3, Processos Seo 3.2.1, Usando system) insegura. Essa funo chama ca e ca o shell padro do sistema para executar o comando e ento retorna o valor a a de sa da. Mas o que ocorre se um hacker malicioso envia uma word que est atualmente seguida pela seguinte linha ou uma sequncia de caracteres a e similar? foo /dev/null; rm -rf / Nesse caso, o servidor ir executar o comando adiante: a grep -x foo /dev/null; rm -rf / /usr/dict/words Agora o problema bvio. O usurio transformou um comando, osteneo a sivamente a chamada a grep, em dois comandos pelo fato de o shell tratar
Se voc no sabe nada sobre grep, voc deve olhar nas pginas de manual. O grep e a e a e um programa incrivelmente util.
22

270

um ponto e v rgula como um separador de comandos. O primeiro comando ainda uma inocente invocao do grep, mas o segundo comando remove e ca todos os arquivo do sistema! Mesmo se o sistema no estiver rodando como a root, todos os arquivos que podem ser removidos pelo usurio executando o a servidor iro ser removidos. O mesmo problema pode aparecer com popen a (descrito na Seo 5.4.4, As Funes popen e pclose), as quais criam um ca co pipe entre o processo pai e o processo lho mas ainda usam o shell para executar o comando. Existem duas forma para evitar esses problemas. Uma usar a fam de e lia funes exec ao invs de system ou de popen. Essa soluo evita o problema co e ca pelo fato de caracteres que o shell trata especialmente (tais como o ponto e v rgula no comando anterior) no so tratados especialmente quando aparea a cerem na lista de argumentos para uma chamada a exec. Certamente, voc e desiste da comodidade de system e de popen. A outra alternativa validar a sequncia de caracteres para garantir que e e benigna. No exemplo do servidor de dicionrio, voc pode garantir que a e a e palavra fornecida contenha somente caracteres alfabticos, usando a funo e ca isalpha. Se a palavra fornecida no contiver qualquer outro caractere, no a a existe forma de enganar o shell de forma que ele execute um segundo comando. No implemente a vericao olhando para os caracteres perigosos e a ca inesperados; a vericao sempre mais segura explicitando a vericao dos ca e ca caracteres que voc sabe serem seguros em lugar de tentar antecipar todos e os caracteres que podem causar complicaes. co

271

272

Cap tulo 11 Um Modelo de Aplicao ca GNU/Linux


ESSE CAP ITULO E ONDE TUDO SE JUNTA. IREMOS DESCREVER e implementar um programa GNU/Linux completo que incorpora muitas das tcnicas descritas ness livro. O programa fornece informao sobre o sistema e ca no qual est instalado por meio de uma interface Web. a O programa uma demonstrao completa de alguns dos mtodos que e ca e descrevemos para programao em GNU/Linux e ilustra em programas curca tos. Esse programa escrito mais como cdigo realista, diferentemente e o da maioria das listagens de cdigo que mostramos nos cap o tulos anteriores. O cdigo mostrado aqui pode servir como um ponto de partida para seus o prprios programas GNU/Linux. o

11.1

Viso Geral a

O programa exemplo parte de um sistema para monitorar um sistema e GNU/Linux que est sendo executado. O programa de monitoramento inclui a os recursos adiante: O programa incorpora um servidor Web m nimo. Clientes locais ou remotos acessam informao do sistema por meio de requisies de ca co pginas Web ao servidor usando o protocolo HTTP. a O programa no disponibiliza pginas HTML estticas. Ao invs disso, a a a e as pginas so geradas em tempo real por mdulos, cada um dos quais a a o fornece uma pgina sumarizando um aspcto do estado do sistema. a e 273

Modulos no so linkados estaticamente dentro do executvel do sera a a vidor. Ao invs disso, eles so carregados dinmicamente a partir de e a a bibliotecas compartilhadas. Mdulos podem ser adicionados, removio dos, ou substitu dos enquanto o servidor est executando. a O servidor atende cada coneco em um processo lho. Essa forma de ca atendimento habilita o servidor a mante-se respondendo mesmo quando requisies individuais demorarem um momento para completarem-se, co e tambm protege o servidor de falhas nos mdulos. e o O servidor no precisa de privilgios de superusurio para executar a e a (bem como no executa em uma porta privilegiada). Todavia, isso a limita a informao de sistema que o servidor pode coletar. ca Fornecemos quatro mdulos amostra que demonstram como mdulos poo o dem ser escritos. Eles adicionalmente ilustram algumas das tcnicas para reue nir informaes do sistema mostradas anteriormente nesse livro. O mdulo co o time demonstra o uso da chamada de sistema gettimeofday. O mdulo issue o demonstra entrada e sa de baixo n e a chamada de sistema sendle. O da vel mdulo diskfree demonstra o uso de fork, exec, e dup2 por meio da execuo o ca de um comando em um processo lho. O mdulo processes demonstra o uso o do sistema de arquivo /proc e vrias chamadas de sistema. a

11.1.1

Ressalvas

Esse programa tem muitos dos recursos que voc iria esperar de um programa e de aplicao, tais como recepo de informaes pela linha de comando e traca ca co tamento de erros. Ao mesmo tempo, zemos algumas simplicaes para meco lhorar a legibilidade e focar em tpicos espec o cos do GNU/Linux discutidos nesse livro. Tenha em mente essas ressalvas ao examinar o cdigo. o No tentamos fornecer uma completa implementao do HTTP. Ao a ca invs disso, implementamos apenas o suciente para o servidor interagir e com clientes Web. Um programa realista ou poderia fornecer uma implemantao HTTP mais completa ou poderia interagir com uma ca das vrias excelentes implementaes de servidor Web 1 dispon a co veis ao invs de fornecer servios HTTP diretamente. e c
O mais popular e de cdigo aberto servidor Web para GNU/Linux o servidor Apache, o e dispon em http://www.apache.org. vel
1

274

Similarmente, no objetivamos alcanar compatibilidade completa com a c as especicaes HTML (veja http://www.w3.org/MarkUp/). Geraco mos uma sa simples em HTML que pode ser manuseada pelos nada vegadores populares.

O servidor no est ajustado para alta performace ou uso m a a nimo de recursos. Em particular, intencionalmente omitimos alguns dos cdigos o de congurao de rede que voc poderia esperar em um servidor Web. ca e Esse tpico est fora do escopo desse livro. Veja um das muito exeo a celentes referncias sobre desenvolvimento de aplicaes em rede, tais e co como UNIX Network Programming,Volume 1: Networking APIs Sockets and XTI, de autoria de W. Richard Stevens (Prentice Hall, 1997), para mais informao. ca

No zemos tentativas para regular os recursos (nmero de processos, a u uso de memria, e assim por diante) consumidos pelo servidor ou seus o mdulos. Muitas implementaes de servidores Web multiprocessados o co de coneces de servio usam um reservatrio limitado de processos em co c o lugar de criar um novo processo lho para cada coneco. ca

O servidor chama a biblioteca compartilhada para um mdulo do servio dor cada vez que o servidor requisitado e ento imediatamente descare a rega o mdulo quando a requisio tiver sido completada. Uma impleo ca mentao mais eciente poderia provavelmente selecionar os mdulos ca o mais usados e mant-los na memria. e o 275

HTTP O Hypertext Transport Protocol (HTTP )a usado para comunicao entre e ca clientes Web e servidores Web. O cliente conecta-se ao servidor por meio do estabelecimento de uma coneco a uma bem conhecida porta (usualmente a ca porta 80 para servidor Web conectados ` Internet , mas qualquer porta pode a ser usada). Requisies HTTP e cabealhos HTTP so compostos de texto co c a puro. Uma vez conectado, o cliente envia uma requisio ao servidor. Uma ca requisio t ca pica GET /page HTTP/1.0. O mtodo GET indica que o clie e ente est requisitando que o servidor envie a ele cliente uma pgina Web. O a a segundo elemento o caminho para a referida pgina no servidor. O terceiro e a elemento o protocolo e a verso do protocolo. Linhas subsequntes possuem e a e campos de cabealho, formatados similarmente a cabealhos de email, os quais c c possuem informaes extras sobre o cliente. O cabealho termina com uma co c linha em branco. O servidor envia de volta uma resposta indicando o resultado do processamento da requisio. Uma resposta t ca pica HTTP/1.0 200 e OK. O primeiro elemento a verso do protocolo. Os seguintes dois elemene a tos indicam o resultado; nesse caso, resultado 200 indica que a requisio foi ca processada com sucesso. Linhas subsequntes posuem campos de cabealho, e c formatados similarmente a cabealhos de email. O cabealho termina com c c uma linha em branco. O servidor pode ento enviar dados arbitrrios para a a satisfazer a requisio. Tipicamente, o servidor responde a uma requisio ca ca de determinada pgina enviando de volta o cdigo HTML da pgina Web rea o a quisitada. Nesse caso, os cabealhos de resposta iro incluir Content-type: c a text/html, indicando que o resultado cdigo na linguagem HTML. O cdigo e o o HTML segue imediatamente aps o cabealho. Veja a especicao HTTP em o c ca http://www.w3.org/Protocols/ para mais informao. ca
a

Nota do tradutor: Protocolo de Transporte de Hipertexto

11.2

Implementao ca

Todos incluindo os programas menores escritos em C requerem organizao ca cuidadosa para preservar a modularidade e manutensibilidade do cdigo o fonte. O programa apresentado nesse cap tulo dividido em quatro arquivos e fonte principais. Cada arquivo fonte exporta funes ou variveis que podem ser acessaco a das por outras partes do programa. Por simplicidade, todas as funes e co as variveis exportadas so declaradas em um unico arquivo de capealho, a a c server.h (veja a Listagem 11.1), o qual est inclu em outros arquivos. a do Funes que so intencionalmente para uso dentro de uma unica unidade co a de compilao somente so declaradas como sendo do tipo static e no so ca a a a declaradas em server.h. 276

Listagem 11.1: (server.h) Declaraes de Funes e de Variveis co co a


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 #i f n d e f SERVER H #d e f i n e SERVER H #include <n e t i n e t / i n . h> #include <s y s / t y p e s . h> / S y m b o l s defined i n common . c . /

/ The name o f t h i s p r o g r a m . / extern const char program name ; / I f nonz e r o , p r i n t extern i n t v e r b o s e ; verbose messages . /

/ L i k e m a l l o c , e x c e p t a b o r t s t h e p r o g r a m extern void x m a l l o c ( s i z e t s i z e ) ;

if

allocation

fails .

/ L i k e r e a l l o c , e x c e p t a b o r t s t h e p r o g r a m i f a l l o c a t i o n extern void x r e a l l o c ( void p t r , s i z e t s i z e ) ; / L i k e s t r d u p , e x c e p t a b o r t s t h e p r o g r a m extern char x s t r d u p ( const char s ) ; if allocation

fails .

fails .

/ P r i n t an e r r o r m e s s a g e f o r a f a i l e d c a l l OPERATION, o f e r r n o , and end t h e p r o g r a m . / extern void s y s t e m e r r o r ( const char o p e r a t i o n ) ;

using

the

value

/ P r i n t an e r r o r m e s s a g e f o r f a i l u r e i n v o l v i n g CAUSE, i n c l u d i n g a d e s c r i p t i v e MESSAGE, and end t h e p r o g r a m . / extern void e r r o r ( const char c a u s e , const char m e s s a g e ) ; / R e t u r n t h e d i r e c t o r y c o n t a i n i n g t h e r u n n i n g p r o g r a m s e x e c u t a b l e . The r e t u r n v a l u e i s a memory b u f f e r w h i c h t h e c a l l e r must d e a l l o c a t e using free . T h i s f u n c t i o n c a l l s a b o r t on f a i l u r e . / extern char g e t s e l f e x e c u t a b l e d i r e c t o r y ( ) ;

/ S y m b o l s

defined

i n module . c

/ An i n s t a n c e o f a l o a d e d s e r v e r m o d u l e . / struct server module { / The s h a r e d l i b r a r y h a n d l e c o r r e s p o n d i n g t o t h e l o a d e d m o d u l e . / void h a n d l e ; / A name d e s c r i b i n g t h e m o d u l e . / const char name ; / The f u n c t i o n w h i c h g e n e r a t e s t h e HTML r e s u l t s f o r t h i s m o d u l e . / void ( g e n e r a t e f u n c t i o n ) ( i n t ) ; }; / The d i r e c t o r y f r o m w h i c h m o d u l e s a r e extern char m o d u l e d i r ; loaded . /

/ A t t e m p t t o l o a d a s e r v e r m o d u l e w i t h t h e name MODULE PATH . If a s e r v e r m o d u l e e x i s t s w i t h t h i s p a t h , l o a d s t h e m o d u l e and r e t u r n s a server module structure representing i t . O t h e r w i s e , r e t u r n s NULL . / extern s t r u c t s e r v e r m o d u l e m o d u l e o p e n ( const char m o d u l e p a t h ) ; / C l o s e a s e r v e r m o d u l e and d e a l l o c a t e t h e MODULE o b j e c t . extern void m o d u l e c l o s e ( s t r u c t s e r v e r m o d u l e module ) ; /

/ S y m b o l s

defined

in

server . c .

/ / Run t h e s e r v e r on LOCAL ADDRESS and PORT. extern void s e r v e r r u n ( s t r u c t i n a d d r l o c a l a d d r e s s ,

uint16 t

port ) ;

#e n d i f

/ SERVER H /

11.2.1

Funes Comuns co

O programa common.c (veja a Listagem 11.2) contm funes de utilidade e co geral que so usadas em todo o programa. a 277

Listagem 11.2: (common.c) Funes de Utilidade Geral co


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 #include #include #include #include #include <e r r n o . h> <s t d i o . h> < s t d l i b . h> < s t r i n g . h> <u n i s t d . h>

#include s e r v e r . h const char program name ; int verbose ; void x m a l l o c ( s i z e t s i z e ) { void p t r = m a l l o c ( s i z e ) ; / A b o r t i f t h e a l l o c a t i o n i f ( p t r == NULL) abort () ; else return p t r ; }

failed .

void x r e a l l o c ( void p t r , s i z e t s i z e ) { ptr = r e a l l o c ( ptr , s i z e ) ; / A b o r t i f t h e a l l o c a t i o n f a i l e d . / i f ( p t r == NULL) abort () ; else return p t r ; } char x s t r d u p ( const char s ) { char copy = s t r d u p ( s ) ; / A b o r t i f t h e a l l o c a t i o n f a i l e d . i f ( copy == NULL) abort () ; else return copy ; }

void s y s t e m e r r o r ( const char o p e r a t i o n ) { / G e n e r a t e an e r r o r m e s s a g e f o r e r r n o . error ( operation , s t r e r r o r ( errno ) ) ; }

void e r r o r ( const char c a u s e , const char m e s s a g e ) { / P r i n t an e r r o r m e s s a g e t o s t d e r r . / f p r i n t f ( s t d e r r , %s : e r r o r : (% s ) %s \n , program name , / End t h e p r o g r a m . / exit (1) ; } char g e t s e l f e x e c u t a b l e d i r e c t o r y { int r v a l ; char l i n k t a r g e t [ 1 0 2 4 ] ; char l a s t s l a s h ; size t result length ; char r e s u l t ; ()

cause ,

message ) ;

/ Read t h e t a r g e t o f t h e s y m b o l i c l i n k / p r o c / s e l f / e x e . / r v a l = r e a d l i n k ( / proc / s e l f / exe , l i n k t a r g e t , s i z e o f ( l i n k t a r g e t ) 1) ; i f ( r v a l == 1) / The c a l l t o r e a d l i n k f a i l e d , s o b a i l . / abort () ; else / NUL e r m i n a t e t h e t a r g e t . t / l i n k t a r g e t [ r v a l ] = \0 ; / We want t o t r i m t h e name o f t h e e x e c u t a b l e f i l e , t o o b t a i n t h e directory that contains i t . Find t h e r i g h t m o s t s l a s h . / last slash = strrchr ( link target , / ) ; i f ( l a s t s l a s h == NULL | | l a s t s l a s h == l i n k t a r g e t ) / S o m e t h i n g s t a n g e i s g o i n g on . / abort () ; / A l l o c a t e a b u f f e r t o h o l d t h e r e s u l t i n g p a t h . / result length = last slash link target ; r e s u l t = ( char ) x m a l l o c ( r e s u l t l e n g t h + 1 ) ;

278

Listagem 11.3: (common.c) Continuao ca


82 83 84 85 86 } / Copy t h e r e s u l t . / strncpy ( result , link tar get , r e s u l t [ r e s u l t l e n g t h ] = \0 ; return r e s u l t ; result length ) ;

Voc pode usar essas funes em outros programas tambm; o contedo e co e u desse arquivo pode ser inclu em uma biblioteca de cdigo comum que do o e compartilhada entre muitos projetos: xmalloc, xrealloc, e xstrdup so verses com vericao de erro das a o ca funes da biblioteca C GNU padro malloc, realloc, e strdup, resco a pectivamente. Ao contrrio das verses padronizadas que retornam a o um apontador nulo se a alocao falhar, essas funes imediatamente ca co abortam o programa quando a memria necessria for insuciente. Deo a teco antecipada de falhas de alocao de memria uma boa idia. ca ca o e e De outra forma, uma alocao que falhou introduz apontadores nulos ca em lugares inesperados dentro do programa. Pelo fato de falhas de alocao no serem fceis de reproduzir, depurar tais problemas pode ca a a ser dif cil. Falhas de alocao so de modo geral catastrcas, de forma ca a o que abortar o programa muitas vezes uma linha de ao aceitvel. e ca a a funo error para reportar um erro fatal que venha a ocorrer durante ca e a execuo do programa. A funo error imprime uma mensagem para ca ca stderr e termina o programa. Para erros causados por chamadas de sistema que falharam ou por chamadas a bibliotecas que falharam, system error gera parte da mensagem de erro a partir do contedo u da varivel errno (veja a Seo 2.2.3, Cdigos de Erro de Chamadas a ca o de Sistema no Cap tulo 2, Escrevendo Bom Software GNU/Linux). get self executable directory determina o diretrio contendo o arquivo o executvel que vai rodar no processo atual. O caminho do diretrio a o pode ser usado para localizar outros componentes do programa, os quais so instalados no mesmo lugar em tempo de execuo. Essa a ca funo trabalha examinando o link simblico /proc/self/exe no sistema ca o de arquivos /proc (veja Seo 7.2.1, /proc/self no Cap ca tulo 7, O Sistema de Arquivos /proc). Adicionalmente, common.c dene duas variveis globais uteis: a O valor de program name o nome do programa sendo executado, e como especicado em sua lista de argumentos (veja Seo 2.1.1, A ca 279

Lista de Argumentos no Cap tulo 2). Quando o programa chamado e a partir do shell, esse o caminho e nome do programa como o usurio e a informou.

A varivel verbose diferente de zero se o programa est rodando no a e a modo verbose. Nesse caso, vrias partes do programa mostram mensaa gens de progresso em stdout.

11.2.2

Chamando Mdulos de Servidor o

O programa module.c (veja a Listagem 11.4) fornece a implementao do ca servidor de mdulos carregados dinamicamente. Um servidor de mdulos o o carregados representado por uma instncia de struct server module, a qual e a denida em server.h. e 280

Listagem 11.4: (module.c) Carregando e Descarregando Mdulo de Servio dor


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 #include #include #include #include <d l f c n . h> < s t d l i b . h> <s t d i o . h> < s t r i n g . h>

#include s e r v e r . h char m o d u l e d i r ; s t r u c t s e r v e r m o d u l e m o d u l e o p e n ( const char module name ) { char m o d u l e p a t h ; void h a n d l e ; void ( m o d u l e g e n e r a t e ) ( i n t ) ; s t r u c t s e r v e r m o d u l e module ; / C o n s t r u c t t h e f u l l p a t h o f t h e m o d u l e s h a r e d l i b r a r y we l l t r y t o load . / module path = ( char ) x m a l l o c ( s t r l e n ( m o d u l e d i r ) + s t r l e n ( module name ) + 2 ) ; s p r i n t f ( m o d u l e p a t h , %s/%s , m o d u l e d i r , module name ) ; / A t t e m p t t o o p e n MODULE PATH a s a s h a r e d l i b r a r y . / h a n d l e = d l o p e n ( m o d u l e p a t h , RTLD NOW) ; f r e e ( module path ) ; i f ( h a n d l e == NULL) { / F a i l e d ; e i t h e r t h i s p a t h d o e s n t e x i s t , o r i t i s n t a s h a r e d library . / return NULL ; } / R e s o l v e t h e m o d u l e g e n e r a t e s y m b o l f r o m t h e s h a r e d l i b r a r y . / m o d u l e g e n e r a t e = ( void ( ) ( i n t ) ) dlsym ( h a n d l e , m o d u l e g e n e r a t e ) ; / Make s u r e t h e s y m b o l was f o u n d . / i f ( m o d u l e g e n e r a t e == NULL) { / The s y m b o l i s m i s s i n g . While t h i s i s a s h a r e d l i b r a r y , i t p r o b a b l y i s n t a s e r v e r module . C l o s e up and i n d i c a t e f a i l u r e . / d l c l o s e ( handle ) ; return NULL ; } / / A l l o c a t e and i n i t i a l i z e a s e r v e r m o d u l e o b j e c t . module = ( s t r u c t s e r v e r m o d u l e ) x m a l l o c ( s i z e o f ( s t r u c t s e r v e r m o d u l e ) ) ; module >h a n d l e = h a n d l e ; module >name = x s t r d u p ( module name ) ; module >g e n e r a t e f u n c t i o n = m o d u l e g e n e r a t e ; / R e t u r n i t , i n d i c a t i n g s u c c e s s . / return module ; } void m o d u l e c l o s e ( s t r u c t s e r v e r m o d u l e module ) { / C l o s e t h e s h a r e d l i b r a r y . / d l c l o s e ( module >h a n d l e ) ; / D e a l l o c a t e t h e m o d u l e name . / f r e e ( ( char ) module >name ) ; / D e a l l o c a t e t h e m o d u l e o b j e c t . / f r e e ( module ) ; }

Cada mdulo um arquivo de biblioteca compartilhada (veja Seo 2.3.2, o e ca Bibliotecas Compartilhadas no Cap tulo 2) e deve denir e exportar uma funo chamada module generate. Essa funo gera uma pgina Web HTML ca ca a e a escreve no descritor de arquivo do socket do cliente informado como seu argumento. O programa module.c contm duas funes: e co module open tenta carregar um mdulo de servidor com um nome foro necido. O nome geralmente terminda com a extenso .so pelo fato a 281

de mdulos de servidor serem implementados como bilbiotecas como partilhadas. A funo module open abre a biblioteca compartilhada ca com dlopen e resolve um s mbolo chamado module generate da biblioteca com dlsym (veja Seo 2.3.6, Carregamento e Descarregamento ca Dinmico no Cap a tulo 2). Se a biblioteca no puder ser aberta, ou a se module generate no for um nome exportado pela biblioteca, a chaa mada falha e module open retorna um apontador nulo. De outra forma, module open aloca e retorna um objeto mdulo. o

module close fecha a biblioteca compartilhada correspondente ao mdulo o de servidor e desaloca o objeto struct server module.

O programa module.c tambm dene uma varivel global module dir. e a Essa varivel contm o caminho do diretrio no qual module open tenta ena e o contrar bibliotecas compartilhadas correspondendo aos mdulos de servidor. o

11.2.3

O Servidor

O programa server.c (veja Listagem 11.5) a implementao do servidor e ca HTTP m nimo. 282

Listagem 11.5: (server.c) Implementao do Servidor ca


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 #include #include #include #include #include #include #include #include #include #include #include <a r p a / i n e t . h> < a s s e r t . h> <e r r n o . h> <n e t i n e t / i n . h> < s i g n a l . h> <s t d i o . h> < s t r i n g . h> <s y s / t y p e s . h> <s y s / s o c k e t . h> <s y s / w a i t . h> <u n i s t d . h>

#include s e r v e r . h / HTTP r e s p o n s e and h e a d e r for a successful request . /

s t a t i c char o k r e s p o n s e = HTTP/ 1 . 0 200 OK\n Contentt y p e : t e x t / html \n \n ; / HTTP r e s p o n s e , understand the h e a d e r , and b o d y request . / indicating that t h e we d i d n t

s t a t i c char b a d r e q u e s t r e s p o n s e = HTTP/ 1 . 0 400 Bad R e q u e s t \n Contentt y p e : t e x t / html \n \n <html>\n <body>\n <h1>Bad Request </h1>\n <p>T h i s s e r v e r d i d n o t u n d e r s t a n d y o u r r e q u e s t . </p>\n </body>\n </html>\n ; / HTTP r e s p o n s e , h e a d e r , and b o d y t e m p l a t e r e q u e s t e d d o c u m e n t was n o t f o u n d . / indicating that the

s t a t i c char n o t f o u n d r e s p o n s e t e m p l a t e = HTTP/ 1 . 0 404 Not Found\n Contentt y p e : t e x t / html \n \n <html>\n <body>\n <h1>Not Found</h1>\n <p>The r e q u e s t e d URL %s was n o t f o u n d on t h i s </body>\n </html>\n ; / HTTP r e s p o n s e , h e a d e r , and b o d y method was n o t u n d e r s t o o d . / template

s e r v e r . </p>\n

indicating

that

the

s t a t i c char b a d m e t h o d r e s p o n s e t e m p l a t e = HTTP/ 1 . 0 501 Method Not Implemented \n Contentt y p e : t e x t / html \n \n <html>\n <body>\n <h1>Method Not Implemented </h1>\n <p>The method %s i s n o t i m p l e m e n t e d by t h i s </body>\n </html>\n ; / H a n d l e r f o r SIGCHLD , terminated . / to c l e a n up child

s e r v e r . </p>\n

processes

that

have

s t a t i c void c l e a n u p c h i l d p r o c e s s { int s t a t u s ; w a i t (& s t a t u s ) ; }

( int signal number )

/ P r o c e s s an HTTP GET r e q u e s t f o r PAGE, and s e n d f i l e d e s c r i p t o r CONNECTION FD . / s t a t i c void h a n d l e g e t ( i n t c o n n e c t i o n f d , { s t r u c t s e r v e r m o d u l e module = NULL ;

the

results

to

the

const char page )

283

Listagem 11.6: (server.c) Continuao ca


79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 / Make s u r e t h e r e q u e s t e d p a g e b e g i n s w i t h a s l a s h and d o e s c o n t a i n any a d d i t i o n a l s l a s h e s we don t s u p p o r t any subdirectories . / i f ( page == / && s t r c h r ( page + 1 , / ) == NULL) { char m o d u l e f i l e n a m e [ 6 4 ] ; not

/ The p a g e name l o o k s OK. C o n s t r u c t t h e m o d u l e name b y a p p e n d i n g . s o t o t h e p a g e name . / s n p r i n t f ( module file name , sizeof ( module file name ) , %s . s o , page + 1 ) ; / Try t o o p e n t h e m o d u l e . / module = m o d u l e o p e n ( m o d u l e f i l e n a m e ) ; } if ( module == NULL) { / E i t h e r t h e r e q u e s t e d p a g e was m a l f o r m e d , o r we c o u l d n t o p e n a m o d u l e w i t h t h e i n d i c a t e d name . E i t h e r way , r e t u r n t h e HTTP r e s p o n s e 4 0 4 , Not Found . / char r e s p o n s e [ 1 0 2 4 ] ; / G e n e r a t e t h e r e s p o n s e m e s s a g e . / s n p r i n t f ( response , sizeof ( response ) , not found response template , / Send i t t o t h e c l i e n t . / write ( connection fd , response , s t r l e n ( response ) ) ; } else { / The r e q u e s t e d

page ) ;

m o d u l e was l o a d e d

successfully .

/ Send t h e HTTP r e s p o n s e i n d i c a t i n g s u c c e s s , and t h e HTTP h e a d e r f o r an HTML p a g e . / write ( connection fd , ok response , s t r l e n ( ok response ) ) ; / I n v o k e t h e module , w h i c h w i l l g e n e r a t e HTML o u t p u t and s e n d i t to the c l i e n t f i l e descriptor . / ( module >g e n e r a t e f u n c t i o n ) ( c o n n e c t i o n f d ) ; / We r e d o n e w i t h t h e m o d u l e . / m o d u l e c l o s e ( module ) ; } } / H a n d l e a client c o n n e c t i o n on t h e ( int file d e s c r i p t o r CONNECTION FD . /

s t a t i c void h a n d l e c o n n e c t i o n { char b u f f e r [ 2 5 6 ] ; s s i z e t bytes read ;

connection fd )

/ Read some d a t a f r o m t h e c l i e n t . / bytes read = read ( connection fd , buffer , i f ( bytes read > 0) { char method [ s i z e o f ( b u f f e r ) ] ; char u r l [ s i z e o f ( b u f f e r ) ] ; char p r o t o c o l [ s i z e o f ( b u f f e r ) ] ;

sizeof

( b u f f e r ) 1) ;

/ Some d a t a was r e a d s u c c e s s f u l l y . NUL e r m i n a t e t h e b u f f e r s o t we can u s e s t r i n g o p e r a t i o n s on i t . / b u f f e r [ b y t e s r e a d ] = \0 ; / The f i r s t l i n e t h e c l i e n t s e n d s i s t h e HTTP r e q u e s t , w h i c h i s c o m p o s e d o f a method , t h e r e q u e s t e d p a g e , and t h e p r o t o c o l version . / s s c a n f ( b u f f e r , %s %s %s , method , u r l , p r o t o c o l ) ; / The c l i e n t may s e n d v a r i o u s h e a d e r i n f o r m a t i o n f o l l o w i n g t h e request . For t h i s HTTP i m p l e m e n t a t i o n , we don t c a r e a b o u t i t . However , we n e e d t o r e a d any d a t a t h e c l i e n t t r i e s t o s e n d . Keep on r e a d i n g d a t a u n t i l we g e t t o t h e end o f t h e h e a d e r , w h i c h i s d e l i m i t e d by a b l a n k l i n e . HTTP s p e c i f i e s CR/LF a s t h e l i n e delimiter . / while ( s t r s t r ( b u f f e r , \ r \n\ r \n ) == NULL) bytes read = read ( connection fd , buffer , sizeof ( b u f f e r ) ) ; / Make s u r e t h e l a s t r e a d d i d n t f a i l . I f i t did , t h e r e s a p r o b l e m w i t h t h e c o n n e c t i o n , s o g i v e up . / i f ( b y t e s r e a d == 1) { close ( connection fd ) ; return ; } / Check t h e p r o t o c o l f i e l d . We u n d e r s t a n d HTTP v e r s i o n s 1 . 0 and 1.1. / i f ( s t r c m p ( p r o t o c o l , HTTP/ 1 . 0 ) && s t r c m p ( p r o t o c o l , HTTP/ 1 . 1 ) ) { / We don t u n d e r s t a n d t h i s p r o t o c o l . Report a bad r e s p o n s e . / write ( connection fd , bad request response ,

284

Listagem 11.7: (server.c) Continuao ca


158 sizeof ( bad request response ) ) ; 159 } 160 e l s e i f ( s t r c m p ( method , GET ) ) { 161 / T h i s s e r v e r o n l y i m p l e m e n t s t h e GET method . The c l i e n t 162 s p e c i f i e d some o t h e r method , s o r e p o r t t h e f a i l u r e . / 163 char r e s p o n s e [ 1 0 2 4 ] ; 164 165 s n p r i n t f ( response , sizeof ( response ) , 166 b a d m e t h o d r e s p o n s e t e m p l a t e , method ) ; 167 write ( connection fd , response , s t r l e n ( response ) ) ; 168 } 169 else 170 / A v a l i d r e q u e s t . Process i t . / 171 handle get ( connection fd , url ) ; 172 } 173 e l s e i f ( b y t e s r e a d == 0 ) 174 / The c l i e n t c l o s e d t h e c o n n e c t i o n b e f o r e s e n d i n g any d a t a . 175 N o t h i n g t o do . / 176 ; 177 else 178 / The c a l l t o r e a d f a i l e d . / 179 s y s t e m e r r o r ( read ) ; 180 } 181 182 183 void s e r v e r r u n ( s t r u c t i n a d d r l o c a l a d d r e s s , u i n t 1 6 t p o r t ) 184 { 185 struct s o c k a d d r i n s o c k e t a d d r e s s ; 186 int r v a l ; 187 struct s i g a c t i o n s i g c h l d a c t i o n ; 188 int s e r v e r s o c k e t ; 189 190 / I n s t a l l a h a n d l e r f o r SIGCHLD t h a t c l e a n s up c h i l d p r o c e s s e s t h a t 191 have terminated . / 192 memset (& s i g c h l d a c t i o n , 0 , s i z e o f ( s i g c h l d a c t i o n ) ) ; 193 s i g c h l d a c t i o n . s a h a n d l e r = &c l e a n u p c h i l d p r o c e s s ; 194 s i g a c t i o n (SIGCHLD , &s i g c h l d a c t i o n , NULL) ; 195 196 / C r e a t e a TCP s o c k e t . / 197 s e r v e r s o c k e t = s o c k e t ( PF INET , SOCK STREAM, 0 ) ; 198 i f ( s e r v e r s o c k e t == 1) 199 system error ( socket ) ; 200 / C o n s t r u c t a s o c k e t a d d r e s s s t r u c t u r e f o r t h e l o c a l a d d r e s s on 201 w h i c h we want t o l i s t e n f o r c o n n e c t i o n s . / 202 memset (& s o c k e t a d d r e s s , 0 , s i z e o f ( s o c k e t a d d r e s s ) ) ; 203 s o c k e t a d d r e s s . s i n f a m i l y = AF INET ; 204 socket address . s i n p o r t = port ; 205 socket address . sin addr = local address ; 206 / Bind t h e s o c k e t t o t h a t a d d r e s s . / 207 r v a l = b i n d ( s e r v e r s o c k e t , &s o c k e t a d d r e s s , s i z e o f ( s o c k e t a d d r e s s ) ) ; 208 i f ( r v a l != 0 ) 209 s y s t e m e r r o r ( bind ) ; 210 / Instruct the socket to accept connections . / 211 r v a l = l i s t e n ( s e r v e r s o c k e t , 10) ; 212 i f ( r v a l != 0 ) 213 system error ( l i s t e n ) ; 214 215 i f ( verbose ) { 216 / I n v e r b o s e mode , d i s p l a y t h e l o c a l a d d r e s s and p o r t number 217 we r e l i s t e n i n g on . / 218 socklen t address length ; 219 220 / F i n d t h e s o c k e t s l o c a l a d d r e s s . / 221 address length = sizeof ( socket address ) ; 222 r v a l = g e t s o c k n a m e ( s e r v e r s o c k e t , &s o c k e t a d d r e s s , &a d d r e s s l e n g t h ) ; 223 a s s e r t ( r v a l == 0 ) ; 224 / P r i n t a m e s s a g e . The p o r t number n e e d s t o b e c o n v e r t e d f r o m 225 network byte order ( b i g endian ) to host byte order . / 226 p r i n t f ( s e r v e r l i s t e n i n g on %s :%d\n , 227 inet ntoa ( socket address . sin addr ) , 228 ( int ) ntohs ( s o c k e t a d d r e s s . s i n p o r t ) ) ; 229 } 230 231 / Loop f o r e v e r , h a n d l i n g c o n n e c t i o n s . / 232 while ( 1 ) { 233 struct s o c k a d d r i n remote address ; 234 socklen t address length ; 235 int connection ; 236 pid t child pid ;

285

Listagem 11.8: (server.c) Continuao ca


237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 } 295 } / A c c e p t a c o n n e c t i o n . This c a l l b l o c k s u n t i l a connection i s ready . / address length = sizeof ( remote address ) ; c o n n e c t i o n = a c c e p t ( s e r v e r s o c k e t , &r e m o t e a d d r e s s , &a d d r e s s l e n g t h ) ; i f ( c o n n e c t i o n == 1) { / The c a l l t o a c c e p t f a i l e d . / i f ( e r r n o == EINTR) / The c a l l was i n t e r r u p t e d b y a s i g n a l . Try a g a i n . / continue ; else / S o m e t h i n g e l s e w e n t wrong . / system error ( accept ) ; } / We h a v e a c o n n e c t i o n . P r i n t a message v e r b o s e mode . / i f ( verbose ) { socklen t address length ; if we r e running in

/ Get t h e r e m o t e a d d r e s s o f t h e c o n n e c t i o n . / address length = sizeof ( socket address ) ; r v a l = g e t p e e r n a m e ( c o n n e c t i o n , &s o c k e t a d d r e s s , &a d d r e s s l e n g t h ) ; a s s e r t ( r v a l == 0 ) ; / P r i n t a m e s s a g e . / p r i n t f ( c o n n e c t i o n a c c e p t e d from %s \n , inet ntoa ( socket address . sin addr ) ) ; } / F o r k a c h i l d p r o c e s s t o h a n d l e t h e c o n n e c t i o n . / child pid = fork () ; i f ( c h i l d p i d == 0 ) { / T h i s i s t h e c h i l d p r o c e s s . I t shouldn t use s t d i n or s t d o u t , s o c l o s e them . / c l o s e ( STDIN FILENO ) ; c l o s e (STDOUT FILENO) ; / A l s o t h i s c h i l d p r o c e s s s h o u l d n t do a n y t h i n g w i t h t h e listening socket . / close ( server socket ) ; / H a n d l e a r e q u e s t f r o m t h e c o n n e c t i o n . We h a v e o u r own c o p y of the connected socket d e s c r i p t o r . / handle connection ( connection ) ; / A l l d o n e ; c l o s e t h e c o n n e c t i o n s o c k e t , and end t h e c h i l d process . / close ( connection ) ; exit (0) ; } else i f ( c h i l d p i d > 0) { / T h i s i s t h e p a r e n t p r o c e s s . The c h i l d p r o c e s s h a n d l e s t h e c o n n e c t i o n , s o we don t n e e d o u r c o p y o f t h e c o n n e c t e d s o c k e t descriptor . Close i t . Then c o n t i n u e w i t h t h e l o o p and accept another connection . / close ( connection ) ; } else / C a l l t o f o r k f a i l e d . / system error ( fork ) ;

Essas so as funes em server.c: a co server run o ponto de entrada principal para executar o servidor. e Essa funo inicia o servidor e comea aceitando coneces, e no reca c co a torna a menos que um erro srio ocorra. O servidor usa um socket e servidor de uxo TCP (veja Seo 5.5.3, Servidores no Cap ca tulo 5, Comunicao Entre Processos). O primeiro argumento a server run ca especica o endereo local no qual as coneces so aceitas. Um comc co a putador GNU/Linux pode ter multiplos endereos de rede, e cada enc 286

dereo pode estar associado a uma interface de rede diferente2 . Para c restringir o servidor a aceitar coneces de uma interface em partico cular3 , especique o correspondente endereo de rede. Especique o c endereo local INADDR ANY para aceitar coneces de qualquer enc co dereo local. c O segundo argumento a server run o nmero de porta sobre a qual e u aceitar coneces. Se o nmero de porta j estiver sendo usada por co u a outro servio, ou se corresponder a uma porta privilegiada e o servidor c no estiver sendo executado com privilgios de superusurio, o servia e a dor ir falhar. O valor especial 0 instrui o GNU/Linux a selecionar a uma porta livre automaticamente. Veja a pgina de manual para inet a para mais informao sobre endereo de dom ca c nio Internet e nmeros u de porta. O servidor manipula cada coneco com os clientes em um processo ca lho criado com fork (veja a Seo 3.2.2, Usando Bifurcar e Execuca tar no Cap tulo 3, Processos). O processo principal (pai) continua aceitando novas coneces enquanto as j existentes esto sendo servico a a das. O processo lho chama handle connection e ento fecha o socket a de coneco e sai. ca ca handle connection processa uma unica coneco de cliente, usando o descritor de arquivo do socket informado como seu argumento. Essa funo l dados vindos do socket e tenta interpret-los como uma reca e a quisio de pgina HTTP. ca a O servidor processa somente requisies HTTP na verso 1.0 e na co a verso 1.1. Quando encontra um protocolo ou verso diferente, o sera a vidor responde enviando o cdigo de resultado HTTP 400 e a mensao gem bad request response. O servidor entende somente o mtodo GET e do HTTP. Se o cliente requisita qualquer outro mtodo, o servidor e responde enviando o cdigo de resultado HTTP 501 e a mensagem o bad method response template. Se o cliente envia uma bem formada requisio GET, handle connection ca chama handle get para atend-la. Essa funo tenta chamar um mdulo e ca o de servidor com um nome gerado da pagina requisitada. Por exemplo, Se o cliente requisita a pgina chamada information, handle get tenta a chamar um mdulo de servidor chamado information.so. Se o mdulo o o no pode ser chamado, handle get envia ao cliente o cdigo de resula o
Seu computador pode ser congurado para incluir tais interfaces como eth0, uma placa Ethernet; lo, a rede (loopback ) local; ou ppp0, uma coneco de rede dial-up. ca 3 Nota do tradutor: temos tambm as interfaces wireless iniciando com wlan0. e
2

287

tado HTTP 404 e a mensgem not found response template. Se o cliente envia uma requisio de pgina que corresponde a um mdulo de serca a o vidor, handle get envia um cabealho de cdigo de resultado 200 para c o o cliente, o qual indica que a requisio foi processada com sucesso e ca chama a funo de mdulo module generate. Essa funo gera o cdigo ca o ca o fonte HTML para uma pgina Web e envia esse cdigo fonte para o a o cliente Web.

server run instala clean up child process como o manipulador de sinal para SIGCHLD. Essa funo simplesmente limpa processos lhos que ca terminaram (veja Seo 3.3.5, Limpando Filhos de Forma No Sincroca a nizada no Cap tulo 3).

11.2.4

O Programa Principal

O programa main.c (veja Listagem 11.9) fornece uma funo main para o ca programa server. A responsabilidade da funo main tratar opes de linha ca e co de comando, detectar e reportar erros, e congurar e executar o servidor. 288

Listagem 11.9: (main.c) Programa Principal do Servidor e Tratamento de Linha de Comando


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 #include #include #include #include #include #include #include #include < a s s e r t . h> <g e t o p t . h> <n e t d b . h> <s t d i o . h> < s t d l i b . h> < s t r i n g . h> <s y s / s t a t . h> <u n i s t d . h>

#include s e r v e r . h / D e s c r i p t i o n of long options for getopt long . /

s t a t i c const s t r u c t o p t i o n { address , 1, { help , 0, { moduled i r , 1, { port , 1, { verbose , 0, }; / D e s c r i p t i o n of short

long options [ ] = { NULL, a } , NULL, h } , NULL, m } , NULL, p } , NULL, v } ,

options

for

getopt long .

s t a t i c const char const s h o r t o p t i o n s = a : hm : p : v ; / U s a g e summary t e x t . / template = Bind t o l o c a l a d d r e s s ( by d e f a u l t , b i n d \n t o a l l l o c a l a d d r e s s e s ) . \ n P r i n t t h i s i n f o r m a t i o n . \ n Load modules from s p e c i f i e d d i r e c t o r y \n ( by d e f a u l t , u s e e x e c u t a b l e d i r e c t o r y ) . \ n Bind t o s p e c i f i e d p o r t . \ n P r i n t v e r b o s e m e s s a g e s . \ n ;

s t a t i c const char const u s a g e Usage : %s [ o p t i o n s ] \ n a , a d d r e s s ADDR h , h e l p m, moduled i r DIR p , p o r t PORT v , v e r b o s e

/ P r i n t u s a g e i n f o r m a t i o n and e x i t . I f IS ERROR i s nonz e r o , w r i t e t o s t d e r r and u s e an e r r o r e x i t c o d e . O t h e r w i s e , w r i t e t o s t d o u t and u s e a none r r o r t e r m i n a t i o n c o d e . Does n o t r e t u r n . / s t a t i c void p r i n t u s a g e ( i n t { fprintf ( is error ? stderr e x i t ( i s e r r o r ? 1 : 0) ; } is error ) : stdout , usage template , program name ) ;

i n t main ( i n t a r g c , char const a r g v [ ] ) { struct i n a d d r l o c a l a d d r e s s ; uint16 t port ; int next option ; / S t o r e t h e p r o g r a m name , program name = a r g v [ 0 ] ; w h i c h we l l use in error messages . /

/ S e t d e f a u l t s f o r o p t i o n s . Bind t h e s e r v e r t o a l l l o c a l a d d r e s s e s , and a s s i g n an u n u s e d p o r t a u t o m a t i c a l l y . / l o c a l a d d r e s s . s a d d r = INADDR ANY ; port = 0; / Don t p r i n t v e r b o s e m e s s a g e s . / verbose = 0; / Load m o d u l e s f r o m t h e d i r e c t o r y c o n t a i n i n g t h i s e x e c u t a b l e . / module dir = g e t s e l f e x e c u t a b l e d i r e c t o r y () ; a s s e r t ( m o d u l e d i r != NULL) ; / P a r s e o p t i o n s . / do { next option = g e t o p t l o n g ( a r g c , argv , s h o r t o p t i o n s , switch ( n e x t o p t i o n ) { case a : / U s e r s p e c i f i e d a o r a d d r e s s . / { struct hostent l o c a l h o s t n a m e ;

l o n g o p t i o n s , NULL) ;

289

Listagem 11.10: (main.c) Continuao ca


76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 / Look up t h e h o s t name t h e u s e r s p e c i f i e d . / l o c a l h o s t n a m e = gethostbyname ( optarg ) ; i f ( l o c a l h o s t n a m e == NULL | | l o c a l h o s t n a m e >h l e n g t h == 0 ) / C o u l d n o t r e s o l v e t h e name . / e r r o r ( o p t a r g , i n v a l i d h o s t name ) ; else / H o s t name i s OK, s o u s e i t . / l o c al a dd r e ss . s addr = ( ( int ) ( l o c a l h o s t n a m e >h a d d r l i s t [ 0 ] ) ) ; } break ; case h : / U s e r s p e c i f i e d h o r h e l p . print usage (0) ;

case m : / U s e r s p e c i f i e d m o r moduled i r . { struct s t a t d i r i n f o ;

/ Check t h a t i t e x i s t s . / i f ( a c c e s s ( o p t a r g , F OK) != 0 ) e r r o r ( o p t a r g , module d i r e c t o r y d o e s n o t e x i s t ) ; / Check t h a t i t i s a c c e s s i b l e . / i f ( a c c e s s ( o p t a r g , R OK | X OK) != 0 ) e r r o r ( o p t a r g , module d i r e c t o r y i s n o t a c c e s s i b l e ) ; / Make s u r e t h a t i t i s a d i r e c t o r y . / i f ( s t a t ( o p t a r g , & d i r i n f o ) != 0 | | ! S ISDIR ( d i r i n f o . s t m o d e ) ) e r r o r ( optarg , not a d i r e c t o r y ) ; / I t l o o k s OK, s o u s e i t . / module dir = strdup ( optarg ) ; } break ; case p : / U s e r s p e c i f i e d p o r p o r t . { long v a l u e ; char end ;

v a l u e = s t r t o l ( o p t a r g , &end , 1 0 ) ; i f ( end != \0 ) / The u s e r s p e c i f i e d non d i g i t s i n t h e p o r t number . / print usage (1) ; / The p o r t number n e e d s t o b e c o n v e r t e d t o n e t w o r k ( b i g e n d i a n ) byte order . / port = ( u i n t 1 6 t ) htons ( value ) ; } break ; case v : / U s e r s p e c i f i e d v o r v e r b o s e . verbose = 1; break ; case ? : / U s e r s p e c i f i e d print usage (1) ; case 1: / Done w i t h break ;

an n r e c o g n i z e d

option .

options .

default : abort () ; } } while ( n e x t o p t i o n != 1) ; / T h i s p r o g r a m t a k e s no a d d i t i o n a l u s e r s p e c i f i e d any . / i f ( o p t i n d != a r g c ) print usage (1) ; / P r i n t t h e m o d u l e i f ( verbose ) directory , if arguments . I s s u e an e r r o r if the

we r e

running

verbose .

290

Listagem 11.11: (main.c) Continuao ca


152 p r i n t f ( modules w i l l be l o a d e d from %s \n , m o d u l e d i r ) ; 153 154 / Run t h e s e r v e r . / 155 server run ( l o c a l a d d r e ss , port ) ; 156 157 return 0 ; 158 }

O programa main.c contm essas funes: e co a funo main chama getopt long (veja Seo 2.1.3, Usando getopt long ca ca no Cap tulo 2) para tratar opes de linha de comando. A getopt long co fornece ambas as formas de opo longa e curta, a antiga no array ca e long options e a mais nova na sequncia de caracteres short options. O valor padronizado para a porta escutada pelo servidor 0 e para um e endereo local INADDR ANY. Esses valores padronizados podem ser c e sobrescritos pelas opes port (-p) e address (-a), respectivaco mente. Se o usurio especica um endereo, a funo main chama a a c ca 4 funo de biblioteca gethostbyname para converter esse endereo forca c necido pelo usurio para um endereo de Internet numrico. a c e O valor padro para o diretrio do qual chamar mdulos de servia o o dor o diretrio contendo o executvel server, como determinado por e o a get self executable directory. O usurio pode sobrescrever o valor cona ca tido em get self executable directory com a opo module-dir (-m); a funo main garante que o diretrio especicado esteja acess ca o vel. Por padro, mensgens detalhadas no so impressas. O usurio pode a a a a habilitar as mensagens detalhadas especicando a opo verbose ca (-v). Se o usurio especicar a opo help (-h) ou especicar alguma a ca opo invlida, a funo main chama a funo print usage, a qual mosca a ca ca tra um sumrio de uso e sai. a

11.3

Modulos

Fornecemos quatro mdulos para demonstrar o tipo de funcionalidade que o voc pode implementar usando essa implementao de servidor. Implementar e ca seu prprio mdulo de servidor to simples quanto denir uma funo o o e a ca module generate para retornar um texto apropriado na linguagem HTML.
A funo de biblioteca gethostbyname realiza a resoluo de nomes usando DNS, se ca ca necessrio. a
4

291

11.3.1

Mostra a Hora do Relgio Comum o

O mdulo time.so (veja a Listagem 11.12) gera uma unica pgina contendo a o a hora do local do relgio comum do servidor. A funo module generate desse o ca mdulo chama gettimeofday para obter a hora atual (veja Seo 8.7, A chao ca mada gettimeofday: Hora Relgio Comum no Cap o tulo 8, Chamadas de Sistema do GNU/Linux) e usa localtime e strftime para gerar uma representao em modo texto da hora solicitada. Essa representao embutida ca ca e no modelo HTML page template. Listagem 11.12: (time.c) Mdulo do Servidor para Mostrar a Hora Relgio o o Comum
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #include #include #include #include < a s s e r t . h> <s t d i o . h> <s y s / t i m e . h> <t i m e . h>

#include s e r v e r . h / A t e m p l a t e for t h e HTML p a g e this module generates . /

s t a t i c char p a g e t e m p l a t e = <html>\n <head>\n <meta h t t pe q u i v =\ r e f r e s h \ c o n t e n t =\5\>\n </head>\n <body>\n <p>The c u r r e n t t i m e i s %s . </p>\n </body>\n </html>\n ; void m o d u l e g e n e r a t e ( i n t f d ) { struct timeval tv ; s t r u c t tm ptm ; char t i m e s t r i n g [ 4 0 ] ; FILE f p ; / O b t a i n t h e t i m e o f day , and c o n v e r t i t t o a tm s t r u c t . / g e t t i m e o f d a y (& tv , NULL) ; ptm = l o c a l t i m e (& t v . t v s e c ) ; / Format t h e d a t e and t i m e , down t o a s i n g l e s e c o n d . / s t r f t i m e ( t i m e s t r i n g , s i z e o f ( t i m e s t r i n g ) , % H:%M:%S , ptm ) ; / C r e a t e a s t r e a m c o r r e s p o n d i n g t o t h e c l i e n t descriptor . / f p = f d o p e n ( f d , w ) ; a s s e r t ( f p != NULL) ; / G e n e r a t e t h e HTML o u t p u t . / f p r i n t f ( fp , page template , t i m e s t r i n g ) ; / A l l d o n e ; f l u s h t h e s t r e a m . / f f l u s h ( fp ) ; } socket file

Esse mdulo usa as rotinas de E/S da biblioteca C GNU padro por o a convenincia. A chamada a gefdopen gera um apontador de uxo (FILE*) e correspondendo ao descritor de arquivo do socket do cliente (veja Seo B.4, ca Relao de Funes de E/S da Biblioteca C GNU Padro no Apndice ca co a e B, E/S de Baixo N vel). O mdulo escreve para o apontador de uxo o usando fprintf e descarrega o uxo usando ush para evitar a perda de dados armazenados no espao temporrio de armazenagem quando o socket c a fechado. e 292

A pgina HTML retornada pelo mdulo time.so inclui um elemento <meta> a o no cabealho da pgina que instrui os clientes a atualizar a pgina a cada 5 c a a segundos. Dessa forma o cliente mosta a hora atual.

11.3.2

Mostra a Distribuio GNU/Linux ca

O mdulo issue.so (veja Listagem 11.13) mostra informao sobre a distrio ca buio GNU/Linux instalada no servidor. Essa informao tradicionalca ca e mente armazenada no arquivo /etc/issue. Esse mdulo envia o contedo o u desse arquivo, envolvido em um elemento <pre> de uma pgina HTML. a Listagem 11.13: (issue.c) Mdulo de Servidor para Mostrar Informao o ca da Distribuio GNU/Linux ca
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #include #include #include #include < a s s e r t . h> <s t d i o . h> <s y s / t i m e . h> <t i m e . h>

#include s e r v e r . h / A t e m p l a t e for t h e HTML p a g e this module generates . /

s t a t i c char p a g e t e m p l a t e = <html>\n <head>\n <meta h t t pe q u i v =\ r e f r e s h \ c o n t e n t =\5\>\n </head>\n <body>\n <p>The c u r r e n t t i m e i s %s . </p>\n </body>\n </html>\n ; void m o d u l e g e n e r a t e ( i n t f d ) { struct timeval tv ; s t r u c t tm ptm ; char t i m e s t r i n g [ 4 0 ] ; FILE f p ; / O b t a i n t h e t i m e o f day , and c o n v e r t i t t o a tm s t r u c t . / g e t t i m e o f d a y (& tv , NULL) ; ptm = l o c a l t i m e (& t v . t v s e c ) ; / Format t h e d a t e and t i m e , down t o a s i n g l e s e c o n d . / s t r f t i m e ( t i m e s t r i n g , s i z e o f ( t i m e s t r i n g ) , % H:%M:%S , ptm ) ; / C r e a t e a s t r e a m c o r r e s p o n d i n g t o t h e c l i e n t descriptor . / f p = f d o p e n ( f d , w ) ; a s s e r t ( f p != NULL) ; / G e n e r a t e t h e HTML o u t p u t . / f p r i n t f ( fp , page template , t i m e s t r i n g ) ; / A l l d o n e ; f l u s h t h e s t r e a m . / f f l u s h ( fp ) ; } socket file

O mdulo primeiramente tenta abrir /etc/issue. Se o /etc/issue no o a puder ser aberto, o mdulo envia uma pgina de erro para o cliente. De o a outra forma, o mdulo envia o in da pgina HTML, contido em page start. o cio a Ento o mdulo issue.so envia o contedo do /etc/issue usando a chamada a o u de sistema sendle (veja a Seo 8.12, A Chamada sendle: Transferncia ca e de Dados Rpida no Cap a tulo 8). Finalmente, o mdulo issue.so envia o o m de pgina HTML, contido em page end. a 293

Voc pode facilmente adaptar esse mdulo para enviar o contedo de e o u outro arquivo. Se o arquivo contiver uma pgina completa HTML, simplesa mente omita o cdigo que envia o contedo de page start e page end. Voc o u e pode tambm adaptar a implementao do sevidor principal para disponibie ca lizar arquivos estticos, da maneira de um servidor Web tradicional. O uso a de sendle fornece um grau extra de ecincia. e

11.3.3

Mostrando o Espao Livre do Disco c

O mdulo diskfree.so (veja a Listagem 11.14) gera uma pgina mostrando o a informao sobre o espao livre do disco sobre os sistemas de arquivos monca c tados no computador servidor. Essa informao gerada simplesmente a ca e sa de uma chamada ao comando df -h. Da mesma forma que o mdulo isda o sue.so, esse mdulo empacota a sa em um elemento <pre> de uma pgina o da a HTML. Listagem 11.14: (diskfree.c) Mdulo de Servidor para Mostrar Informaes o co Sobre Espao Livre no Disco c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #include #include #include #include < a s s e r t . h> <s t d i o . h> <s y s / t i m e . h> <t i m e . h>

#include s e r v e r . h / A t e m p l a t e for t h e HTML p a g e this module generates . /

s t a t i c char p a g e t e m p l a t e = <html>\n <head>\n <meta h t t pe q u i v =\ r e f r e s h \ c o n t e n t =\5\>\n </head>\n <body>\n <p>The c u r r e n t t i m e i s %s . </p>\n </body>\n </html>\n ; void m o d u l e g e n e r a t e ( i n t f d ) { struct timeval tv ; s t r u c t tm ptm ; char t i m e s t r i n g [ 4 0 ] ; FILE f p ; / O b t a i n t h e t i m e o f day , and c o n v e r t i t t o a tm s t r u c t . / g e t t i m e o f d a y (& tv , NULL) ; ptm = l o c a l t i m e (& t v . t v s e c ) ; / Format t h e d a t e and t i m e , down t o a s i n g l e s e c o n d . / s t r f t i m e ( t i m e s t r i n g , s i z e o f ( t i m e s t r i n g ) , % H:%M:%S , ptm ) ; / C r e a t e a s t r e a m c o r r e s p o n d i n g t o t h e c l i e n t descriptor . / f p = f d o p e n ( f d , w ) ; a s s e r t ( f p != NULL) ; / G e n e r a t e t h e HTML o u t p u t . / f p r i n t f ( fp , page template , t i m e s t r i n g ) ; / A l l d o n e ; f l u s h t h e s t r e a m . / f f l u s h ( fp ) ; } socket file

Enquanto issue.so envia o contedo de um arquivo usando sendle, esse u mdulo deve chamar um comando e redirecionar sua sa para o cliente. o da 294

Para fazer isso, o mdulo segue esses passos: o

1. Primeiramente, o mdulo cria um processo lho usando fork (veja Seo o ca 3.2.2, Usando Bifurcar e Executar no Cap tulo 3).

2. O processo lho copia o descritor de arquivo do socket do cliente para os descritores de arquivo STDOUT FILENO e STDERR FILENO, os quais correspondem ` sa padro e ` sa de erro (veja Seo 2.1.4, a da a a da ca E/S Padro no Cap a tulo 2. Os descritores de arquivo so copiados a usando a chamada dup2 (veja Seo 5.4.3, Redirecionando os Fluxos ca da Entrada Padro, da Sa Padro e de Erro no Cap a da a tulo 5). Toda a sa adicional do processo para qualquer desses uxos enviada para da e o socket do cliente.

3. O processo lho chama o comando df como a opo -h por meio de ca uma chamada a execv (veja Seo 3.2.2, Usando Bifurcar e Executar ca no Cap tulo 3).

4. O processo pai espera pela sa do processo lho por meio de uma da chamada a waitpid (veja Seo 3.3.3, As Chamadas de Sistema da ca Fam wait no Cap lia tulo 3).

Voc pode facilmente adaptar esse mdulo para chamar um comando e o diferente e redirecionar sua sa para o cliente. da

11.3.4

Sumarizando Processos Executando

O mdulo processes.so (veja Listagem 11.15) uma implementao de mdulo o e ca o de servidor mais extens vel. O mdulo processes.so gera uma pgina contendo o a uma tabela que sumariza os processos atualmente executando no sistema do servidor. Cada processo representado por uma linha na tabela que lista o e PID, o nome do programa executvel, o usurio proprietrio e o nomes dos a a a grupos, e o tamanho do conjunto residente. 295

Listagem 11.15: ( processes.c) Mdulo de Servidor para Sumarizar Proo cessos


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 #include #include #include #include #include #include #include #include #include #include #include #include < a s s e r t . h> <d i r e n t . h> < f c n t l . h> <g r p . h> <pwd . h> <s t d i o . h> < s t d l i b . h> < s t r i n g . h> <s y s / s t a t . h> <s y s / t y p e s . h> <s y s / u i o . h> <u n i s t d . h>

#include s e r v e r . h / S e t UID and GID t o t h e o w n i n g u s e r ID and g r o u p ID , r e s p e c t i v e l y , o f p r o c e s s PID . R e t u r n z e r o on s u c c e s s , nonz e r o on f a i l u r e . / static int g e t u i d g i d ( p i d t { char d i r n a m e [ 6 4 ] ; struct s t a t d i r i n f o ; int r v a l ; pid , u i d t uid , g i d t gid )

/ G e n e r a t e t h e name o f t h e p r o c e s s s d i r e c t o r y i n / p r o c . / s n p r i n t f ( d i r n a m e , s i z e o f ( d i r n a m e ) , / p r o c/%d , ( i n t ) p i d ) ; / O b t a i n i n f o r m a t i o n a b o u t t h e d i r e c t o r y . / r v a l = s t a t ( dir name , &d i r i n f o ) ; i f ( r v a l != 0 ) / C o u l d n t f i n d i t ; p e r h a p s t h i s p r o c e s s no l o n g e r e x i s t s . / return 1 ; / Make s u r e i t s a d i r e c t o r y ; a n y t h i n g e l s e i s u n e x p e c t e d . / a s s e r t ( S ISDIR ( d i r i n f o . s t m o d e ) ) ; / E x t r a c t t h e IDs we want . uid = d i r i n f o . s t u i d ; gid = d i r i n f o . s t g i d ; return 0 ; } / R e t u r n t h e name o f u s e r UID . The r e t u r n v a l u e c a l l e r must a l l o c a t e w i t h f r e e . UID must b e a s t a t i c char g e t u s e r n a m e { s t r u c t passwd e n t r y ; ( uid t uid ) i s a b u f f e r which the v a l i d u s e r ID . / /

ent ry = getpwuid ( uid ) ; i f ( e n t r y == NULL) s y s t e m e r r o r ( getpwuid ) ; return x s t r d u p ( e n t r y >pw name ) ; } / R e t u r n t h e name o f g r o u p GID . The r e t u r n v a l u e i s a b u f f e r w h i c h t h e c a l l e r must a l l o c a t e w i t h f r e e . GID must b e a v a l i d g r o u p ID . / s t a t i c char g e t g r o u p n a m e ( g i d t { struct group e n t r y ; entry = getgrgid ( gid ) ; i f ( e n t r y == NULL) system error ( getgrgid ) ; return x s t r d u p ( e n t r y >gr name ) ; } / R e t u r n t h e name o f t h e p r o g r a m r u n n i n g i n p r o c e s s PID , o r NULL on error . The r e t u r n v a l u e i s a n e w l y a l l o c a t e d b u f f e r w h i c h t h e c a l l e r must d e a l l o c a t e w i t h f r e e . / s t a t i c char g e t p r o g r a m n a m e ( p i d t { char f i l e n a m e [ 6 4 ] ; char s t a t u s i n f o [ 2 5 6 ] ; int fd ; int r v a l ; char o p e n p a r e n ; char c l o s e p a r e n ; char r e s u l t ; pid ) gid )

296

Listagem 11.16: ( processes.c) Continuao ca


80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 / G e n e r a t e t h e name o f t h e s t a t f i l e i n t h e p r o c e s s s / p r o c d i r e c t o r y , and o p e n i t . / s n p r i n t f ( f i l e n a m e , s i z e o f ( f i l e n a m e ) , / p r o c/%d/ s t a t , ( i n t ) p i d ) ; f d = open ( f i l e n a m e , O RDONLY) ; i f ( f d == 1) / C o u l d n t o p e n t h e s t a t f i l e f o r t h i s p r o c e s s . Perhaps t h e p r o c e s s no l o n g e r e x i s t s . / return NULL ; / Read t h e c o n t e n t s . / r v a l = read ( fd , s t a t u s i n f o , s i z e o f ( s t a t u s i n f o ) 1) ; c l o s e ( fd ) ; i f ( r v a l <= 0 ) / C o u l d n t r e a d , f o r some r e a s o n ; b a i l . / return NULL ; / NUL e r m i n a t e t h e f i l e c o n t e n t s . t / s t a t u s i n f o [ r v a l ] = \0 ; / The p r o g r a m name i s t h e s e c o n d e l e m e n t o f t h e f i l e c o n t e n t s , and i s surrounded by p a r e n t h e s e s . Find t h e p o s i t i o n s o f t h e p a r e n t h e s e s in the f i l e contents . / open paren = s t r c h r ( s t a t u s i n f o , ( ) ; close paren = strchr ( status info , ) ) ; i f ( o p e n p a r e n == NULL | | c l o s e p a r e n == NULL | | c l o s e p a r e n < open paren ) / C o u l d n t f i n d them ; b a i l . / return NULL ; / A l l o c a t e memory f o r t h e r e s u l t . / r e s u l t = ( char ) x m a l l o c ( c l o s e p a r e n o p e n p a r e n ) ; / Copy t h e p r o g r a m name i n t o t h e r e s u l t . / strncpy ( r e s u l t , open paren + 1 , c l o s e p a r e n open paren 1) ; / s t r n c p y d o e s n t NUL e r m i n a t e t h e r e s u l t , s o do i t h e r e . t / r e s u l t [ c l o s e p a r e n o p e n p a r e n 1 ] = \0 ; / A l l d o n e . / return r e s u l t ; } / R e t u r n t h e r e s i d e n t s e t s i z e R e t u r n 1 on f a i l u r e . / static int g e t r s s ( p i d t { char f i l e n a m e [ 6 4 ] ; int fd ; char mem info [ 1 2 8 ] ; int r v a l ; int r s s ; pid ) ( RSS ) , in kilobytes , of p r o c e s s PID .

/ G e n e r a t e t h e name o f t h e p r o c e s s s s t a t m e n t r y i n i t s / p r o c directory . / s n p r i n t f ( f i l e n a m e , s i z e o f ( f i l e n a m e ) , / p r o c/%d/ s t a t m , ( i n t ) p i d ) ; / Open i t . / f d = open ( f i l e n a m e , O RDONLY) ; i f ( f d == 1) / C o u l d n t o p e n i t ; p e r h a p s t h i s p r o c e s s no l o n g e r e x i s t s . / return 1; / Read t h e f i l e s c o n t e n t s . / r v a l = r e a d ( f d , mem info , s i z e o f ( mem info ) 1 ) ; c l o s e ( fd ) ; i f ( r v a l <= 0 ) / C o u l d n t r e a d t h e c o n t e n t s ; b a i l . / return 1; / NUL e r m i n a t e t h e c o n t e n t s . t / mem info [ r v a l ] = \0 ; / E x t r a c t t h e RSS . I t s the second item . / r v a l = s s c a n f ( mem info , %d %d , &r s s ) ; i f ( r v a l != 1 ) / The c o n t e n t s o f s t a t m a r e f o r m a t t e d i n a way we don t u n d e r s t a n d . return 1; / The v a l u e s i n s t a t m a r e i n u n i t s o f C o n v e r t t h e RSS t o k i l o b y t e s . / return r s s g e t p a g e s i z e ( ) / 1 0 2 4 ; } / G e n e r a t e an HTML t a b l e row f o r p r o c e s s PID . The r e t u r n v a l u e i s a p o i n t e r t o a b u f f e r w h i c h t h e c a l l e r must d e a l l o c a t e w i t h f r e e , o r NULL i f an e r r o r o c c u r s . / s t a t i c char f o r m a t p r o c e s s i n f o ( pid t pid ) the system s page size .

297

Listagem 11.17: ( processes.c) Continuao ca


160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 { int r v a l ; u i d t uid ; g i d t gid ; char u s e r n a m e ; char group name ; int r s s ; char program name ; size t result length ; char r e s u l t ; / O b t a i n t h e p r o c e s s s u s e r and g r o u p IDs . / r v a l = g e t u i d g i d ( pid , &uid , &g i d ) ; i f ( r v a l != 0 ) return NULL ; / O b t a i n t h e p r o c e s s s RSS . / r s s = g e t r s s ( pid ) ; i f ( r s s == 1) return NULL ; / O b t a i n t h e p r o c e s s s p r o g r a m name . / program name = g e t p r o g r a m n a m e ( p i d ) ; i f ( program name == NULL) return NULL ; / C o n v e r t u s e r and g r o u p IDs t o c o r r e s p o n d i n g names . user name = get user name ( uid ) ; group name = g e t g r o u p n a m e ( g i d ) ;

/ Compute t h e l e n g t h o f t h e s t r i n g we l l n e e d t o h o l d t h e r e s u l t , and a l l o c a t e memory t o h o l d i t . / r e s u l t l e n g t h = s t r l e n ( program name ) + s t r l e n ( u s e r n a m e ) + s t r l e n ( group name ) + 1 2 8 ; r e s u l t = ( char ) x m a l l o c ( r e s u l t l e n g t h ) ; / Format t h e r e s u l t . / snprintf ( result , result length , <t r > d a l i g n =\ r i g h t \>%d</td> <t <td> t>%s </t t ></td> <t <td>%s </td> <td>%s </td> d a l i g n =\ r i g h t \>%d</td></t r >\n , <t ( i n t ) pid , program name , u s e r n a m e , group name , r s s ) ; / C l e a n up . / f r e e ( program name ) ; f r e e ( user name ) ; f r e e ( group name ) ; / A l l d o n e . / return r e s u l t ; } / HTML s o u r c e for the start of the process listing page . /

s t a t i c char p a g e s t a r t = <html>\n <body>\n <t a b l e c e l l p a d d i n g =\4\ c e l l s p a c i n g =\0\ b o r d e r =\1\>\n <thead >\n <t r >\n <th>PID</th >\n <th>Program</th >\n <th>User </th >\n <th>Group</th >\n <th>RSS&nbsp ; ( KB)</th >\n </t r >\n </thead >\n <tbody >\n ; / HTML s o u r c e for t h e end o f the process listing page . /

s t a t i c char p a g e e n d = </tbody >\n </ t a b l e >\n </body>\n </html>\n ; void m o d u l e g e n e r a t e ( i n t f d ) { size t i ; DIR p r o c l i s t i n g ; / S e t up an i o v e c a r r a y . We l l f i l l t h i s w i t h b u f f e r s t h a t l l b e p a r t o f our output , growing i t d y n a m i c a l l y as n e c e s s a r y . / / The number o f e l e m e n t s s i z e t vec length = 0; in the array t h a t we v e u s e d . /

298

Listagem 11.18: ( processes.c) Continuao ca


240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 } / The a l l o c a t e d s i z e o f t h e a r r a y . / s i z e t vec size = 16; / The a r r a y o f i o v c e c e l e m e n s . / struct i o v e c vec = ( struct i o v e c ) xmalloc ( v e c s i z e s i z e o f

( struct start

iovec ) ) ; of the page . /

/ The f i r s t b u f f e r i s t h e HTML s o u r c e f o r t h e vec [ v e c l e n g t h ] . i o v b a s e = p a g e s t a r t ; vec [ v e c l e n g t h ] . i o v l e n = s t r l e n ( p a g e s t a r t ) ; ++v e c l e n g t h ; / S t a r t a d i r e c t o r y l i s t i n g f o r / p r o c . p r o c l i s t i n g = opendir ( / proc ) ; i f ( p r o c l i s t i n g == NULL) system error ( opendir ) ; / Loop o v e r d i r e c t o r y e n t r i e s while ( 1 ) { struct d i r e n t p r o c e n t r y ; const char name ; p i d t pid ; char p r o c e s s i n f o ; in / proc . /

/ Get t h e n e x t e n t r y i n / p r o c . / proc entry = readdir ( proc listing ) ; i f ( p r o c e n t r y == NULL) / We v e h i t t h e end o f t h e l i s t i n g . break ; /

I f t h i s e n t r y i s n o t composed p u r e l y o f d i g i t s , i t s n o t a p r o c e s s d i r e c t o r y , so s k i p i t . / >d name ; name = p r o c e n t r y i f ( s t r s p n ( name , 0 1 2 3 4 5 6 7 8 9 ) != s t r l e n ( name ) ) continue ; / The name o f t h e e n t r y i s t h e p r o c e s s ID . / p i d = ( p i d t ) a t o i ( name ) ; / G e n e r a t e HTML f o r a t a b l e row d e s c r i b i n g t h i s p r o c e s s . / p r o c e s s i n f o = f o r m a t p r o c e s s i n f o ( pid ) ; i f ( p r o c e s s i n f o == NULL) / S o m e t h i n g w e n t wrong . The p r o c e s s may h a v e v a n i s h e d w h i l e we were l o o k i n g a t i t . Use a p l a c e h o l d e r row i n s t e a d . / <t </td></t r > ; p r o c e s s i n f o = <t r > d c o l s p a n =\5\>ERROR / Make s u r e t h e i o v e c a r r a y i s l o n g e n o u g h t o h o l d t h i s b u f f e r ( p l u s one more , s i n c e we l l add an e x t r a e l e m e n t when we r e d o n e l i s t i n g processes ) . I f not , grow i t t o t w i c e i t s c u r r e n t s i z e . / i f ( v e c l e n g t h == v e c s i z e 1 ) { v e c s i z e = 2 ; v e c = x r e a l l o c ( vec , v e c s i z e s i z e o f ( s t r u c t i o v e c ) ) ; } / S t o r e t h i s b u f f e r a s t h e n e x t e l e m e n t o f t h e a r r a y . / vec [ v e c l e n g t h ] . i o v b a s e = p r o c e s s i n f o ; vec [ v e c l e n g t h ] . i o v l e n = s t r l e n ( p r o c e s s i n f o ) ; ++v e c l e n g t h ; } / End t h e d i r e c t o r y l i s t i n g closedir ( proc listing ) ; operation . /

/ Add one l a s t b u f f e r w i t h HTML t h a t e n d s t h e vec [ v e c l e n g t h ] . i o v b a s e = page end ; vec [ v e c l e n g t h ] . i o v l e n = s t r l e n ( page end ) ; ++v e c l e n g t h ; / O u t p u t t h e e n t i r e p a g e t o t h e w r i t e v ( f d , vec , v e c l e n g t h ) ; client file

page .

descriptor

all

at

once .

/ D e a l l o c a t e t h e b u f f e r s we c r e a t e d . and s h o u l d n o t b e d e a l l o c a t e d . / f o r ( i = 1 ; i < v e c l e n g t h 1 ; ++i ) f r e e ( vec [ i ] . i o v b a s e ) ; / D e a l l o c a t e t h e i o v e c a r r a y . / f r e e ( vec ) ;

The

first

and

last

are

static ,

O ato de reunir dados dos processos e format-los como uma tabela HTML a quebrado em algumas operaes mais simples: e co 299

get uid gid extrai os IDs do proprietrio e do grupo de um processo. a Para fazer isso, a funo chama stat (veja Seo B.2, stat no Apndice ca ca e B) sobre o subdiretrio do processo no /proc (veja a Seo 7.2, Entrao ca das dos Processos no Cap tulo 7). O usurio e o grupo que so proa a prietrios desse diretrio so idnticos ao usurio e grupo proprietrios a o a e a a do processo. get user name retorna o nome de usurio correspondente a um dea terminado UID. Essa funo simplesmente chama a funo getpwuid ca ca da biblioteca C GNU padro, que consulta o arquivo /etc/passwd do a sistema e retorna uma cpia do resultado. get group name retorna o o nome do grupo correspondente a um determinado GID. A funo ca get group name usa a chamada de sistema getgrgid. get program name retorna o nome do programa executando em um processo especicado. Essa informao extra da entrada stat no ca e da diretrio do processo sob o /proc (veja Seo 7.2, Entradas de Proo ca cessos no Cap tulo 7). Usamos essa entrada do /proc em lugar de examinar o link simblico exe (veja Seo 7.2.4, O Executvel do Proo ca a cesso no Cap tulo 7) ou a entrada cmdline (veja Seo 7.2.2, Lista ca de Argumentos do Processo no Cap tulo 7) pelo fato de esses ultimos dois estarem inacess veis se o processo executando o programa server no for de propriedade do mesmo usurio que o processo sendo exaa a minado. Tambm, lendo de stat no fora o GNU/Linux a paginar o e a c processo sob exame de volta ` memria, se ocorrer de o processo ser a o removido da rea de swap. a get rss retorna o tamanho do conjunto residente de um processo. Essa informao est dispon como o segundo elemento no contedo da ca a vel u entrada statm do processo (veja Seo 7.2.6, Estat ca sticas de Memria o do Processo no Cap tulo 7) no seu subdiretrio do /proc. o e format process info gera uma sequncia de caracteres contendo elementos HTML para uma unica linha de tabela, representando um unico processo. Aps chamar as funes listadas previamente para preencher o co a unica linha, format process info aloca uma rea temporria de arma a a zenagem e gera o cdigo HTML usando funo snprintf da Biblioteca o ca C GNU Padro. a module generate gera a pgina HTML completa, incluindo a tabela. a A sa consiste de uma sequncia de caracteres contendo o in da da e cio pgina e a tabela (em page start), uma sequncia de caracteres para a e 300

cada linha da tabela (gerada por format process info), e uma sequncia e de caracteres contendo o m da tabela e a pgina (em page end ). A a funo module generate determina os PIDs dos processos executando ca no sistema por meio de um exame ao contedo do /proc. A funo u ca module generate obtm uma listagem desse diretrio usando opendir e e o readdir (veja a Seo B.6, Lendo o Contedo de um Diretrio no ca u o Apndice B). A funo module generate percorre o contedo, procue ca u rando por entradas cujos nomes so compostos inteiramente de d a gitos; esses nomes compostos inteiramente de d gitos so usados para sea rem entradas de processos. Potencialmente um grande nmero de u sequncias de caractere devem ser escritas no socket do cliente uma e sequncia para cada in e m de pgina, adicionalmente uma para e cio a cada processo. Se tivermos de escrever cada sequncia de caracteres e para o descritor de arquivo do socket do cliente com uma chamada separada a write, pode gerar trfego de rede desnecessrio pelo fato de a a cada sequncia de caracteres pode ser enviada em um pacote separado e de rede. Para otimizar a embalagem de dados em pacotes, usamos uma unica chamada a writev ao invs de chamar write (veja Seo B.3, Leituras e ca e Escritas de Vetor no Apndice B). Para fazer isso, devemos conse truir um array de objetos struct iovec, vec. Todavia, pelo fato de no a sabermos o nmero de processos antecipadamente, devemos iniciar com u um pequeno array e expandir esse mesmo array ` medida que novos a processos so adicionados. A varivel vec length contm o nmero de a a e u elementos de vec que so usados, enquanto vec size contm o tamanho a e alocado de vec. Quando vec length est prestes a extrapolar vec size, a expandimos vec para duas vezes seu tamano por meio de uma chamada a xrealloc. Quando estamos terminando com a escrita do vetor, devemos desalocar tudo da sequncias de caractere dinmicamente alocada e a apontada pelo vec, e ento desalocar o vec propriamente dito. a

11.4

Usando o Servidor

Se estivermos planejando distribuir esse programa por meio de seu cdigo o fonte, mantendo esse cdigo fonte sobre uma base cont o nua, ou port-lo para a outras plantaformas, provavelmente iremos desejar empacotar esse cdigo o fonte usando o GNU Automake e o GNU Autoconf, ou um similar sistema de congurao automtica. Tais ferramentas esto fora do escopo desse lica a a vro; para mais informaes sobre as ferramentas de congurao automtica, co ca a consulte o GNU Autoconf, Automake, and Libtool (de autoria de Vaughan, 301

Elliston,Tromey, e Taylor, publicado pela New Riders, 2000).

11.4.1

O Makele

Ao invs de usar o Autoconf ou uma ferramenta similar, fornecemos um unico e 5 Makele compat com o GNU Make de forma que fcil compilar e linkar vel e a o programa server e seus mdulos. O Makele mostrado na Listagem 11.19. o e Veja a pgina info do GNU Make para detalhes da sintaxe do arquivo6 . a Listagem 11.19: (Makele) GNU Make Conguration File for Server Example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 # ## C o n f i g u r a t i o n . # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # C source f i l e s for the s e r v e r . SOURCES = s e r v e r . c module . c common . c main . c # Object f i l e s corresponding to source f i l e s . OBJECTS = $ (SOURCES : . c =. o ) # S e r v e r module s h a r e d l i b r a r y f i l e s . MODULES = d i s k f r e e . so i s s u e . so p r o c e s s e s . so time . so # ## R u l e s . .PHONY: # Default all : # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # all clean

target : build everything . s e r v e r $ (MODULES)

# C l e a n up b u i l d p r o d u c t s . clean : rm f $ (OBJECTS) $ (MODULES)

server

# The main s e r v e r program . L i n k w i t h Wl, e x p o r t dyanamic s o # d y n a m i c a l l y l o a d e d modules can b i n d s y m b o l s i n t h e program . # l i b d l , which c o n t a i n s c a l l s f o r dynamic l o a d i n g . server : $ (OBJECTS) $ (CC) $ (CFLAGS) Wl, e x p o r t dynamic o $@ $ l d l # A l l o b j e c t f i l e s i n t h e s e r v e r depend on s e r v e r . h . # d e f a u l t r u l e f o r b u i l d i n g o b j e c t f i l e s from s o u r c e $ (OBJECTS) : server .h

Link i n

But u s e t h e files .

# Rule f o r b u i l d i n g module s h a r e d l i b r a r i e s from t h e c o r r e s p o n d i n g # source f i l e s . Compile fPIC and g e n e r a t e a s h a r e d o b j e c t f i l e . $ (MODULES) : \ %. s o : %. c s e r v e r . h $ (CC) $ (CFLAGS) fPIC s h a r e d o $@ $<

O Makele fornece esses alvos: all (o padro se voc chama o make sem argumentos pelo fato de all ser a e o primeiro no Makele) inclui o executvel server e todos os mdulos. a o Os mdulos esto listados na varivel MODULES. o a a clean apaga qualquer arquivo produzido pelo Makele. server linka somente o executvel server. Os arquivos fontes listados a na varivel SOURCES so compilados e linkados tambm. a a e
5 6

GNU Make vem instalado em sistemas GNU/Linux. Nota do tradutor: na linha de comando digite info Make.

302

A ultima regra um modelo genrico para compilar arquivos de objetos e e compartilhados para os mdulos do servidor para os correspondentes o arquivos fonte. Note que arquivos fonte para os mdulos de servidor so compilados com o a a opo -fPIC pelo fato deles serem linkados dentro de bibliotecas comparca tilhadas (veja Seo 2.3.2,Bibliotecas Compartilhadas no Cap ca tulo 2). Tambm observe que o executvel server linkado com a opo de compie a e ca lador -Wl,-export-dynamic. Com essa opo, GCC informa a opo -exportca ca dynamic para o linkador, o qual cria um arquivo executvel que tambm a e exporta seus s mbolos externos como uma biblioteca compartilhada. Isso permite aos mdulos, os quais so chamados dinmicamente como biblioo a a tecas compartilhadas, referencias funes de common.c que foram linkadas co estaticamente dentro do executvel server. a

11.4.2

Gerando o Executvel do Programa Server a

Compilar e linkar programas fcil. De dentro do diretrio contendo os e a o fontes, simplesmente chame make:
% make cc -Wall cc -Wall cc -Wall cc -Wall cc -Wall cc -Wall cc -Wall cc -Wall cc -Wall -g -g -g -g -g -g -g -g -g -c -o server.o server.c -c -o module.o module.c -c -o common.o common.c -c -o main.o main.c -Wl,-export-dynamic -o server server.o module.o common.o main.o -ldl -fPIC -shared -o diskfree.so diskfree.c -fPIC -shared -o issue.so issue.c -fPIC -shared -o processes.so processes.c -fPIC -shared -o time.so time.c

Ao chamar o make compila-se e linka-se o programa server e as bibliotecas compartilhadas de mdulos. o


% ls -l server *.so -rwxr-xr-x 1 samuel -rwxr-xr-x 1 samuel -rwxr-xr-x 1 samuel -rwxr-xr-x 1 samuel -rwxr-xr-x 1 samuel samuel samuel samuel samuel samuel 25769 31184 41579 71758 13980 Mar Mar Mar Mar Mar 11 11 11 11 11 01:15 01:15 01:15 01:15 01:15 diskfree.so issue.so processes.so server time.so

11.4.3

Executando o Programa Server

Para rodar o servidor, simplesmente chame o executvel server. a Se voc no especicar o nmero de porta que o server deve escutar com e a u a opo port (-p), GNU/Linux ir escolher uma para voc; nesse caso, ca a e especique verbose (-v) para fazer com que o server mostre na tela o nmero de porta em uso. u Se voc no especicar um endereo com a opo address (-a), o exee a c ca cutvel server ir estar acess a todos os seus endereos de computadores a a vel c 303

de rede. Se seus computadores esto conectados a uma rede, isso signica a que outros iro ser capazes de acessar o programa server, desde que eles coa nheam o nmero de porta correto a ser usado e a pgina a requisitar. Por c u a razes de segurana, uma boa idia especicar o endereo localhost at que o c e e c e voc esteja convencido de que o programa server trabalha corretamente e e no est liberando informao que voc prefere no tornar pblica. Associa a ca e a u ando ao localhost faz com que o servidor associe para o dispositivo de rede local (designado lo) somente programas executando no mesmo computador podem conectar ao programa server. Se voc especicar um endereo e c diferente, esse endereo diferente deve corresponder a seu computador: c % ./server --address localhost --port 4000 O servidor est agora executando. Abrindo uma janela de navegador, e a tente contactar o programa server nesse nmero de porta. Requisite uma u pgina cujo nome coincide com um dos mdulos. Por exemplo, chame o a o mdulo diskfree.so, use a URL adiante: o http://localhost:4000/diskfree Ao invs de 4000, informe o nmero de porta que voc especicou (ou o e u e nmero de prta que o GNU/Linux escolheu para voc). Pressione Ctrl+C u e para interromper o programa server quando voc tiver terminado. Se voc e e no especicar localhost como o endereo do servidor, voc pode tambm a c e e conectar-se ao programa server com um navegador rodando em outro computador por meio do uso do nome de host 7 do seu computador na URL por exemplo: http://host.domain.com:4000/diskfree Se voc especicou a opo verbose (-v), o programa server mostra e ca na tela algumas informaes durante a inicializao e mostra o endereo co ca c de Internet em sua forma numrica de cada cliente que se conectar a esse e mesmo programa sever. Se voc conecta via o endereo localhost, o endereo e c c do cliente ir sempre ser 127.0.0.1. a Se voc zer uma experincia e escrever seu prprio mdulo de servidor, e e o o voc pode coloc-lo em um diretrio diferente daquele contendo os mdulos e a o o atuais. Nesse caso, especique o novo diretrio onde est localizado o novo o a
Nota do tradutor: para ver o nome do host simplesmente abra um terminal/konsole pois em algumas distribuies ele aparece entre o arroba e o cursor piscante ou use o co comando cat /etc/hostname. No slackware temos o /etc/HOSTNAME.
7

304

mdulo com a opo module-dir (-m). O programa server ir olhar nesse o ca a diretrio ao procurar por mdulos de servidor ao invs de olhar na localizao o o e ca padro. a Se voc esquecer a sintaxe das opes de linha de comando, chame o e co programa server com a opo help (-h). ca
% ./server --help Usage: ./server [ options ] -a, --address ADDR Bind to local address (by default, bind to all local addresses). -h, --helpPrint this information. -m, --module-dir DIR Load modules from specified directory (by default, use executable directory). -p, --port PORT Bind to specified port. -v, --verbose Print verbose messages.

11.5

Terminando

Se voc realmente planeja liberar esse programa para uso geral, voc ir pree e a cisar escrever documentao para ele tambm. Muitas pessoas no percebem ca e a que escrever boa documentao to dif e demorado e to importante ca e a cil a quanto escrever um bom programa. Todavia, documentao de prograca mas assunto para outro livro, de forma que iremos deixar voc com algue e mas referncia sobre onde aprender mais sobre como documentar programas e GNU/Linux. Voc ir provavelmente desejar escrever uma pgina de manual para o proe a a grama server, por exemplo. A pgina de manual o primeiro lugar onde muia e tos usurios iro olhar buscando informaes sobre um programa. Pginas de a a co a manual so formatadas usando um sistema de formatao clssico do UNIX a ca a chamado tro. Para ver uma pgina de manual para tro, a qual descreve o a formato de arquivos tro, use o seguinte comando: % man troff Para aprender sobre como GNU/Linux localiza pginas de manual, cona sulte a pgina de manual do comando man propriamente dito por meio do a seguinte comando: % man man Voc pode tambm desejar escrever pginas info, usando o sistema GNU e e a Info, para o programa server e seus mdulos. Naturalmente, documentao o ca sobre o sistema info vem no formato info; para ver essas informaes, use o co seguinte comando: % info info 305

Muitos programas GNU/Linux vem com documentao no formato texto e ca puro ou no formato HTML tambm. e Desejamos que o ato de programar com GNU/Linux seja feliz para voc! e

306

Parte III Apndices e

307

A Outras Ferramentas de Desenvolvimento B E/S de Baixo N vel C Tabela de Sinais D Online Resources E Open Publication License Version 1.0 F GNU General Public License G Sa das Diversas do /proc H Adicionais ao Cap tulo 8 Chamadas de Sistema do GNU/Linux I Assembly J Segurana c K Anexos aos Apndices e

309

310

Apndice A e Outras Ferramentas de Desenvolvimento


O DESENVOLVIMENTO PROGRAMAS GNU/LINUX CORRETOS e rpia dos requer mais que apenas entender o sistema operacional GNU/Linux e suas chamadas de sistema. Nesse apndice, discutiremos ferramentas de dee senvolvimento para encontrar erros durante a execuo tais como uso ilegal ca de memria alocada dinmicamente e para determinar quais partes de um o a programa esto consumindo mais do tempo de execuo. A analize do cdigo a ca o de um programa pode revelar alguma dessas informaes; por meio do uso co dessas ferramentas de execuo e executando o programa dentro dessa ferraca menta de execuo, voc pode encontrar muito mais. ca e

A.1

Anlise Esttica do Programa a a

Alguns erros de programao podem ser detectados usando ferramentas de ca anlise esttica que analizam o cdigo fonte do programa. Se voc chama o a a o e GCC com -Wall e -pedantic, o compilador mostra alertas sobre erradas ou possivelmente errneas construes de programao. Atravs da eliminao o co ca e ca de tais construes, voc ir reduzir o risco de erros de programa, e voc ir co e a e a encontrar essas construes errneas facilmente ao compilar seus programas co o com diferentes variantes GNU/Linux e mesmo em outros sistemas operacionais. Usando vrias opes de comando, voc pode fazer com que o GCC mosa co e tre alertas sobre muitos diferentes tipos de construes questionveis de proco a gramao. A opo -Wall habilita a maioria dessas vericaes. Por exemca ca co plo, o compilador ir produzir um alerta sobre um comentrio que comea a a c dentro de outro comentrio, sobre um tipo incorreto de retorno especicado a 311

pela funo main, e sobre uma funo no void omitindo uma declarao de ca ca a ca retorno. Se voc especicar a opo -pedantic, GCC emite alertas demane ca dados por obedincia estrita a ANSI C e ISO C++. Por exemplo, o uso e da extensoGNU asm far com que ocorra um alerta de uso dessa opo. a a ca Umas poucas extenses GNU, tais como o uso de palavras chave alternativas o comeando com c (duas sublinhas), no ir disparar mensagens de alerta. a a Embora as pginas info do GCC censure o uso dessa opo, recomendamos a ca que voc a use mesmo assim e evite a maioria das extenses de linguagem e o GNU pelo fato de as extenses do GCC tenderem a mudar com o decorrer do o tempo e frequntemente interagirem pobremente com a otimizao de cdigo. e ca o Listagem A.1: (hello.c) Programa Al Mundo o
1 i n t main ( ) 2 { 3 p r i n t f ( Hello , 4 return 0 ; 5 } w o r l d . \ n ) ;

Considere compilar o programa Al Mundo o programa mostrado na o Listagem A.1. Apesar de o GCC compilar o programa sem reclamar, o cdigo fonte no obedece as regras ANSI C. Se voc habilitar alertas por o a e meio de uma compilao com as opes -Wall -pedantic, o GCC revela trs ca co e construes questionveis. co a
% gcc -Wall -pedantic hello.c hello.c:2: warning: return type defaults to int hello.c: In function main: hello.c:3: warning: implicit declaration of function printf hello.c:4: warning: control reaches end of non-void function

Esses alertas indicam que os seguintes problemas ocorreram: O tipo de dado de retorno da funo main no foi especicado. ca a A funo printf est implicitamente declarada pelo fato de <stdio.h> ca a no estar inclu a da. A funo, implicitamente declarada para retornar um tipo de dado int, ca atualmente no retorna nenhum valor. a Analizando um cdigo fonte de programa no podemos encontrar todos o a os enganos de programao e inecincias. Na seo seguintes, mostramos ca e ca quatro ferramentas paa encontrar enganos no uso de memria dinmicamente o a alocada. Na seo subsequnte, mostramos como analizar o tempo de execuca e ca o de um programa usando o gerador de perl gprof. 312

A.2

Encontrando Erros de Memria Alocada o Dinmicamente a

Ao escrever um programa, voc frequantemente no pode saber quanta meme a o ria o programa ir precisar quando estiver sendo executado. Por exemplo, a uma linha lida de um arquivo na hora da execuo pode ter qualquer comprica mento nito. Programas em C e em C++ usam malloc, free, e suas variantes para alocar memria dinmicamente enquanto o programa est rodando. As o a a regras para o uso de memria dinmica incluem as seguintes: o a O nmero de chamadas de alocao (chamadas a malloc) deve exatau ca mente coincidir com o nmero de chamadas de desalocao (chamadas u ca a free). Leituras e escritas para a memria alocada devem ocorrer dentro da o memria alocada, no fora desse intervalo. o a A memria alocada no pode ser usada antes de ser alocada ou aps o a o ser desalocada. Pelo fato de alocao e desalocao dinmica de memria ocorrerem duca ca a o rante a execuo, a anlise esttica de programas raramente encontra vica a a olaes. Ao invs disso, ferramentas de vericao de memria executam o co e ca o programa, coletando dados para determinar se qualquer regra foi violada. As violaes que uma ferramenta pode encontrar incluem as seguintes: co Leitura da memria antes de aloc-la o a Escrita na memria antes de aloc-la o a Leitura antes do in da memria alocada cio o Escrita antes do in da memria alocada cio o Leitura aps o m da memria alocada o o Escrita aps o m da memria alocada o o Leitura da memria aps sua desalocao o o ca Escrita na memria aps sua desalocao o o ca Falha na desalocao da memria alocada ca o Desalocao da mesma memria duas vezes ca o 313

Desalocao de memria que no foi alocada ca o a E tambm importante alertar sobre requisitar uma alocao com 0 bytes, e ca a qual provavelmente indica erro do programador. A Tabela A.1 indica quatro diferentes capacidades de ferramentas de diagnstico. Desafortunadamente, nenhuma ferramenta simples diagnostica o todos os usos errados de memria. Tambm, nenhuma ferramenta alega deo e tectar leitura ou escrita antes de fazer a alocao de memria, mas fazendo ca o isso ir provavelmente causar uma falha de segmentao. Desalocao de a ca ca memria duas vezes ir provavelmente tambm causar uma falha de sego a e mentao. Essas ferramentas diagnosticam erros que atualmente ocorrem ca enquanto o programa est sendo executado. Se voc roda o programa sem a e entradas que faam com que nenhuma memria seja alocada, a ferramenta ir c o a indicar a voc que no existem erros de memria. Para testar um programa e a o completamente, voc deve executar o programa usando diferentes entradas e para garantir que todo poss caminho atravs do programa seja seguido. vel e Tambm, voc pode usar somente uma ferramenta de cada vez, de forma que e e voc ir ter que repetir o teste com muitas ferramentas para ter a melhor e a vericao de erro1 . ca

Nota do tradutor: veja no Apndice K Seo K.2 uma relao de analizadores de e ca ca cdigo. o

314

315

Tabela A.1: Capacidades das Ferramentas de Vericao Dinmica de Memria (X Indica Deteco, e O Indica ca a o ca Deteco para Alguns Casos) ca Comportamento Errneo o malloc Checking mtrace ccmalloc Eletric Fence Ler antes de alocar memria o Escrever antes de alocar memria o Ler antes do in da alocao cio ca X Escrever antes do in da alocao cio ca O O X Ler aps o m da alocao o ca X Escrever aps o m da alocao o ca X X Ler aps desalocar o X Escrever aps desalocar o X Falha ao desalocar memria o X Desalocar memria duas vezes o X X Desalocar memria no alocada o a X X Alocao de memria de tamanho zero ca o X X

Nas sees que seguem, primeiro descrevemos como usar os mais facilco mente usados malloc checking e mtrace, e ento ccmalloc e Electric Fence. a

A.2.1

Um Programa para Testar Alocao e ca Desalocao de Memria ca o

Iremos usar o programa malloc-use na listagem Listagem A.2 para ilustrar alocao de memria, desalocao de memria, e como usar a alocao e ca o ca o ca a desalocao. Para iniciar rode o programa malloc-use, especicando o ca nmero mximo de regies de memria alocada como seu unico argumento u a o o de linha de comando. Por exemplo, malloc-use 12 cria um array A com 12 apontadores de caractere que no apontam para nada. O programa aceita a cinco diferentes comandos: Para alocar b bytes apontados por meio de uma entrada de array A[i], insira a i b. O ndice de array i pode ser qualquer nmero no negativo u a menor que o argumento de linha de comando. O nmero de bytes deve u ser no negativo. a Para desalocar memria no o ndice de array i, insira d i. Para ler o p-simo caractere da memria alocada no e o ndice i (como em A[i][p]), insira r i p. Aqui, p pode ter um valor inteiro. Para escrever um caractere na p-sima posio na memria alocada no e ca o ndice i, insira w i p. Quando terminar, insira q. Iremos mostrar o cdigo do programa mais tarde, na Seo A.2.7, e iluso ca trar como us-lo. a

A.2.2

malloc Checking

As funes de alocao de memria fornecidas pela biblioteca C GNU padro co ca o a podem detectar escrita antes do in cio de uma alocao e desalocao da ca ca mesma alocao duas vezes. Denindo a varivel de ambiente MALLOC CHECK ca a para o valor 2 faz com que um programa pare ao ser detectado tal erro. (Note que a varivel de ambiente termina com uma sublinha.) No necessrio rea a e a compilar o programa. Ilustraremos o diagnstico de uma escrita para a memria em uma posio o o ca apenas antes do in de uma alocao. cio ca 316

% export MALLOC_CHECK_=2 % ./malloc-use 12 Please enter a command: a 0 10 Please enter a command: w 0 -1 Please enter a command: d 0 Aborted (core dumped) O comando export habilita malloc checking. Especicando o valor 2 faz com que o programa pare na hora em que um erro detectado. e O uso de malloc checking vantajoso pelo fato de o programa no pree a cisar ser recompilado, mas sua capacidade de diagnosticar erros limitada. e Basicamente, o programa malloc checking verica se a estrutura de dados do alocador no foi corrompida. Dessa forma, o programa malloc checking a pode detectar desalocao dupla da mesma alocao. Tambm, a escrita ca ca e apenas antes do in cio de uma alocao de memria pode comumente ser ca o detectada pelo fato de o alocador armazenar o tamanho de cada alocao de ca memria apenas antes da regio alocada. Dessa forma, escrita apenas antes o a da memria alocada ir corromper esse nmero. Desafortunadamente, veo a u ricao de consistncia pode ocorrer somente quando seu programa chama ca e rotinas de alocao, no quando seu programa acessa a memria, de forma ca a o que muitas leituras ilegais e escritas ilegais podem ocorrer antes de um erro ser detectado. No exemplo prvio, a escrita ilegal foi detectada somente e quando a memria alocada foi desalocada. o

A.2.3

Encontrando Vazamento de Memria Usando o mtrace

A ferramenta mtrace ajuda a diagnosticar o mais comum erro quando usamos memria dinmica: falha em corresponder, em termos numricos, as o a e alocaes e desalocaes. Existem quatro passos a serem seguidos para se co co usar mtrace, a qual est dispon com a biblioteca C GNU padro: a vel a 1. Modique o cdigo fonte incluindo <mcheck.h> e chame mtrace () to o a logo o programa inicie, no in da main. A chamada a mtrace habilita cio rastreamento de alocaes de memria e de desalocaes de memria. co o co o 2. Especique o nome de um arquivo para armazenar informao sobre ca todas as alocaes e desalocaes: co co % export MALLOC_TRACE=memory.log 317

3. Execute o programa. Todas a alocaes e desalocaes de memria so co co o a armazenadas no arquivo de registro de transaes memory.log. co 4. Usando o comando mtrace, analize as alocaes e as desalocaes de co co memria para garantir que elas coincidam. o % mtrace my_program $MALLOC_TRACE As mensagens produzidas por mtrace so relativamente fceis de entender a a Por exemplo, para o nosso exemplo malloc-use, a sa seria parecida com o da seguinte: - 0000000000 Free 3 was never allocd malloc-use.c:39 Memory not freed: ----------------Address Size 0x08049d48 0xc

Caller at malloc-use.c:30

Essas mensagens indicam uma tentativa na linha 39 de malloc-use.c para liberar memria que nunca foi alocada, e uma alocao de memria na lio ca o nha 30 que nunca foi liberada. O comando mtrace diagnostica erros tendo a gravao de toda a alocao e desalocao de memria feita pelo proca ca ca o grama executvel no arquivo especicado pela varivel de ambiente MALa a LOC TRACE. O executvel deve terminar normalmente para os dados sea rem escritos. O comando mtrace analiza esse arquivo e lista alocaes e co desalocaes no coincidentes. co a

A.2.4

Usando ccmalloc

A biblioteca ccmalloc diagnostica erros de memria alocada dinmicamente o a por meio da substituio de malloc e free com cdigo de rastreio de seu ca o uso. Se o programa termina elegantemente, ccmalloc produz um relatrio de o vazamento de memria e outros erros. A bilioteca ccmalloc foi escrita por o Armin Bierce. Voc ir provavelmente ter que baixar e instalar a biblioteca ccmalloc voc e a e mesmo. Pegue a ccmalloc a partir de http://www.inf.ethz.ch/personal/biere /projects/ccmalloc/, 2 descompacte o cdigo, e rode o script congure. exeo
Nota do tradutor: o endereo ainda vlido mas deu erro no navegador - 403 Forbidc e a den. Em http://www.lewatcher.com/ digite ccmalloc-0.4.0.tar.gz em Filename Search que aparecer uma srie de s a e tios onde o arquivo pode ser encontrado. O s original tio continua sendo citado na Internet mas est inaccess no presente momento. O tamanho a vel do arquivo que encontrei 57.917 bytes. e
2

318

cute a seguir o make e o make install, copie o arquivo ccmalloc.cfg para o diretrio onde voc ir executar o programa que voc deseja testar, e renoo e a e meie a cpia para .ccmalloc. Agora voc est pronto para usar a ferramenta. o e a Os arquivos objetos devem ser linkados com a biblioteca ccmalloc e com a biblioteca de linkagem dinmica3 . Anexe -lccmalloc -ldl a seu comando de a linkagem, por exemplo.
% gcc -g -Wall -pedantic malloc-use.o -o ccmalloc-use -lccmalloc -ldl

Execute o programa para produzir um relatrio. Por exemplo, executando o nosso programa malloc-use para alocar mas no desalocar memria produz a o o seguinte relatrio: o
% ./ccmalloc-use 12 file-name=a.out does not contain valid symbols trying to find executable in current directory ... using symbols from ccmalloc-use (to speed up this search specify file ccmalloc-use in the startup file .ccmalloc) Please enter a command: a 0 12 Please enter a command: q .---------------. |ccmalloc report| ======================================================== | total # of| allocated | deallocated | garbage | +-----------+-------------+-------------+---------------+ | 60 | 48 | 12 | bytes| +-----------+-------------+-------------+---------------+ |allocations| 2| 1| 1| +-------------------------------------------------------+ | number of checks: 1 | | number of counts: 3 | | retrieving function names for addresses ... done. | | reading file info from gdb ... done. | | sorting by number of not reclaimed bytes ... done. | | number of call chains: 1 | | number of ignored call chains: 0 | | number of reported call chains: 1 | | number of internal call chains: 1 | | number of library call chains: 0 | ======================================================== | *100.0% = 12 Bytes of garbage allocated in 1 allocation | | | | 0x400389cb in <???> | | | | 0x08049198 in <main> | | at malloc-use.c:89 | | | | 0x08048fdc in <allocate> | | at malloc-use.c:30 | | | -----> 0x08049647 in <malloc> | at src/wrapper.c:284 | ------------------------------------------------------

As ultimas poucas linhas indicam a sequncia de chamadas de funes e co que alocou memria que no foi desalocada. o a Para usr ccmalloc para diagnosticar escritas antes do in ou aps o m cio o da regio alocada, voc ir ter que modicar o arquivo .ccmalloc no diretrio a e a o 4 5 atual . Esse arquivo lido quando o programa inica sua execuo . e ca
Nota do tradutor: man dlltool. Nota do tradutor: onde o teste est sendo feito. a 5 Nota do tradutor: http://zentire.com/teaching/cs352 summer05/notes/ccmalloc-howto.pdf.
4 3

319

A.2.5

Electric Fence

Escrito por Bruce Perens, Electric Fence pra os programas que esto em a a execuo na linha exata do cdigo onde uma escrita ou leitura feita fora ca o e da rea de memria alocada ocorre. Essa a unica ferramenta que descoa o e bre leituras ilegais. O programa Eletric Fence est inclu nas maiorias a do da distribuies GNU/Linux, mas o cdigo fonte pode ser encontrado em co o http://www.perens.com/FreeSoftware/. Da mesma forma que ocorre com ccmalloc, seus arquivos objeto do programa devem ser linkados com a biblioteca do Electric Fence por meio da colocao no nal do comando de linkagem -lefence, por exemplo: ca
% gcc -g -Wall -pedantic malloc-use.o -o emalloc-use -lefence

Como o programa executa, os usos da memria alocada so vericados o a a ` procura de correes. Uma violao faz com que ocorra uma falha de co ca 6 segmentao : ca % ./emalloc-use 12 Electric Fence 2.0.5 Copyright (C) 1987-1998 Bruce Perens. Please enter a command: a 0 12 Please enter a command: r 0 12 Segmentation fault Usando um depurador, voc pode determinar o contexto da ao ilegal. e ca Por padro, Electric Fence diagnostica somente acessos aps o nal das a o alocaes. Para encontrar acessos antes do in das alocaes ao invs de co cio co e acessos aps o m das alocaes, use esse cdigo: o co o % export EF_PROTECT_BELOW=1 Para encontrar acessos a memria desalocada, ajuste EF PROTECT FR o EE para 1. Mais capacidades so descritas na pgina de manual libefence. a a Electric Fence diagnostica acessos legais ` memria atravs da armazea o e nagem de cada alocao em ao menos duas pginas de memria. least two ca a o memory pages. O Electric Fence coloca a alocao no m da primeira pgina; ca a qualquer acesso alm do m da alocao, na segunda pgina, causar uma e ca a a falha de segmentao. Se voc ajustou EF PROTECT BELOW para 1, o ca e Electric Fence coloca a alocao no in ca cio da segunda pgina ao invs de a e colocar na primeira pgina. Pelo fato de alocar duas pginas de memria a a o por chamada a malloc, o Electric Fence pode usar uma enorme quantidade de memria. Use essa biblioteca para depurao somente. o ca
Nota do tradutor: http://perens.com/FreeSoftware/ElectricFence/electric-fence 2.1.13-0.1.tar.gz
6

320

A.2.6

Escolhendo Entre as Diferentes Ferramentas Depuradoras de Memria o

Discutimos quatro ferramentas separadas e incompat veis ferramentas para diagnosticar uso errneo de memria dinmica. Como faz um programador o o a GNU/Linux para garantir que memria dinmica seja corretamente usada? o a Nenhuma ferramenta garante o diagnstico de todos os erros, mas usando o qualquer uma delas aumenta a possibilidade de encontrar erros. Para facilmente encontrar todos os erros de memria alocada dinmicamente, deo a senvolva separadamente o cdigo que manipula a memria dinmica. Esse o o a procedimento reduz o total de cdigo no qual voc deve procurar os erros. o e Se voc est usando C++, escreva uma classe que manipule todo o uso da e a memria dinmica. Se voc estiver usando C, minimize o nmero de funes o a e co usando alocao e desalocao. Ao testar esse cdigo, garanta usar somente ca ca o uma ferramenta de cada vez pelo fato de elas serem incompat veis. Ao testar um programa, garanta variao na forma como o programa executa, para ca testar a proo mais comumente executada do cdigo. ca o Qual das quatro ferramentas voc deve usar? Pelo fato de falhas de e correspondncia entre alocaes e desalocaes serem o erro mais comum de e co co alocao de memria dinmica, use mtrace durante o desenvolvimento inicial. ca o a O programa est dispon a vel em todos os sistemas GNU/Linux e tem sido bem testado. Aps a garantia de que o nmero de alocaes e desalocaes o u co co coincide, use Electric Fence para encontrar acessos ilegais ` memria. Essa a o pesquisa de acessos ilegais ` memria ir eliminar a maioria de todos os erros a o a de memria. Ao usar o Electric Fence, voc ir precisar ser cuidadoso no o e a a executar muitas alocaes e desalocaes pelo fato de cada alocao requerer co co ca pelo menos duas pginas de memria. Usando essas duas ferramentas ir a o a revelar a maioria dos erros de memria. o

A.2.7

Cdigo Fonte para o Programa de Memria o o Dinmica a

A Listagem A.2 mostra o cdigo fonte para um programa ilustrando alocao o ca e desalocao de memria dinmica, e como usar a memria dinmica. Veja a ca o a o a Seo A.2.1, Um Programa para Testar Alocao e Desalocao de Memria ca ca ca o para uma descrio de como usar alocao e desalocao de memra. ca ca ca o 321

Listagem A.2: (malloc-use.c) Exemplo de Como Testar Alocao ca Dinmica de Memria a o


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 / Use C s d y n a m i c memory a l l o c a t i o n functions . / specifying the to ( p o s s i b l y ) / I n v o k e t h e p r o g r a m u s i n g one commandl i n e s i z e o f an a r r a y . This array c o n s i s t s of allocated arrays . When t h e p r o g r a m m i n g commands : is running , select argument pointers

among t h e

following

o a l l o c a t e memory : a <i n d e x > <memorys i z e > o d e a l l o c a t e memory : d <i n d e x > o r e a d f r o m memory : r <i n d e x > < p o s i t i o n w i t h i n a l l o c a t i o n > o w r i t e t o memory : w <i n d e x > < p o s i t i o n w i t h i n a l l o c a t i o n > o quit : q The u s e r i s memory u s e . respond / for obeying ( or disobeying the r u l e s on d y n a m i c

#i f d e f MTRACE #include <mcheck . h> #e n d i f / MTRACE / #include <s t d i o . h> #include < s t d l i b . h> #include < a s s e r t . h> / A l l o c a t e memory w i t h success . / the specified size , returning n o n z e r o upon

void a l l o c a t e ( char a r r a y , { array = malloc ( s i z e ) ; } / D e a l l o c a t e memory . /

size t

size )

void d e a l l o c a t e ( char a r r a y ) { f r e e ( ( void ) a r r a y ) ; } / Read f r o m a p o s i t i o n i n memory . /

void r e a d f r o m m e m o r y ( char a r r a y , i n t p o s i t i o n ) { v o l a t i l e char c h a r a c t e r = a r r a y [ p o s i t i o n ] ; } / W r i t e to a position i n memory . / int position )

void w r i t e t o m e m o r y ( char a r r a y , { array [ position ] = a ; } i n t main ( i n t a r g c , char a r g v [ ] ) { char a r r a y ; unsigned a r r a y s i z e ; char command [ 3 2 ] ; unsigned a r r a y i n d e x ; char c o m m a n d l e t t e r ; int s i z e o r p o s i t i o n ; int e r r o r = 0 ; #i f d e f MTRACE mtrace ( ) ; #e n d i f / MTRACE / if ( a r g c != 2 ) { f p r i n t f ( s t d e r r , %s : return 1 ;

a r r a y s i z e \n , a r g v [ 0 ] ) ;

} a r r a y s i z e = s t r t o u l ( argv [ 1 ] , 0 , 0) ; a r r a y = ( char ) c a l l o c ( a r r a y s i z e , a s s e r t ( a r r a y != 0 ) ; / F o l l o w the u s e r s commands . /

sizeof

( char ) ) ;

322

Listagem A.3: (malloc-use.c) Exemplo de Como Testar Alocao ca Dinmica de Memria a o


79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 } while ( ! e r r o r ) { p r i n t f ( P l e a s e e n t e r a command : ) ; command letter = getchar ( ) ; a s s e r t ( c o m m a n d l e t t e r != EOF) ; switch ( c o m m a n d l e t t e r ) { case a : f g e t s ( command , s i z e o f ( command ) , s t d i n ) ; i f ( s s c a n f ( command , %u %i , &a r r a y i n d e x , & s i z e o r p o s i t i o n ) == 2 && a r r a y i n d e x < a r r a y s i z e ) a l l o c a t e (&( a r r a y [ a r r a y i n d e x ] ) , s i z e o r p o s i t i o n ) ; else error = 1; break ; case d : f g e t s ( command , s i z e o f ( command ) , s t d i n ) ; i f ( s s c a n f ( command , %u , &a r r a y i n d e x ) == 1 && a r r a y i n d e x < a r r a y s i z e ) d e a l l o c a t e (&( a r r a y [ a r r a y i n d e x ] ) ) ; else error = 1; break ; case r : f g e t s ( command , s i z e o f ( command ) , s t d i n ) ; i f ( s s c a n f ( command , %u %i , &a r r a y i n d e x , & s i z e o r p o s i t i o n ) == 2 && a r r a y i n d e x < a r r a y s i z e ) read from memory ( a r r a y [ a r r a y i n d e x ] , s i z e o r p o s i t i o n ) ; else error = 1; break ; case w : f g e t s ( command , s i z e o f ( command ) , s t d i n ) ; i f ( s s c a n f ( command , %u %i , &a r r a y i n d e x , & s i z e o r p o s i t i o n ) == 2 && a r r a y i n d e x < a r r a y s i z e ) write to memory ( array [ array index ] , s i z e o r p o s i t i o n ) ; else error = 1; break ; case q : f r e e ( ( void ) a r r a y ) ; return 0 ; default : error = 1; } } f r e e ( ( void ) a r r a y ) ; return 1 ;

A.3

Montando Perl

Agora que seu programa est (esperanosamente) correto, voltaremos nossa a c ateno para aumentar a velocidade de sua execuo. Usando o gerador de ca ca perl gprof, voc pode determinar quais funes requerem a maioria do tempo e co de execuo. O gerador de perl gprof pode ajudar voc a determinar quais ca e partes do programa otimizar ou reescrever para executar mais rapidamente. O gerador de perl gprof pode tambm ajudar voc a encontrar. Por exeme e plo, voc pode encontrar que uma particular funo chamada muito mais e ca e vezes que voc esperava. e 323

Nessa seo, descrevemos como usar o gerador de perl gprof. Reescreca vendo cdigo para executar mais rapidamente requer criatividade e cuidadosa o escolha de algor tmos. O ato de obter informao de perl requer trs passos: ca e 1. Compilar e linkar seu programa para habilitar a gerao de perl. ca 2. Execute seu programa para gerar dados de perl. 3. Use gprof para analizar e mostrar os dados de perl. Antes de ilustrarmos esses passos, introduziremos um programa grande o suciente para tornar a gerao do perl interessante. ca

A.3.1

Uma Calculadora Simples

Para ilustrar a gerao de um perl, usaremos um programa de calculadora ca simples. Para garantir que a calculadora use um montante de tempo no a trivial, usaremos nmeros unrios para os clculos, alguma coisa qque ns u a a o denitivamente no desejamos fazer em um programa do mundo real. O a cdigo para esse programa aparece no nal desse cap o tulo. Um nmero unrio representado por tantos s u a e mbolos quantos forem seu valor. Por exemplo, o nmero 1 representado por x 2 por xx e 3 por u e xxx. Ao invs de usar letras x, nosso programa representa um nmero e u no negativo usando uma lista encadeada com tantos elementos quantos o a valor do nmero. O arquivo number.c contm rotinas para criar o nmero u e u 0, adicionar 1 a um nmero, subtrair 1 de um nmero, e adicionar, subtrair, u u e multiplicar nmeros. Outra funo converte uma sequncia de caracteres u ca e realizando a converso de um nmero decimal no negativo para um nmero a u a u unrio, e uma funo converte de nmero unrio para int. A operao de a ca u a ca adio implementada usando repetidas adies da unidade, enquanto a ca e co subtrao usa repetidas remoes de unidades. A multiplicao denida ca co ca e usando adies repetidas. Os predicados unrios par e co a mpar cada um retorna o nmero unrio para 1 se e somente se seu unico operando for par ou u a mpar, respectivamente; de outra forma eles retornam o nmeo unrio para 0. Os u a dois predicados (par e mpar) so mutuamente exclusivos. Por exemplo, um a nmero par se for zero, ou se um nmero abaixo desse nmero for u e u u mpar. A calculadora aceita expresses com operador ps xado do tamanho de o o 7 uma linha e mostra o valor de cada expresso por exemplo: a
Na notao com operador ps xado, um operador binrio colocado aps seus ca o a e o operando ao invs de entre eles. De forma que, por exemplo, para multiplica 6 e 8, voc e e deve usaar 6 8 x . Para multiplicar 6 e 8 e ento adicionar 5 ao resultado, voc deve a e usar 6 8 5 +.
7

324

% ./calculator Please enter a postfix expression: 2 3 + 5 Please enter a postfix expression: 2 3 + 4 1 A calculadora, denida em calculator.c, l cada expresso, armazenando e a valores intermedirios em uma pilha de nmeros unrios, denida em stack.c. a u a a pilha armazena seus nmeros unrios em uma lista encadeada. u a

A.3.2

Coletando Informaes de Montagem de Perl co

O primeiro passo na montagem do perl de um programa fazer o compilador e incluir informaes adicionais em seus executveis para coletar informaes co a co de montagem de perl. Para fazer isso, use o sinalizador de compilao -pg ca ao fazer ambas a compilao dos arquivos objetos e a linkagem. Por exemplo, ca considere esse cdigo: o % % % % gcc gcc gcc gcc -pg -pg -pg -pg -c -o calculator.o calculator.c -c -o stack.o stack.c -c -o number.o number.c calculator.o stack.o number.o -o calculator

Isso habilita a coleta de informaes sobre chamadas a funes e inco co formaes de cronometragem. Para coletar informao de uso linha por linha, co ca tambm especique o sinalizador de depurao -g . Para contar blocos de e ca execuo bsicos, tais como o nmero de interaes em um do-loop, use o ca a u co sinalizador -a. O segundo passo executar o programa. Enquanto o programa est exee a cutando, dados de montagem de perl coletado em um arquivo chamado e gmon.out, somente para aquelas pores de cdigo que forem usadas. Voc co o e deve variar as entradas ou comandos do programa para executar as sees de co cdigo qu voc deseja montar o perl. O programa deve terminar normalo e mente para que o arquivo de montagem de perl seja escrito.

A.3.3

Mostrando Dados de Montagem de Perl

Fornecido o nome de um arquivo executvel, o gprof o arquivo gmon.out a para mostrar informaes sobre quanto tempo cada funo requereu. Por co ca 325

exemplo, considere os dados de montagem de perl de at para o clculo a de 1787 x 13 - 1918 usando nosso programa calculador, o qual produzido e por meio da execuo de gprof ./calculator : ca Flat profile: Each sample counts as 0.01 seconds.

% cumulative time seconds 26.07 1.76 24.44 3.41 19.85 4.75 15.11 5.77 14.37 6.74 0.15 6.75 0.00 6.75 0.00 6.75

self self seconds calls ms/call 1.76 20795463 0.00 1.65 1787 0.92 1.34 62413059 0.00 1.02 1792 0.57 0.97 20795463 0.00 0.01 1788 0.01 0.00 1792 0.00 0.00 11 0.00

total ms/call 0.00 1.72 0.00 2.05 0.00 0.01 0.00 0.00

name decrement_nu add zerop destroy_numb add_one copy_number make_zero empty_stack

Calculando a funo decrement number e todas as funes que decreca co ca ment number chama requereu 26.07% do total de tempo de execuo do programa. A funo decrement number foi chamada 20,795,463 vezes. Cada ca execuo individual requereu 0.0 segundos a saber, um tempo muito peca queno para se medir. A funo add foi chamada 1,787 ezes, presumivelmente ca para calcular o produto. Cada chamada requereu 0.92 segundos. A funo ca copy number function was invoked only 1,788 times, while it and the functions it calls required only 0.15% do total do tempo de execuo. Algumas ca vezes as funes mcount e prol usadas na montagem do perl aparecem nos co dados. Adicionalmente aos dados de perl de at, o qual indica o tempo total gasto dentro de cada funo, gprof produz o grco de chamadas mostrando ca a o tempo gasto em cada funo e seus processos lhos dentro do contexto de ca um encadeamento de chamada de funo: ca
self children called name <spontaneous> 0.00 6.75 main [1] 0.00 6.75 2/2 apply_binary_function [2] 0.00 0.00 1/1792 destroy_number [4] 0.00 0.00 1/1 number_to_unsigned_int [10] 0.00 0.00 3/3 string_to_number [12] 0.00 0.00 3/5 push_stack [16] 0.00 0.00 1/1 create_stack [18] 0.00 0.00 1/11 empty_stack [14] 0.00 0.00 1/5 pop_stack [15] 0.00 0.00 1/1 clear_stack [17] ----------------------------------------------[1] 100.0 index % time

326

0.00 6.75 2/2 main [1] 0.00 6.75 2 apply_binary_function [2] 0.00 6.74 1/1 product [3] 0.00 0.01 4/1792 destroy_number [4] 0.00 0.00 1/1 subtract [11] 0.00 0.00 4/11 empty_stack [14] 0.00 0.00 4/5 pop_stack [15] 0.00 0.00 2/5 push_stack [16] ----------------------------------------------0.00 6.74 1/1 apply_binary_function [2] [3] 99.8 0.00 6.74 1 product [3] 1.02 2.65 1787/1792 destroy_number [4] 1.65 1.43 1787/1787 add [5] 0.00 0.00 1788/62413059 zerop [7] 0.00 0.00 1/1792 make_zero [13] [2] 100.0

O primeiro quadro mostra que a execuo da funo main e seus lhos ca ca requereu 100% dos 6.75 segundos do programa. A funo main chamou ca a funo apply binary function duas vezes, que por sua vez foi chamada ca um total de duas vezes ao longo de todo o programa. Seu chamador foi <spontaneous>; isso indica que o gerador de perl no foi capaz de detera minar quem chamou a funo main. O primeiro quadro tambm mosta que ca e string to number chamou push stack trs vezes mas foi chamada cinco vezes e ao longo de todo o programa. O terceiro quadro mostra que a execuo da ca funo product e as funes que product chamou requer 99.8% do tempo toca co tal de execuo do programa. A funo product foi chamada uma vez por ca ca apply binary function. Os dados do grco de chamada mostram o tempo total gasto executando a uma funo e seus processos lhos. Se o grco de chamada de funo uma ca a ca e a rvore esse nmero fcil de calcular, mas funes denidas recursivamente u e a co devem ser tratadas especialmente. Por exemplo, a funo even chama a ca funo odd, a qual chama even. A cada ciclo de tal chamada fornecido ca e seu prprio nmero e mostrado individualmente nos dados do grco de o u e a chamada. Considere esses dados de gerao de perl obtidos na determinao ca ca de se 1787133 par: e
----------------------------------------------0.00 0.02 1/1 main [1] [9] 0.1 0.00 0.02 1 apply_unary_function [9] 0.01 0.00 1/1 even <cycle 1> [13] 0.00 0.00 1/1806 destroy_number [5] 0.00 0.00 1/13 empty_stack [17] 0.00 0.00 1/6 pop_stack [18] 0.00 0.00 1/6 push_stack [19] ----------------------------------------------[10] 0.1 0.01 0.00 1+69693 <cycle 1 as a whole> [10] 0.00 0.00 34847 even <cycle 1> [13] ----------------------------------------------34847 even <cycle 1> [13] [11] 0.1 0.01 0.00 34847 odd <cycle 1> [11] 0.00 0.00 34847/186997954 zerop [7] 0.00 0.00 1/1806 make_zero [16] 34846 even <cycle 1> [13]

O 1+69693 no quadro [10] indica que o ciclo 1 foi chamado uma vez, enquanto as funes no ciclo foram chamadas 69,693 vezes.O ciclo chamou a co funo even. A entrada seguinte mostra que a funo odd foi chamada 34,847 ca ca vezes pela funo even. ca 327

Nessa seo, discutimos brevemente somente alguns recursos do gprof. As ca pginas info do gprof contm informao sobre outros recursos uteis: a e ca

Use a opo -s para sumarizar os resultados de muitas diferentes execues. ca co Use a opo -c para identicar processos lhos que porderiam ter sido ca chamados mas no foram. a Use a opo -l para mostrar informao de gerao de perl linha por ca ca ca linha. Use a opo -A para mostrar cdigo fonte anotado com nmeros de ca o u porcentagem de execuo. ca

As pginas info tambm fornecem mais informao sobre a interpretao a e ca ca dos dados analizados.

A.3.4

Como gprof Coleta Dados

Quando um executvel cujo perl se quer estabelecer roda, a cada vez que a uma funo chamada seu contador tambm incrementado. Tambm, gprof ca e e e e periodicamente interrompe o executvel para determinar a funo que est a ca a sendo executada atualmente. Essas amostras determinam o nmero de vezes u que uma funo executada. Pelo fato de dois cliques seguidos do relgio do ca e o GNU/Linux terem a diferena entre s de 0.01 segundos, essas interrupes c co ocorrem, no mximo, a cada 0.01 segundo. Dessa forma, perf de programas a s que executam muito rapidamente ou para chamadas de funes rapidamente co e raramente executadas podem ser imprecisas. Para evitar essas imprecises, o rode o executvel por longos per a odos de tempo, ou sumarize juntos dados de perl de muitas execues. Leia sobre a opo -s para sumarizar dados de co ca gerao de perl na pgina info do gprof. ca a

A.3.5

Cdigo Fonte do Programa Calculadora o

A Listagem A.4 mostra um programa que calcula o valor de expresses com o operadores ps-xados. o 328

Listagem A.4: (calculator.c) Programa Principal da Calculadora


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 / C a l c u l a t e using u n a r y n um b e r s . / / E n t e r onel i n e e x p r e s s i o n s u s i n g r e v e r s e p o s t f i x n o t a t i o n , e . g . , 602 7 5 3 + N o n n e g a t i v e n u mb e r s a r e e n t e r e d u s i n g d e c i m a l n o t a t i o n . The o p e r a t o r s + , , and a r e s u p p o r t e d . The u n a r y o p e r a t o r s e v e n and odd r e t u r n t h e number one i f f i t s one o p e r a n d i s e v e n o r odd , r e s p e c t i v e l y . S p a c e s must s e p a r a t e a l l w o r d s . Negative n u mb e r s a r e n o t s u p p o r t e d . / #include #include #include #include #include <s t d i o . h> < s t d l i b . h> < s t r i n g . h> <c t y p e . h> d e f i n i t i o n s . h

/ A p p l y t h e b i n a r y f u n c t i o n p u s h i n g t h e a n s w e r on t h e int { apply binary function

w i t h o p e r a n d s o b t a i n e d from t h e s t a c k , stack . R e t u r n n o n z e r o upon s u c c e s s . /

( number ( f u n c t i o n ) ( number , number ) , Stack stack )

number operand1 , o p e r a n d 2 ; i f ( empty stack ( stack ) ) return 0 ; operand2 = p o p s t a c k ( s t a c k ) ; i f ( empty stack ( stack ) ) return 0 ; operand1 = p o p s t a c k ( s t a c k ) ; p u s h s t a c k ( s t a c k , ( f u n c t i o n ) ( operand1 , destroy number ( operand1 ) ; destroy number ( operand2 ) ; return 1 ; }

operand2 ) ) ;

/ A p p l y t h e u n a r y f u n c t i o n w i t h an o p e r a n d o b t a i n e d f r o m t h e s t a c k , p u s h i n g t h e a n s w e r on t h e s t a c k . R e t u r n n o n z e r o upon s u c c e s s . / int { number o p e r a n d ; i f ( empty stack ( stack ) ) return 0 ; operand = p o p s t a c k ( s t a c k ) ; p u s h s t a c k ( stack , ( f u n c t i o n ) ( operand ) ) ; destroy number ( operand ) ; return 1 ; } i n t main ( ) { char c o m m a n d l i n e [ 1 0 0 0 ] ; char c o m m a n d t o p a r s e ; char t o k e n ; Stack number stack = c r e a t e s t a c k apply unary function ( number ( f u n c t i o n ) ( number ) , Stack stack )

() ;

while ( 1 ) { p r i n t f ( P l e a s e e n t e r a p o s t f i x e x p r e s s i o n : \ n ) ; c o m m a n d t o p a r s e = f g e t s ( command line , s i z e o f ( c o m m a n d l i n e ) , i f ( c o m m a n d t o p a r s e == NULL) return 0 ; t o k e n = s t r t o k ( c o m m a n d t o p a r s e , \ t \n ) ; command to parse = 0 ; while ( t o k e n != 0 ) { i f ( i s d i g i t ( token [ 0 ] ) ) p u s h s t a c k (& n u m b e r s t a c k , s t r i n g t o n u m b e r ( t o k e n ) ) ; e l s e i f ( ( ( s t r c m p ( t o k e n , + ) == 0 ) && ! a p p l y b i n a r y f u n c t i o n (&add , &n u m b e r s t a c k ) ) | | ( ( s t r c m p ( t o k e n , ) == 0 ) && ! a p p l y b i n a r y f u n c t i o n (& s u b t r a c t , &n u m b e r s t a c k ) ) ( ( s t r c m p ( t o k e n , ) == 0 ) &&

stdin ) ;

||

329

Listagem A.5: (calculator.c) Continuao ca


75 ! a p p l y b i n a r y f u n c t i o n (& p r o d u c t , &n u m b e r s t a c k ) ) 76 ( ( s t r c m p ( t o k e n , e v e n ) == 0 ) && 77 ! a p p l y u n a r y f u n c t i o n (& even , &n u m b e r s t a c k ) ) | | 78 ( ( s t r c m p ( t o k e n , odd ) == 0 ) && 79 ! a p p l y u n a r y f u n c t i o n (&odd , &n u m b e r s t a c k ) ) ) 80 return 1 ; 81 t o k e n = s t r t o k ( c o m m a n d t o p a r s e , \ t \n ) ; 82 } 83 i f ( empty stack ( number stack ) ) 84 return 1 ; 85 else { 86 number a n s w e r = p o p s t a c k (& n u m b e r s t a c k ) ; 87 p r i n t f ( %u\n , n u m b e r t o u n s i g n e d i n t ( a n s w e r ) ) ; 88 destroy number ( answer ) ; 89 c l e a r s t a c k (& n u m b e r s t a c k ) ; 90 } 91 } 92 93 return 0 ; 94 } ||

As funes na Listagem A.6 implementam nmeros unrios usando listas co u a encadeadas vazias.

Listagem A.6: (number.c) Implementao de Nmero Unrio ca u a


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 / O p e r a t e on u n a r y n u mb e r s . #include #include #include #include < a s s e r t . h> < s t d l i b . h> < l i m i t s . h> d e f i n i t i o n s . h representing zero . / /

/ C r e a t e a number number m a k e z e r o { return 0 ; } / R e t u r n n o n z e r o ()

if

t h e number

represents

zero .

i n t z e r o p ( number n ) { return n == 0 ; } / D e c r e a s e a positive number b y one . /

number d e c r e m e n t n u m b e r ( number n ) { number a n s w e r ; a s s e r t ( ! zerop (n) ) ; a n s w e r = n >o n e l e s s ; free (n) ; return a n s w e r ; } / Add 1 t o a number . /

number a d d o n e ( number n ) { number a n s w e r = m a l l o c ( s i z e o f answer >o n e l e s s = n ; return a n s w e r ; } / D e s t r o y i n g a number . /

( struct LinkedListNumber ) ) ;

void d e s t r o y n u m b e r ( number n )

330

Listagem A.7: (number.c) Continuao ca


45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 { while ( ! z e r o p ( n ) ) n = decrement number ( n ) ; } / Copy a number . This allocation . / function is only needed because o f memory

number copy number ( number n ) { number a n s w e r = m a k e z e r o ( ) ; while ( ! z e r o p ( n ) ) { answer = add one ( answer ) ; n = n >o n e l e s s ; } return a n s w e r ; } / Add t w o n um b e r s . /

number add ( number n1 , number n2 ) { number a n s w e r = copy number ( n2 ) ; number addend = n1 ; while ( ! z e r o p ( addend ) ) { answer = add one ( answer ) ; addend = addend >o n e l e s s ; } return a n s w e r ; } / S u b t r a c t a number f r o m a n o t h e r . /

number s u b t r a c t ( number n1 , number n2 ) { number a n s w e r = copy number ( n1 ) ; number s u b t r a h e n d = n2 ; while ( ! z e r o p ( s u b t r a h e n d ) ) { a s s e r t ( ! z e r o p ( answer ) ) ; answer = decrement number ( answer ) ; subtrahend = subtrahend >o n e l e s s ; } return a n s w e r ; }

As funes na Listagem A.8 implementam uma pilha de nmeros unrios co u a usando uma lista encadeada. Listagem A.8: (stack.c) Pilha do Nmero Unrio u a
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 / P r o v i d e a s t a c k o f number s . / #include < a s s e r t . h> #include < s t d l i b . h> #include d e f i n i t i o n s . h / C r e a t e an empty Stack c r e a t e s t a c k { return 0 ; } / R e t u r n n o n z e r o stack . () /

if

the

stack

is

empty .

int empty stack ( Stack { return s t a c k == 0 ; } / Remove t h e number a t empty , a b o r t . / number p o p s t a c k

stack )

the

top

o f a nonempty

stack .

If

the

stack

is

( Stack stack )

331

Listagem A.9: (stack.c) Continuao ca


25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 { number a n s w e r ; Stack r e s t o f s t a c k ; a s s e r t ( ! empty stack ( stack ) ) ; a n s w e r = ( s t a c k )>e l e m e n t ; r e s t o f s t a c k = ( s t a c k )>n e x t ; f r e e ( stack ) ; stack = r e s t o f s t a c k ; return a n s w e r ; } / Add a number t o the beginning of a stack . /

void p u s h s t a c k ( S t a c k s t a c k , number n ) { Stack new stack = malloc ( s i z e o f ( struct StackElement ) ) ; >e new stack lement = n ; new stack >n e x t = s t a c k ; stack = new stack ; } / Remove all the stack s elements . /

Listagem A.10 contendo declaraes para pilhas e nmeros. co u Listagem A.10: (denitions.h) Header File for number.c and stack.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #i f n d e f DEFINITIONS H #d e f i n e DEFINITIONS H 1 / I m p l e m e n t a number u s i n g a l i n k e d l i s t . struct LinkedListNumber { struct LinkedListNumber one less ; }; typedef s t r u c t L i n k e d L i s t N u m b e r number ; / I m p l e m e n t a s t a c k o f number s a s a l i n k e d an empty s t a c k . / struct StackElement { number element ; struct StackElement n e x t ; }; typedef s t r u c t S t a c k E l e m e n t S t a c k ; / O p e r a t e on t h e s t a c k o f n um b e r s . / Stack c r e a t e s t a c k ( ) ; int empty stack ( Stack stack ) ; number p o p s t a c k ( S t a c k s t a c k ) ; void p u s h s t a c k ( S t a c k s t a c k , number n ) ; void c l e a r s t a c k ( S t a c k s t a c k ) ; / O p e r a t i o n s on n u mb e r s . / number m a k e z e r o ( ) ; void d e s t r o y n u m b e r ( number n ) ; number add ( number n1 , number n2 ) ; number s u b t r a c t ( number n1 , number n2 ) ; number p r o d u c t ( number n1 , number n2 ) ; number e v e n ( number n ) ; number odd ( number n ) ; number s t r i n g t o n u m b e r ( char c h a r n u m b e r ) ; unsigned n u m b e r t o u n s i g n e d i n t ( number n ) ; #e n d i f / DEFINITIONS H / /

list .

Use 0 t o

represent

332

Apndice B e E/S de Baixo N vel


PROGRAMADORES EM C NO GNU/LINUX POSSUEM DOIS CONJUNTOS DE FUNCOES DE ENTRADA/SA IDA ` sua disposio. A biblioteca a ca C GNU padro fornece funes de E/S: printf, fopen, e assim por diante1 . O a co kernel do GNU/Linux por s mesmo fornece outro conjunto de operaes de co E/S que trabalham em um n mais baixo que as funes da biblioteca C vel co GNU padro. a Pelo fato de esse livro ser para pessoas que j sabem a linguagem C, a assumiremos que voc tenha encontrado e saiba como usar as funes de E/S e co da biblioteca C GNU padro. a Muitas vezes existem boas razes para usar as funes de E/S de baixo o co n vel do kernel do GNU/Linux. Muitas dessas funes so chamadas de co a 2 sistema e fornecem a maioria das opes de acesso direto `s capacidades co a subjacentes do sistema que est dispon a programas de aplicao. De fato, a vel ca as rotinas da biblioteca C GNU padro de E/S so implementadas no topo a a das chamadas de sistema de E/S de baixo n do kernel do GNU/Linux. vel O uso das chamadas de sistema usualmente o caminho mais eciente para e executar operaes de entrada e sa e algumas vezes mais conveniente, co da e tambm. e Ao longo de todo esse livro, assumimos que voc est familiarizado com e a as chamadas descritas nesse apndice. Voc pode j estar familiarizado com e e a elas pelo fato de elas estarem muito prximas daquelas mesmas fornecidas o em outros sistemas operacionais UNIX e semelhantes ao UNIX (e na plantaforma Win32 tambm). Se voc no est familiarizado com elas, todavia, e e a a aprenda; voc ir encontrar o restante do livro mais fcil para entender se e a a
A biblioteca padro C++ fornece iostreams com funcionalidades similares. A biblioa teca C GNU padro est tambm dispon na linguagem C++. a a e vel 2 Veja Cap tulor 8, Chamadas de Sistema do GNU/Linux para uma explanao das ca diferenas entre uma chamada e uma chamada de funo comum. c ca
1

333

voc familiarizar-se por conta prpria com as chamadas de sistema primeirae o mente.

B.1

Lendo e Escrevendo Dados

A primeira funo de E/S que voc provavelmente encontrou quando voc ca e e inicialmente aprendeu a linguagem C foi printf. A printf formata um texto na forma de sequncia de caracteres e ento mostra o resultado da formatao e a ca na sa padro. A verso generalizada, a funo fprintf, pode imprimir um da a a ca texto para um uxo outro que no a sa padro. Um uxo representado a da a e por meio de um apontador do tipo FILE*. Voc obtm um apontador do e e tipo FILE* atravs da abertura de um arquivo com a funo fopen. Quando e ca voc tiver terminado, voc pode fechar o apontador do tipo FILE* com a e e funo fclose. Adicionalmente a fprintf, voc pode usar funes outras tais ca e co como fputc, fputs, e fwrite para escrever dados para o uxo, ou fscanf, fgetc, fgets, e fread para ler dados. Com as operaes de baixo n de E/S do GNU/Linux, voc usa um co vel e manipulador de funo chamado de um descritor de arquivos ao invs de um ca e apontador do tipo FILE*. Um descritor de arquivo um valor inteiro que se e refere a uma particular instncia de um arquivo aberto em um unico processo. a Esse descritor de arquivo pode ser aberto para leitura, para escrita, ou para ambos leitura e escrita. Um descritor de arquivos no tem que referir-se a a um arquivo aberto; um descritor de arquivo pode representar uma coneco ca com outro componente do sistema que capaz de enviar ou receber dados. e Por exemplo, uma coneco a um dispositivo de hardware representada por ca e um descritor de arquivo (veja Cap tulo 6, Dispositivos), como pode ser um socket aberto (veja Cap tulo 5, Comunicao Entre Processos Seo 5.5, ca ca Sockets) ou um m de um pipe (veja Seo 5.4, Pipes). ca Inclua os arquivos de cabealho <fcntl.h>, <sys/types.h>, <sys/stat.h>, c e <unistd.h> se voc usa qualquer das funes de E/S de baixo n descritas e co vel aqui.

B.1.1

Abrindo um Arquivo

Para abrir um arquivo e produzir um descritor de arquivo que pode acessar o referido arquivo, use a chamada a open. A chamada a open recebe como argumentos o nome do caminho do arquivo a ser aberto, como uma sequncia e de caracteres, e sinalizadores especicando como abrir o arquivo explicitado no nome do caminho. Voc pode usar open para criar um novo arquivo; se e voc quiser, informe um terceiro argumento que especica as permisses de e o 334

acesso a serem colocadas no novo arquivo. Se o segundo argumento for O RDONLY, o arquivo aberto para leitura e somente; um erro ir resultar se voc subsequntemente tentar escrever para a e e o descritor de arquivo resultante. Similarmente, O WRONLY faz com que o descritor de arquivo seja para escrita somente. Especicando O RDWR produz um descritor de arquivo que pode ser ambos para leitura e para escrita. Note que alguns arquivos no podem ser abertos em todos os trs modos. a e Por exemplo, as permisses sobre um arquivo j existente podem proibir um o a processo particular de abrir o arquivo desejado para leitura ou para escrita; um arquivo localizado em um dispositivo que pode ser lido somente tal como um acionador de CD-ROM no pode ser aberto para escrita. a Voc pode especicar opes adicionais por meio da utilizao de operaes e co ca co bit a bit ou desse valor com um ou mais sinalizadores. Esses so os valores a mais comumente usados: Especique O TRUNC para truncar o arquivo aberto, se o arquivo aberto j existir previamente. Dados escritos para o descritor de ara quivo iro substituir o contedo anterior do arquivo. a u Especique O APPEND para anexar ao nal de um arquivo que j a existe. Dados escritos para o descritor de arquivo iro ser adicionados a ao nal do arquivo. Especique O CREAT para criar um novo arquivo. Se o nome de arquivo que voc forneceu para ser aberto no existir, um novo arquivo e a ser criado, contanto que o diretrio que for receber o novo arquivo a o exista e que o processo tenha permisso para criar arquivos no diretrio a o de destino. se o arquivo j existir anteriormente, ele ser aberto ao invs a a e de criado. c ca Especique O EXCL com O CREAT para forar a criao de um novo arquivo. Se o arquivo j existir, a chamada a open ir falhar. a a Se voc chama open com O CREAT, fornea um adicional terceiro argue c mento especicando as permisses para o novo arquivo. Veja Cap o tulo 10, Segurana Seo 10.3, Permisses do Sistema de Arquivos para uma c ca o descrio dos bits de permisso e como us-los. ca a a Por exemplo, o programa na Listagem B.1 cria um novo arquivo com o nome de arquivo especicado na linha de comando.O programa na Listagem B.1 usa o sinalizador O EXCL com a open, de forma que se o arquivo existir anteriormente, um erro ir ocorrer. O novo arquivo fornecido com a e permisses de leitura e escrita para o proprietrio e o grupo proprietrio, o a a 335

e permisso de de leitura somente para os outros usurios. (Se sua umask a a for ajustada para um valor no nulo, as permisses atuais podem ser mais a o restritivas.)
Umasks Quando voc cria um novo arquivo com a open, alguns bits de permisso que e a voc especicou podem ser desabilitados. Isso ocorre pelo fato de sua umask e ser ajustada para um valor no nulo. Uma umask de processo especica bits a que so mascarados pelas permisses do arquivo criado recentemente. As a o permisses atuais usadas so operaes bit a bit e das permisses que voc o a co o e especicou a open e a operao de complemento bit a bit da umask. ca Para mudar sua umask a partir do shell, use o comando umask, e especique o valor numrico da mscara, na notao octal. Para mudar a umask para e a ca um processo que est executando no momento, use a chamada a umask, infora mando o valor de mscara desejado para ser usado por subsequntes chamadas a e a open. Por exemplo, chamando essa linha umask (S\_IRWXO | S\_IWGRP); em um programa, ou chamando esse comando % umask 027 especica que permisses de escrita para membros do grupo e permisses de o o leitura, escrita, e execuo para outros iro sempre ser mascaradas nas perca a misses de um novo arquivo. o

Listagem B.1: (create-le.c) Create a New File


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include #include #include #include #include < f c n t l . h> <s t d i o . h> <s y s / s t a t . h> <s y s / t y p e s . h> <u n i s t d . h>

i n t main ( i n t a r g c , char a r g v [ ] ) { / The p a t h a t w h i c h t o c r e a t e t h e new f i l e . / char path = a r g v [ 1 ] ; / The p e r m i s s i o n s f o r t h e new f i l e . / mode t mode = S IRUSR | S IWUSR | S IRGRP | S IWGRP | S IROTH ; / C r e a t e t h e f i l e . / i n t f d = open ( path , O WRONLY | O EXCL | O CREAT, mode ) ; i f ( f d == 1) { / An e r r o r o c c u r r e d . P r i n t an e r r o r m e s s a g e and b a i l . p e r r o r ( open ) ; return 1 ; } return 0 ; }

336

Aqui est o programa em ao: a ca % ./create-file testfile % ls -l testfile -rw-rw-r-1 samuel users 0 Feb % ./create-file testfile open: File exists

1 22:47 testfile

Note que o tamanho de novos arquivos 0 pelo fato de o programa no e a escrever qualquer dado no arquivo criado.

B.1.2

Fechando Descritores de Arquivo

Quando voc tiver terminado com um descritor de arquivo, feche esse dese critor com close. Em alguns casos, tais como o do programa na Listagem B.1, no necessrio chamar close explicitamente pelo fato de GNU/Linux a e a fechar todos os descritores de arquivo abertos quando um processo termina (isso , quando o programa termina). Certamente, uma vez que voc fecha e e um descritor de arquivo, voc no deve mais us-lo. e a a Fechando um descritor de arquivo pode fazer com que GNU/Linux tome uma ao em particular, dependendo da natureza do descritor de arquivo. ca Por exemplo, quando voc fecha um descritor de arquivo para um socket de e rede, GNU/Linux fecha a coneco de rede entre os dois computadores que ca esto se comunicando atravs do socket. a e GNU/Linux limita o nmero de descritores de arquivo abertos que um u processo pode ter aberto de uma s vez. Abrir descritores de arquivo usa o recursos do kernel, de forma que uma boa idia fechar descritores de arquivo e e quando voc tiver terminado com eles. Um limite t e pico 1.024 descritores e de arquivo por processo. Voc pode ajustar esse limite com a chamada de e sistema setrlimit; veja Seo 8.5, As Chamadas getrlimit e setrlimit: Limites ca de Recurso para mais informao. ca

B.1.3

Escrevendo Dados

Escrevemos dados para um descritor de arquivo usando a chamada a write. Fornea o descritor de arquivo, um apontador para um espao temporrio de c c a armazenagem de dados, e o nmero de bytes a serem escritos. O descritor de u arquivo deve ser aberto para escrita. Os dados escritos para o arquivo no a precisam ser uma sequncia de caracteres; escreva cpias arbitrrias de bytes e o a a partir do espao temporrio de armazenagem para o descritor de arquivo. c a O programa na Listagem B.2 anexa a hora atual para o arquivo especicado na linha de comando. Se o arquivo no existe, ele criado. esse a e 337

programa tambm utiliza as funes time, localtime, e asctime para obter e e co formatar a hora atual; veja suas respectivas pginas de manual para mais a informao. ca Listagem B.2: (timestamp.c) Anexa uma Timestamp a um Arquivo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include #include #include #include #include #include #include < f c n t l . h> <s t d i o . h> < s t r i n g . h> <s y s / s t a t . h> <s y s / t y p e s . h> <t i m e . h> <u n i s t d . h> string representing the current d a t e and t i m e . /

/ R e t u r n a c h a r a c t e r

char g e t t i m e s t a m p ( ) { t i m e t now = t i m e (NULL) ; return a s c t i m e ( l o c a l t i m e (&now ) ) ; } i n t main ( i n t a r g c , char a r g v [ ] ) { / The f i l e t o w h i c h t o a p p e n d t h e t i m e s t a m p . / char f i l e n a m e = a r g v [ 1 ] ; / Get t h e c u r r e n t t i m e s t a m p . / char timestamp = g e t t i m e s t a m p ( ) ; / Open t h e f i l e f o r w r i t i n g . I f i t e x i s t s , append t o i t ; o t h e r w i s e , c r e a t e a new f i l e . / i n t f d = open ( f i l e n a m e , O WRONLY | O CREAT | O APPEND, 0 6 6 6 ) ; / Compute t h e l e n g t h o f t h e t i m e s t a m p s t r i n g . / s i z e t l e n g t h = s t r l e n ( timestamp ) ; / W r i t e t h e t i m e s t a m p t o t h e f i l e . / w r i t e ( f d , timestamp , l e n g t h ) ; / A l l d o n e . / c l o s e ( fd ) ; return 0 ; }

Aqui est como o programa timestamp trabalha: a % ./timestamp tsfile % cat tsfile Thu Feb 1 23:25:20 2001 % ./timestamp tsfile % cat tsfile Thu Feb 1 23:25:20 2001 Thu Feb 1 23:25:47 2001 Note que a primeira vez que ns chamamos timestamp, foi criado o arquivo o tsle, enquanto a segunda vez o timestamp passou a adicionar entradas ao nal do tsle. A chamada a write retorna o nmero de bytes que foram escritos agora, u ou -1 se um erro tiver ocorrido. Para certos tipos de descritores de arquivo, o nmero de bytes atualmente escritos pode ser menor que o nmero de u u bytes requisitados. Nesse caso, cabe a voc chamar write novamente para e escrever o resto dos dados. A funo na Listagem B.3 demonstra como voc ca e 338

pode fazer isso. Note que para algumas aplicaes, voc pode ter de vericar co e condies especiais no meio da operao de escrita. Por exemplo, se voc est co ca e a escrevendo para um socket de rede, voc ir ter que ampliar essa funo para e a ca detectar se a coneco de rede foi fechada no meio da operao de escrita, e ca ca se a coneco de rede tiver sido fechada, para reativar a coneco de forma ca ca apropriada.

Listagem B.3: (write-all.c) Escreve Tudo de uma Area Temporria de a Armazenagem de Dados
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include < a s s e r t . h> #include <u n i s t d . h> / W r i t e a l l o f COUNT b y t e s f r o m BUFFER t o f i l e d e s c r i p t o r FD . R e t u r n s 1 on e r r o r , o r t h e number o f b y t e s w r i t t e n . / s s i z e t w r i t e a l l ( i n t f d , const void b u f f e r , s i z e t c o u n t ) { s i z e t l e f t t o w r i t e = count ; while ( l e f t t o w r i t e > 0 ) { s i z e t w r i t t e n = w r i t e ( fd , b u f f e r , count ) ; i f ( w r i t t e n == 1) / An e r r o r o c c u r r e d ; b a i l . / return 1; else / Keep c o u n t o f how much more we n e e d t o w r i t e . / l e f t t o w r i t e = w r i t t e n ; } / We s h o u l d h a v e w r i t t e n no more t h a n COUNT b y t e s ! / a s s e r t ( l e f t t o w r i t e == 0 ) ; / The number o f b y t e s w r i t t e n i s e x a c t l y COUNT. / return c o u n t ; }

B.1.4

Lendo Dados

A correspondente chamada para leitura de dados read. Da mesma forma e que write, a read recebe um descritor de arquivo, um aontador para um espao temporrio de armazenagem, e uma contagem. A contagem especic a ca quantos bytes so lidos do descritor de arquivo para dentro do espao a c temporrio de armazenagem. A chamada a read retorna -1 em caso de erro a ou o nmero de bytes lidos atualmente. Esse nmero de bytes lidos pode u u ser menor que o nmero de bytes requisitados, por exemplo, se no ouverem u a bytes sucientes no arquivo. 339

Lendo Arquivos Texto do DOS/Windows Aps ler esse livro, somos positivos no sentido de que voc ir escolher eso e a crever todos os seus programas para GNU/Linux. Todavia, seus programas podem ocasionalmente precisar ler arquivos texto gerados por programas DOS ou Windows. E importante antecipar uma diferena importante em como arc quivos texto so estruturados entre essas duas plantaformas. a Em arquivos texto GNU/Linux, cada linha separada da seguinte com um e caractere de nova linha. Uma nova linha representada por uma constante e do tipo caractere \n, a qual tem o cdigo ASCII 10. No Windows, todavia, o linhas so separadas por uma combinao de dois caracteres: um caractere de a ca retorno de carro (o caractere \r, o qual tem o cdigo ASCII 13), seguido por o um caractere de nova linha. Alguns editores de texto GNU/Linux mostram M ao nal de cada linha ao mostrar um arquivo de texto do Windows esse o caractere de retorno e de carro. Emacs mostra arquivos de texto do Windows de forma adequada mas indica-os mostrando (DOS) na linha de modo na parte inferior do espao c temporrio de armazenagem. Alguns editores Windows, tais como bloco de a notas, mostram todo o texto de um arquivo texto GNU/Linux em uma unica linha pelo fato de eles esperarem um caractere de retorno de carro ao nal de cada linha. Outros programas para ambos GNU/Linux e Windows que processam arquivos texto podem reportar erros misteriosos quando se fornece a eles como entrada um arquivo texto no formato inadequado. Se seu programa l arquivos de texto gerados por programas Windows, voc ir provavelmente e e a desejar substituir a sequncia \r\n por um unico caractere de nova linha. e Similarmente, se seu programa escreve arquivos de texto que devem ser lidos por programas Windows, substitua os caracteres isolados de nova linha por combinaes \r\n. Voc deve fazer isso se voc usa as chamadas de E/S de co e e baixo n mostradas nesse apndice ou se usa as funes de E/S da biblioteca vel e co C GNU padro. a

A Listagem B.4 fornece uma demonstrao simples de leitura. O proca grama imprime na tela uma remessa de hexadecimal do contedo do arquivo u especicado na linha de comando. Entre cada linha e a seguinte temos um deslocamento de 16 bytes. 340

Listagem B.4: (hexdump.c) Mostra uma Remessa de caracteres em Hexadecimal de um Arquivo


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include #include #include #include #include < f c n t l . h> <s t d i o . h> <s y s / s t a t . h> <s y s / t y p e s . h> <u n i s t d . h>

i n t main ( i n t a r g c , char a r g v [ ] ) { unsigned char b u f f e r [ 1 6 ] ; s i z e t offset = 0; s i z e t bytes read ; int i ; / Open t h e f i l e f o r r e a d i n g . / i n t f d = open ( a r g v [ 1 ] , O RDONLY) ; / Read f r o m t h e f i l e , one c h u n k a t a t i m e . Continue u n t i l read comes up s h o r t , i . e . r e a d s l e s s t h a n we a s k e d f o r . This i n d i c a t e s t h a t we v e h i t t h e end o f t h e f i l e . / do { / Read t h e n e x t l i n e s s w o r t h o f b y t e s . / b y t e s r e a d = read ( fd , b u f f e r , s i z e o f ( b u f f e r ) ) ; / P r i n t t h e o f f s e t i n t h e f i l e , f o l l o w e d b y t h e b y t e s t h e m s e l v e s . p r i n t f ( 0 x%06x : , o f f s e t ) ; f o r ( i = 0 ; i < b y t e s r e a d ; ++i ) p r i n t f ( %02x , b u f f e r [ i ] ) ; p r i n t f ( \n ) ; / Keep c o u n t o f o u r p o s i t i o n i n t h e f i l e . / o f f s e t += b y t e s r e a d ; } while ( b y t e s r e a d == s i z e o f ( b u f f e r ) ) ; / A l l d o n e . c l o s e ( fd ) ; return 0 ; } /

Aqui est hexdump em ao. Est mostrando uma remessa de seu prprio a ca a o arquivo executvel: a
% ./hexdump hexdump 0x000000 : 7f 45 4c 0x000010 : 02 00 03 0x000020 : e8 23 00 0x000030 : 1d 00 1a ... 46 00 00 00 01 01 00 06 01 00 00 00 01 00 00 00 00 00 00 00 00 c0 34 34 00 83 00 00 00 04 20 00 00 08 00 00 00 34 06 34 00 00 00 80 00 00 28 04 00 00 00 08

Sua sa pode ser diferente, dependendo do compilador que voc usou da e para compilar o hexdump e dos sinalizadores de compilao que voc especica e cou.

B.1.5

Movendo-se ao Longo de um Arquivo

Um descritor de arquivo lembra sua posio em um arquivo. Como voc l ca e e de ou escreve para o descritor de arquivo, sua posio avana correspondendo ca c do nmero de bytes que voc l ou escreve. Algumas vezes, todavia, voc u e e e ir precisar mover-se ao londo de um arquivo sem ler ou escrever dados. Por a exemplo, voc pode desejar escrever no meio de um arquivo sem modicar e o in cio, ou voc pode desejar pular de volta ao in de um arquivo e reler e cio sem a necessidade de reabrir o arquivo. 341

A chamada a lseek habilita voc a reposicionar um descritor de arquivo e em um arquivo. Informe a lseek o descritor de arquivo e dois argumentos adicionais especicando a nova posio. ca Se o terceiro argumento for SEEK SET, lseek interpreta o segundo argumento como uma posio, em bytes, a partir do in do arquivo. ca cio Se o terceiro argumento for SEEK CUR, lseek interpreta o segundo argumento como uma distncia, a qual pode ser positiva ou negativa, a a partir da posio atual. ca Se o terceiro argumento for SEEK END, lseek interpreta o segundo argumento como uma distncia a partir do nal do arquivo. Um valor a positivo indica uma posio para alm do nal do arquivo. ca e A chamada a lseek retorna a nova posio, como uma distncia a partir ca a do in do arquivo. O tipo de dado da distncia o t. Se um erro ocorrer, cio a e lseek retorna -1. Voc no pode usar lseek com alguns tipos de descritores e a de arquivo, tais como descritores de arquivo de socket. Se voc desejar encontrar a posio de um descritor de arquivo em um e ca arquivo sem modic-lo, especique uma distncia 0 a partir da posio atual a a ca por exemplo: off_t position = lseek (file_descriptor, 0, SEEK_CUR); GNU/Linux habilita voc a usar lseek para posicionar um descritor de e arquivo para alm do nal do arquivo. Normalmente, se um descritor de e arquivo est posicionado no nal de um arquivo e voc escreve para o descritor a e de arquivo, GNU/Linux automaticalmente expande o arquivo para dar lugar aos novos dados. Se voc posiciona um descritor de arquivo para alm do nal e e de um arquivo e ento escreve, GNU/Linux primeiro expande o arquivo para a acomodar a lacuna que voc criou com a operao lseek e ento escreve e ca a at o nal do arquivo. Essa lacuna, todavia, no ocupa espao atualmente e a c no disco; ao invs disso, GNU/Linux apenas faz uma anotao de tamanho e ca dessa lacuna. Se voc mais tarde tentar ler a partir do arquivo anotado, no e arquivo anotado ir aparecer que a lacuna est preenchida com 0 bytes. a a Usando esse comportamento de lseek, torna poss vel criar arquivos extremamente grandes que quase no ocupam nenhum espao no disco. O a c programa lseek-huge na Listagem B.5 faz isso. O programa lseek-huge recebe como argumentos de linha de comando um nome de arquivo e um tamanho de arquivo alvo, em megabytes. O programa abre um novo arquivo, avana c alm do nal usando lseek, e ento escreve um unico 0 byte antes de fechar o e a arquivo. 342

Listagem B.5: (lseek-huge.c) Cria Grandes Arquivos com lseek


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include #include #include #include #include < f c n t l . h> < s t d l i b . h> <s y s / s t a t . h> <s y s / t y p e s . h> <u n i s t d . h>

i n t main ( i n t a r g c , char a r g v [ ] ) { int zero = 0 ; const i n t megabyte = 1024 1 0 2 4 ; char f i l e n a m e = a r g v [ 1 ] ; s i z e t length = ( s i z e t ) atoi

( argv [ 2 ] )

megabyte ;

/ Open a new f i l e . / i n t f d = open ( f i l e n a m e , O WRONLY | O CREAT | O EXCL , 0 6 6 6 ) ; / Jump t o one b y t e s h o r t o f w h e r e we want t h e f i l e t o end . / l s e e k ( f d , l e n g t h 1 , SEEK SET ) ; / W r i t e a s i n g l e z e r o b y t e . / w r i t e ( f d , &z e r o , 1 ) ; / A l l d o n e . / c l o s e ( fd ) ; return 0 ; }

Usando lseek-huge, iremos fazer um arquivo de 1GB (1024MB). Note que o espao livre no acionador de disco antes e depois da operao. c ca
% df -h . Filesystem Size Used Avail Use% Mounted on /dev/hda5 2.9G 2.1G 655M 76% / % ./lseek-huge arquivogrande 1024 % ls -l arquivogrande -rw-r----1 samuel samuel 1073741824 Feb 5 16:29 arquivogrande % df -h . Filesystem Size Used Avail Use% Mounted on /dev/hda5 2.9G 2.1G 655M 76% /

No foi consumido nenhum espao aprecivel, apesar do enorme tamanho a c a do arquivogrande. Ainda, se abrirmos o arquivogrande e zermos uma leitura a partir dele, ele ir aparecer como sendo preenchido com 1GB de valores 0s. a Por exemplo, podemos examinar seu contedo com o programa hexdump da u Listagem B.4.
% ./hexdump bigfile | head -10 0x000000 : 00 00 00 00 00 00 00 0x000010 : 00 00 00 00 00 00 00 0x000020 : 00 00 00 00 00 00 00 0x000030 : 00 00 00 00 00 00 00 0x000040 : 00 00 00 00 00 00 00 0x000050 : 00 00 00 00 00 00 00 ... 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Se voc executar esse arquivo voc mesmo, ir provavelmente desejar e e a encerrar o programa com Ctrl+C, em lugar de assistir o programa mostrar 230 vezes 0 bytes. Note que essas lacunas mgicas em arquivos so um recurso especial do a a sistema de arquivo ext2 que tipicamene usado em discos GNU/Linux. Se e voc tentar usar lseek-huge para criar um arquivo em algum outro tipo de e sistema de arquivo, tais como o fat ou o vfat usados para montar parties co 343

DOS e Windows, ir encontrar que o arquivo resultante ocupa atualmente a todo o montante de espao do disco3 . c GNU/Linux no permite a voc voltar para antes do in de um arquivo a e cio com lseek.

B.2

stat

Usando open e read, voc pode extrair o contedo de um arquivo. Mas e u como extrair informaes sobre os arquivos? Por exemplo, chamando ls -l co mostra, para os arquivos no diretrio atual, informaes como tamanho do o co arquivo, a hora da ultima modicao, permisses, e o proprietrio. ca o a A chamada a stat obtm essa informao sobre um arquivo. Chame stat e ca com o caminho para o arquivo que lhe interessa e um apontador para uma varivel do tipo struct stat. Se a chamada a stat obtiver sucesso, ir retornar a a o valor 0 e preencher os campos da estrutura com informaes sobre aquele co arquivo; de outra forma, a chamada a stat retorna -1. Esses so os campos mais uteis em struct stat: a st mode contm as permisses de acesso do arquivo. Permisses de e o o arquivo so explicadas na Seo 10.3, Permisses do Sistema de Ara ca o quivos. Adicionalmente `s permisses de acesso, o campo st mode codica o a o tipo do arquivo em bits de alta ordem . Veja o texto que segue imediatamente os itens para instrues sobre como decodicar essa informao. co ca st uid e st gid possuem os IDs de usurio e grupo, respectivamente, aos a quais o arquivo pertence. Os IDs de usurios e de grupos so descritos a a na Seo 10.1, Usurios e Grupos. ca a st size contm o tamanho do arquivo, em bytes. e st atime contm a ultima data e hora na qual o arquivo foi acessado e (ou leitura ou escrita). e ca st mtime contm a data e a hora da ultima modicao. Essa macros vericam o valor do campo st mode para mostrar que tipo de arquivo sobre o qual voc chamou stat. Uma macro avalia para true se o e arquivo do tipo da macro usada. e
3

Nota do tradutor: no ext4 e no reiserfs funcionou tambm. e

344

S ISBLK (modo) dispositivo de bloco S ISCHR (modo) dispositivo de caractere o S ISDIR (modo) diretrio S ISFIFO (modo) fo (ipe nomeado) S ISLNK (modo) link simblico o S ISREG (modo) arquivo regular S ISSOCK(modo) socket O campo st dev contm o nmero de dispositivo principal e secundrio e u a do dispositivo de hardware sobre o qual o arquivo localiza-se.Nmeros de u dispositivo so discutidos no Cap a tulo 6. O nmero de dispositivo princiu pal corresponde aos 8 bits mais para a esquerda; o nmero de dispositivo u e secundrio ocupa os 8 bits menos signicativos. O campo st ino contm o a nmero do inode desse arquivo. Esse nmero de inode localiza o arquivo no u u sistema de arquivos. Se voc chama stat sobre um link simblico, stat segue o link e voc e o e pode obter informao sobre o aruivo para o qual o link aponta, no sobre ca a a o link simblico propriamente dito. Isso implica que S ISLNK nunca ir ser o verdadeira par o resultado de stat. Use a funo lstat se voc no deseja seguir ca e a links simblicos; essa funo obtm informao sobre o link propriamente o ca e ca dito em lugar de obter informaes sobre o alvo do link. Se voc chama lstat co e sobre um arquivo que no um link simblico, o comportamento de lstat o a e o e mesmo que o de stat. Chamando stat sobre um link quebrado (um link que aponta para um alvo inexistente ou inacess vel) resulta em um erro, enquanto chamar lstat sobre tal link no causa erro. a Se voc j tem um arquivo aberto para leitura ou escrita, chame fstat e a ao invs de chamar stat. A fstat recebe um descritor de arquivo como seu e primeiro argumento ao invs de um caminho. e A Listagem B.6 mostra uma funo que aloca um espao temporrio de ca c a armazenagem grande o suciente para manter o contedo de um arquivo e u ento ler o arquivo dentro do espao temporrio de armazenagem. A funo a c a ca usa fstat para determinar o tamanho do espao temporrio de armazenagem c a que a funo precisa para fazer a alocao e tambm para vericar que o ca ca e arquivo realmente um arquivo regular. e 345

Listagem B.6: (read-le.c) L um Arquivo para dentro de um Espao e c Temporrio de Armazenagem a


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include #include #include #include #include #include < f c n t l . h> <s t d i o . h> < s t d l i b . h> <s y s / s t a t . h> <s y s / t y p e s . h> <u n i s t d . h>

/ Read t h e c o n t e n t s o f FILENAME i n t o a n e w l y a l l o c a t e d b u f f e r . The s i z e o f t h e b u f f e r i s s t o r e d i n LENGTH. Returns the b u f f e r , which t h e c a l l e r must f r e e . I f FILENAME d o e s n t c o r r e s p o n d t o a r e g u l a r f i l e , r e t u r n s NULL . / char r e a d f i l e ( const char f i l e n a m e , { int fd ; struct s t a t f i l e i n f o ; char b u f f e r ; / Open t h e f i l e . / f d = open ( f i l e n a m e , O RDONLY) ; / Get i n f o r m a t i o n a b o u t t h e f i l e . / f s t a t ( fd , & f i l e i n f o ) ; length = f i l e i n f o . s t s i z e ; / Make s u r e t h e f i l e i s an o r d i n a r y f i l e . i f ( ! S ISREG ( f i l e i n f o . s t m o d e ) ) { / I t s n o t , s o g i v e up . / c l o s e ( fd ) ; return NULL ; } / A l l o c a t e a b u f f e r l a r g e e n o u g h t o h o l d b u f f e r = ( char ) m a l l o c ( l e n g t h ) ; / Read t h e f i l e i n t o t h e b u f f e r . / read ( fd , b u f f e r , l e n g t h ) ; / F i n i s h up . / c l o s e ( fd ) ; return b u f f e r ; } s i z e t length )

the

file s

contents .

B.3

Leituras e Escritas de Vetor

A chamada a write recebe como argumentos um apontador para o in cio do espao temporrio de armazenagem de dados e o comprimento do refec a rido espao temporrio de armazenagem. A chamada a write escreve sobre c a uma regio cont a nua de memria para o descritor de arquivo. Todavia, um o programa muitas vezes ir precisar escrever muitos itens de dado, cada um a residindo em uma diferente parte da memria. Para usar write, o programa o ou ir ter de copiar os itens para uma unica regio de memria, a qual obvia a o amente torna uso ineciente dos ciclos de CPU e da memria, ou ir ter que o a fazer multiplas chamadas a write. Para algumas aplicaes, multiplas chamadas a write so inecientes ou co a indesejveis. Por exemplo, ao escrever para um socket de rede, duas chaa madas a write podem fazer com que dois pacotes sejam enviados atravs da e rede, onde os mesmos dados poderiam ser enviados em um pacote unico se uma chamada unica para write fosse poss vel. A chamada a writev habilita voc a escrever multiplas regies descont e o nuas de memria para um descritor o 346

de arquivo em uma operao unica. Essa escrita de diversas regies chaca o e mada escrita de vetor. O custo de usar writev que voc deve ajustar uma e e estrutura de dados especicando o in e o comprimento de cada regio de cio a memria. Essa estutura de dados um array de elementos struct iovec. Cada o e elemento especica uma regio de memria a ser escrita; os campos iov base e a o iov len especicam o endereo do in da regio e o comprimento da regio, c cio a a respectivamente. Se voc conhece previamente quantas regies voc ir pree o e a cisar, voc pode simplesmente declarar uma varivel do tipo struct iovec; se e a o nmero de regies pode variar, voc deve alocar o array dinmicamente. u o e a

Chame writev informando um descritor de arquivo para o qual voc vai e escrever, o array do tipo struct iovec, e o nmero de elementos no array. O u valor de retorno o nmero total de bytes escritos. e u

O programa na Listagem B.7 escreve seus argumentos de linha de comando para um arquivo usando uma unica chamada a writev. O primeiro argumento o nome do arquivo; o segundo e os subsequntes argumentos e e so escritos para o arquivo com o nome informado no primeiro argumento, a um argumento por linha. O programa aloca um array com elementos do tipo struct iovec que duas vezes mais longo que o nmero de argumentos e u que o programa est escrevendo para cada argumento o programa escreve a o texto do argumento propriamente dito bem como um caractere de nova linha. Pelo fato de no sabermos o nmero de argumentos previamente, o a u vetor alocado usando malloc. e 347

Listagem B.7: (write-args.c) Escreve a Lista de Argumentos para um Arquivo com writev
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #include #include #include #include #include #include < f c n t l . h> < s t d l i b . h> <s y s / s t a t . h> <s y s / t y p e s . h> <s y s / u i o . h> <u n i s t d . h>

i n t main ( i n t a r g c , char a r g v [ ] ) { int fd ; struct i o v e c vec ; struct i o v e c v e c n e x t ; int i ; / We l l n e e d a b u f f e r c o n t a i n i n g a n e w l i n e c h a r a c t e r . Use an ordinary char v a r i a b l e f o r t h i s . / char n e w l i n e = \n ; / The f i r s t commandl i n e a r g u m e n t i s t h e o u t p u t f i l e n a m e . / char f i l e n a m e = a r g v [ 1 ] ; / S k i p p a s t t h e f i r s t t w o e l e m e n t s o f t h e a r g u m e n t l i s t . Element z e r o i s t h e name o f t h i s program , and e l e m e n t one i s t h e o u t p u t filename . / a r g c = 2 ; a r g v += 2 ; / A l l o c a t e an a r r a y o f i o v e c e l e m e n t s . We l l n e e d t w o f o r e a c h e l e m e n t o f t h e a r g u m e n t l i s t , one f o r t h e t e x t i t s e l f and one a newline . / vec = ( struct i o v e c ) malloc (2 argc s i z e o f ( struct i o v e c ) ) ;

for

/ Loop o v e r t h e a r g u m e n t l i s t , b u i l d i n g t h e i o v e c e n t r i e s . / vec next = vec ; f o r ( i = 0 ; i < a r g c ; ++i ) { / The f i r s t e l e m e n t i s t h e t e x t o f t h e a r g u m e n t i t s e l f . / vec next o v b a s e = argv [ i ] ; >i vec next o v l e n = s t r l e n ( argv [ i ] ) ; >i ++v e c n e x t ; / The s e c o n d e l e m e n t i s a s i n g l e n e w l i n e c h a r a c t e r . I t s OK f o r m u l t i p l e elements of the s t r u c t iovec array to point to the same r e g i o n o f memory . / v e c n e x t o v b a s e = &n e w l i n e ; >i vec next o v l e n = 1; >i ++v e c n e x t ; } / W r i t e t h e a r g u m e n t s t o a f i l e . / f d = open ( f i l e n a m e , O WRONLY | O CREAT) ; w r i t e v ( f d , vec , 2 a r g c ) ; c l o s e ( fd ) ; f r e e ( vec ) ; return 0 ; }

Aqui est um exemplo de execuo do programa write-args. a ca


% ./write-args outputfile "primeiro arg" "segundo arg" "terceiro arg" % cat outputfile primeiro arg segundo arg terceiro arg

GNU/Linux fornece uma funo correspondente readv que l em uma ca e operao unica multiplas regies descont ca o nuas de memria. Similar a writev, o um array de elementos do tipo struct iovec especica as regies de memria o o nas quais os dados iro ser lidos a partir do descritor de arquivo. a 348

B.4

Relao de Funoes de E/S da Biblioteca ca c C GNU Padro a

Mencionamos anteriormente que as funes de E/S da biblioteca C GNU co padro so implementadas sobre o topo dessas funes de E/S de baixo n a a co vel. Algumas vezes, apesar disso, conveniente usar funes da biblioteca padro e co a com descritores de arquivo, ou usar funes de E/S de baixo n sobre um co vel uxo de biblioteca C GNU padro do tipo FILE*. GNU/Linux habilita voc a e a fazer ambos. Se voc tiver aberto um arquivo usando fopen, voc pode obter o descritor e e de arquivo respectivo usando a funo leno. A funo leno recebe um ca ca argumento FILE* e retorna o descritor de arquivo. Por exemplo, para abrir um arquivo com a chamada fopen da biblioteca C GNU padro mas escrever a para esse arquivo com writev, voc pode usar esse cdigo: e o FILE* fluxo = fopen (nomearquivo, "w"); int descritor_arquivo = fileno (fluxo); writev (descritor_arquivo, vetor, comprimento_vetor); Note que uxo e descritor arquivo correspondem ao mesmo arquivo aberto. Se voc chamar a linha adiante, voc no pode mais escrever para descrie e a tor arquivo: fclose (fluxo); Similarmente, se voc chama a linha adiante, voc no pode mais escrever e e a para uxo: close (descritor_arquivo); Indo por outro caminho, de um descritor de arquivo para um uxo, use a funo fdopen. A funo fdopen constri um apontador do tipo FILE* ca ca o uxo correspondendo a um descritor de arquivo. A funo fdopen recebe ca um argumento que um descritor de arquivo e um argumento do tipo seq e para uncia de caracteres especicando o modo no qual para ser criado o e e uxo. A sintaxe do argumento que especica o modo a mesma que a do e segundo argumento a fopen, e esse argumento que especica o modo deve ser compat com o descritor de arquivo. Por exemplo, especique um modo vel r para um descritor de arquivo de leitura ou w para um descritor de arquivo de escrita. Da mesma forma que leno, o uxo e o descritor de arquivo devem referir-se ao mesmo arquivo aberto, de forma que se voc e fechar um, voc no pode subsequntemente usar o outro. e a e 349

B.5

Outras Operaoes de Arquivo c

Umas poucas outras operaes sobre aruivos e diretrios so adequadas: co o a getcwd obtm o diretrio atual de trabalho. A getcwd recebe dois e o argumentos, um do tipo char que especica o espao temporrio de c a armazenagem e o comprimento do espao temporrio de armazenagem. c a A getcwd copia o caminho do diretrio de trabalho atual paa dentro do o espao temporrio de armazenagem. c a chdir muda o diretrio de trabalho atual para o caminho fornecido o como seu argumento. mkdir cria um novo diretrio. Seu primeiro argumento o caminho o e do novo diretrio. Seu segundo argumento as permisses de acesso o e o a serem usadas para o novo diretrio. A interpretao das permisses o ca o so as mesmas que as do terceiro argumento a open e so modicados a a pela umask do processo. rmdir apaga um diretrio. Seu argumento o caminho do diretrio. o e o unlink apaga um arquivo. Seu argumento o caminho para o arquivo. e Essa chamada pode tambm ser usada para apagar outros objetos do e sistema de arquivos, tais como pipes nomeados (veja Seo 5.4.5, FIca FOs) ou dispositivos (veja Cap tulo 6). Atualmente, unlink no nea cessriamente apaga o contedo do arquivo. Como mostra seu nome, a a u unlink desmancha o link para o arquivo do diretrio que o contm. O o e arquivo no mais listado naquele diretrio, mas se qualquer processo a e o mantiver um descritor de arquivo aberto para o arquivo, o contedo do u arquivo no removido do disco. Somente quando nenhum processo a e tiver um descritor de arquivo aberto que o contedo do arquivo e u e apagado. De forma que, se um processo abre um arquivo para leitura ou escrita ento um segundo processo chama unlink sobre o arquivo a e cria um novo arquivo cm o mesmo nome, o primeiro processo v o e contedo antigo do arquivo em lugar de o contedo novo (a menos que u u o processo antigo feche o arquivo antigo e reabra-o em seguida). rename renomeia ou move um arquivo. Seus dois argumentos so o a caminho antigo e o caminho novo para o arquivo. Se os caminhos estiverem em diferentes diretrios, rename move o arquivo, enquanto o ambos estiverem no mesmo sistema de arquivo. Voc pode usar rename e para mover diretrios ou outros objetos de sistema de arquivo tambm. o e 350

B.6

Lendo o Conte do de um Diretrio u o

GNU/Linux fornece funes para ler contedos de diretrios. Ambora essas co u o funes no sejam diretamente relacionadas com as funes de E/S de baixo co a co n descritas nesse apndice, vamos mostr-las aqui de qualquer forma pelo vel e a fato de elas serem muitas vezes uteis em programas de aplicaes. co Para ler o contedo de um diretrio, siga esses passos: u o

1. Chame opendir, informando o caminho do diretrio que voc deseja o e examinar. A chamada a opendir retorna um manipulador DIR*, o qual voc ir usar para acessar o contedo do diretrio. Se um erro e a u o ocorrer, a chamada retorna NULL.

2. chame readdir repetidamente, informando o manipulador DIR* que voc obteve de opendir. Cada vez que voc chama readdir, a readdir e e retorna uma instncia de apontador para uma estrutura do tipo struct a dirent correspondendo ` entrada seguinte do diretrio. Quando voc a o e encontra o m do contedo do diretrio, readdir retorna NULL. A u o struct dirent que voc pegou de volta a partir de readdir tem um campo e d name, o qual contm o nome da entrada de diretrio. e o

3. Chame closedir, informando o manipulador DIR*, para terminar a operao de listagem de diretrio. ca o

Inclua <sys/types.h> e <dirent.h> se voc usa essas funes em seu e co programa. Note que se voc precisa do contedo do diretrio arrumado em uma e u o ordem em particular, voc ir ter que organiz-la voc mesmo. e a a e O programa na Listagem B.8 mostra o contedo de um diretrio. O u o diretrio pode ser especicado na linha de comando, mas se no for espeo a cicado, o programa usa o diretrio atual de trabalho. Para cada entrada o no diretrio, o programa mostra o tipo da entrada e seu caminho. A funo o ca get le type usa lstat para determinar o tipo de uma entrada do sistema de arquivo. 351

Listagem B.8: (listdir.c) Print a Directory Listing


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 #include #include #include #include #include #include #include < a s s e r t . h> <d i r e n t . h> <s t d i o . h> < s t r i n g . h> <s y s / s t a t . h> <s y s / t y p e s . h> <u n i s t d . h> string that describes the type of the file system e n t r y PATH. /

/ R e t u r n a

const char g e t f i l e t y p e ( const char path ) { struct s t a t s t ; l s t a t ( path , &s t ) ; i f ( S ISLNK ( s t . s t m o d e ) ) return s y m b o l i c l i n k ; e l s e i f ( S ISDIR ( s t . s t m o d e ) ) return d i r e c t o r y ; e l s e i f ( S ISCHR ( s t . s t m o d e ) ) return c h a r a c t e r d e v i c e ; e l s e i f ( S ISBLK ( s t . s t m o d e ) ) return b l o c k d e v i c e ; e l s e i f ( S ISFIFO ( s t . s t m o d e ) ) return f i f o ; e l s e i f ( S ISSOCK ( s t . s t m o d e ) ) return s o c k e t ; e l s e i f ( S ISREG ( s t . s t m o d e ) ) return r e g u l a r f i l e ; else / U n e x p e c t e d . Each e n t r y s h o u l d b e one o f assert (0) ; } i n t main ( i n t a r g c , char a r g v [ ] ) { char d i r p a t h ; DIR d i r ; struct d i r e n t entry ; char e n t r y p a t h [PATH MAX + 1 ] ; s i z e t path len ;

the

types

above .

( a r g c >= 2 ) / I f a d i r e c t o r y was s p e c i f i e d on t h e command l i n e , u s e i t . / d i r p a t h = argv [ 1 ] ; else / O t h e r w i s e , u s e t h e c u r r e n t d i r e c t o r y . / dir path = . ; / Copy t h e d i r e c t o r y p a t h i n t o e n t r y p a t h . / strncpy ( entry path , dir path , sizeof ( entry path ) ) ; path len = strlen ( dir path ) ; / I f t h e d i r e c t o r y p a t h d o e s n t end w i t h a s l a s h , a p p e n d a s l a s h . i f ( e n t r y p a t h [ p a t h l e n 1 ] != / ) { entry path [ path len ] = / ; e n t r y p a t h [ p a t h l e n + 1 ] = \0 ; ++p a t h l e n ; } / S t a r t t h e l i s t i n g o p e r a t i o n o f t h e d i r e c t o r y s p e c i f i e d on t h e command l i n e . / dir = opendir ( dir path ) ; / Loop o v e r a l l d i r e c t o r y e n t r i e s . / while ( ( e n t r y = r e a d d i r ( d i r ) ) != NULL) { const char t y p e ; / B u i l d t h e p a t h t o t h e d i r e c t o r y e n t r y b y a p p e n d i n g t h e e n t r y name t o t h e p a t h name . / strncpy ( entry path + path len , entry >d name , sizeof ( entry path ) path len ) ; / D e t e r m i n e t h e t y p e o f t h e e n t r y . / type = g e t f i l e t y p e ( entry path ) ; / P r i n t t h e t y p e and p a t h o f t h e e n t r y . / p r i n t f ( %18s : %s \n , type , e n t r y p a t h ) ; } / A l l d o n e . / closedir ( dir ) ; return 0 ; }

if

Aqui est as primeiras poucas linhas de sa da listagem do diretrio a da o 352

/dev. (Sua sa pode diferir um pouco.) da % ./listdir /dev directory directory socket character device regular file fifo character device ...

: : : : : : :

/dev/. /dev/.. /dev/log /dev/null /dev/MAKEDEV /dev/initctl /dev/agpgart

Para vericar isso, voc pode usar o comando ls no mesmo diretrio. e o Especique o sinalizador -U para instruir o comando ls no ordenar entradas, a e especique o sinalizador -a para fazer com que o diretrio atual (.) e o o diretrio pai (..) sejam inclu o dos.
% ls -lUa /dev total 124 drwxr-xr-x 7 drwxr-xr-x 22 srw-rw-rw1 crw-rw-rw1 -rwxr-xr-x 1 prw------1 crw-rw-r-1 ... root root root root root root root root root root root root root root 36864 4096 0 1, 3 26689 0 10, 175 Feb Oct Dec May Mar Dec Feb 1 15:14 . 11 16:39 .. 18 01:31 log 5 1998 null 2 2000 MAKEDEV 11 18:37 initctl 3 2000 agpgart

O primeiro caractere de cada linha na sa do comando ls indica o tipo da de entrada.

353

354

Apndice C e Tabela de Sinais


A TABELA C.1 LISTA ALGUNS DOS SINAIS DO GNU/LINUX QUE VOCE TEM MAIS CHANCE de encontrar ou usar. Note que alguns sinais possuem mltiplas interpretaes, dependendo de onde eles ocorrem. u co Os nomes dos sinais listados aqui so denidos como macros de prprocessador. a e Para us-los em seu programa, inclua <signal.h>. As atuais denies a co esto em /usr/include/sys/signum.h, o qual est inclu como parte de a a do <signal.h>. Para uma lista completa dos sinais, incluindo uma descrio curts de cada ca um e o comportamento padro quando o sinal entregue, consulte a pgina a e a de manual para sinais na Seo 7 atravs da seguinte chamada: ca e % man 7 signal

355

Nome SIGHUP

SIGINT

SIGILL

SIGABRT SIGFPE

SIGKILL SIGUSR1 SIGUSR2 SIGSEGV

Tabela C.1: Sinais do GNU/Linux Descrio ca GNU/Linux envia a um processo esse sinal quando o processo torna-se disconectado de um terminal. Muitos programas GNU/Linux usam SIGHUP para um propsito completamente diferente: para indicar a um o programa que est sendo executado que esse mesmo proa grama deve reler seus arquivos de congurao. ca GNU/Linux envia a um processo esse sinal quando o usurio tenta terminar o referido programa por meio de a Ctrl+C. Um processo recebe esse sinal quando esse mesmo processo tenta executar uma instruo ilegal. Essa tentaca tiva por parte do processo pode indicar que a pilha do programa est corrompida. a A funo abort faz com que o processo receba esse sinal. ca O processo executou uma instruo invlida em ponto ca a utuante. Dependendo de como a CPU est congua rada, uma operao invlida em ponto utuante pode ca a retornar um valor no numrico especial tal como inf a e (innito) or NaN (No Nmeror) ao invs de SIGFPE. a u e Esse sinal termina um processo imediatamente e no a pode ser manipulado. Esse sinal reservado para uso em programas aplicatie vos. Esse sinal reservado para uso em programas aplicatie vos. O programa tentou um acesso invlido ` memria. O a a o acesso pode ser para um endereo que invlido no c e a espao virtual de endereamento de memria do proc c o cesso, ou o acesso pode ser proibido pelas permisses o da memria alvo. Dereferenciar um apontador selvao gem 1 . pode causar um SIGSEGV.

356

Tabela C.2: Sinais do GNU/Linux - Continuao ca Nome Descrio ca SIGPIPE O programa tentou acessar um uxo de dados interrompido, tal como uma coneco atravs de socket que tenha ca e sido fechada pela outra parte. SIGALRM A chamada de sistema alarm agendou a entrega desse sinal em uma hora posterior. Veja a Seo 8.13, A ca Chamada setitimer : Ajustando Intervalos em Temporizadores no Cap tulo 8, Chamadas de Sistema do GNU/Linux para informaes sobre setitimer, uma co verso generalizada de alarm. a SIGTERM Esse sinal requisita que o processo termine. Esse o e sinal padro enviado pelo comando kill. a SIGCHLD GNU/Linux envia a um processo esse sinal quando um processo lho termina. Veja Seo 3.3.5, Limpando Fica lhos de Forna No Sincronizada no Cap a tulo 3, Processos. SIGXCPU GNU/Linux envia a um processo esse sinal quando esse mesmo processo excede o limite de tempo de CPU que o referido processo pode consumir. Veja Seo 8.5, As ca Chamadas getrlimit e setrlimit: Limites de Recurso no Cap tulo 8 para informao sobre limite de tempo de ca CPU. SIGVTALRM A setitimer agendou a entrega desse sinal em um tempo futuro. Veja Seo 8.13, A Chamada setitimer : Ajusca tando Intervalos em Temporizadores. Veja no Apndice K Seo K.1 para uma lista completa (at o momento) e ca e dos sinais e seus valores respectivos.

357

358

Apndice D e Recursos Online


ESSE APENDICE LISTA ALGUNS LUGARES PARA VISITAR NA INTERNET para aprender mais sobre programao para sistemas GNU/Linux. ca

D.1

Informao Geral ca

http://www.advancedlinuxprogramming.com a casa desse livro na Ine ternet . Aqui, voc pode copiar para seu computador o texto completo e desse livro e o cdigo fonte dos programas, encontrar links para ouo tros recursos online, e pegar mais informao sobre programao para ca ca GNU/Linux. A mesma informao pode tambm ser encontrada em ca e http://www.newriders.com. http://www.linuxdoc.org a casa do Linux Documentation Project. e Esse s um rpositrio para uma riqueza de documentao, lista de tio e o ca FAQ, HOWTOs, e outras documentaes sobre sistemas GNU/Linux co e software GNU/Linux.

D.2

Informao Sobre Software GNU/Linux ca

http://www.gnu.org a casa do projeto GNU. Nesse s e tio, voc pode e copiar para o seu computador um impressionante variedade de software aplicativos livres sosticados. Entre eles est a biblioteca C GNU a padro, a qual parte de todo sistema GNU/Linux e contm muitas das a e e funes descritas nesse livro. O s do Projeto GNU tambm fornece co tio e informao sobre como voc pode contribuir para o desenvolvimento ca e do sistema GNU/Linux atravs da escrita de cdigo ou documentao, e o ca 359

atravs do uso de software livre, e atravs da divulgao da mensagem e e ca do software livre. http://www.kernel.org o s primrio para distribuio do cdigo e tio a ca o fontr do kernel do GNU/Linux. Para os problemasmais complicados e questes mais tcnicamente detalhadas sobre como GNU/Linux trabao e lha, o cdigo fonte o melhor lugar para olhar. Veja tambm o diretrio o e e o de documentao para explanao sobre a parte interna do kernel. ca ca http://www.linuxhq.com tambm distribui cdigos fonte do kernel do e o GNU/Linux, patches, e informao relacionada. ca http://gcc.gnu.org a casa do GNU Compiler Collection (GCC). GCC e o compilador primrio usado em sistemas GNU/Linux, e a GCC inclui e a compiladores para C, C++, Objective C, Java, Chill, e Fortran. http://www.gnome.org e http://www.kde.org so as casas dos dois a mais populares ambientes gerenciadores de janela do GNU/Linux, Gnome e KDE. Se voc planeja escrever uma aplicao com um interface grca e ca a de usurio, voc deve familiarizar-se por si mesmo com qualquer dos a e dois ou com ambos.

D.3

Outros S tios

http://developer.intel.com fornece informao sobre as arquiteturas dos ca processadores intel, incluindo a arquitetura x86 (IA32). Se voc est e a desenvolvendo para x86 GNU/Linux e voc usar instrues assembly e co enbutidas, os manuais tcnicos dispon e veis aqui iro ser muito uteis. a http://www.amd.com/devconn/ fornece similar informao sobre a lica nha de microprocessadores da AMD e seus recursos especiais. http://freshmeat.net est um a ndice de software open source, geralmente para GNU/Linux. Esse s um dos melhores lugares para estio e tar informado sobre as mais novas atualizaes do software GNU/Linux, co sobre os principais componentes do sistema para aplcaes mais especo cializadas. http://www.linuxsecurity.com contm informao, tcnicas, e links para e ca e software relacionado com a seguranca em GNU/Linux. O s do c tio e interesse para usurios, administradores de sistema, e desenvolvedores. a

360

Apndice E e Open Publication License


Version 1.0 I. Requirements on Both Unmodied and Modied Versions The Open Publication works may be reproduced and distributed in whole or in part, in any medium, physical or electronic, provided that the terms of this license are adhered to and that this license or an incorporation of it by reference (with any options elected by the author(s) and/or publisher) is displayed in the reproduction. Proper form for an incorporation by reference is as follows: Copyright year by authors name or designee.This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, vX.Y or later (the latest version is presently available at http://www.opencontent.org/openpub/). The reference must be immediately followed with any options elected by the author(s) or publisher of the document (see Section VI, License Options). Commercial redistribution of Open Publication-licensed material is permitted. Any publication in standard (paper) book form shall require the citation of the original publisher and author.The publisher and authors names shall appear on all outer surfaces of the book. On all outer surfaces of the book, the original publishers name shall be as large as the title of the work and cited as possessive with respect to the title. 306 Appendix E Open Publication License Version 1.0 II. Copyright The copyright to each Open Publication is owned by its author(s) or designee. III. Scope of License The following license terms apply to all Open Publication works, unless otherwise explicitly stated in the document. Mere aggregation of Open Publication works or a portion of an Open Publication work with other works or programs on the same media shall not cause this license to apply to those other works.The aggregate work shall contain a notice specifying the inclusion of the Open Publication material and appro361

priate copyright notice. Severability. If any part of this license is found to be unenforceable in any n jurisdiction, the remaining portions of the license remain in force. No warranty. Open Publication works are licensed and provided as is with- n out warranty of any kind, express or implied, including, but not limited to, the implied warranties of merchantability and tness for a particular purpose or a warranty of noninfringement. IV Requirements on Modied Works . All modied versions of documents covered by this license, including translations, anthologies, compilations, and partial documents, must meet the following requirements: 1. The modied version must be labeled as such. 2. The person making the modications must be identied, and the modications must be dated. 3. Acknowledgement of the original author and publisher, if applicable, must be retained according to normal academic citation practices. 4. The location of the original unmodied document must be identied. 5. The original authors (or authors) name(s) may not be used to assert or imply endorsement of the resulting document without the original authors (or authors) permission. V Good-Practice Recommendations . In addition to the requirements of this license, it is requested from and strongly rec- ommended of redistributors that: 1. If you are distributing Open Publication works on hard copy or CD-ROM, you provide email notication to the authors of your intent to redistribute at least 30 days before your manuscript or media freeze, to give the authors time to provide updated documents.This notication should describe modications, if any, made to the document. Open Publication Policy Appendix 307 2. All substantive modications (including deletions) be either clearly marked up in the document or else described in an attachment to the document. 3. Finally, although it is not mandatory under this license, it is considered good form to oer a free copy of any hard copy and CD-ROM expression of an Open Publication-licensed work to its author(s). VI. License Options The author(s) or publisher of an Open Publicationlicensed document may elect cer- tain options by appending language to the reference to or copy of the license.These options are considered part of the license instance and must be included with the license (or its incorporation by reference) in derived works. A. To prohibit distribution of substantively modied versions without the explicit permission of the author(s). Substantive modication is dened as a change to the semantic content of the document and excludes mere changes in format or typographical corrections. To accomplish this, add the phrase Distribution of substantively modied ver- sions of this document is prohibited without the explicit permission of the copyright holder to the license reference or copy. B. To prohibit any 362

publication of this work or derivative works in whole or in part in standard (paper) book form for commercial purposes is prohibited unless prior permission is obtained from the copyright holder. To accomplish this, add the phrase Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder to the license reference or copy. Open Publication Policy Appendix (This is not considered part of the license.) Open Publication works are available in source format via the Open Publication home page at http://works.opencontent.org/. Open Publication authors who want to include their own license on Open Publication works may do so, as long as their terms are not more restrictive than the Open Publication license. If you have questions about the Open Publication License, please contact David Wiley, or the Open Publication Authors List at opal@opencontent.org, via email. To subscribe to the Open Publication Authors List, send email to opal-request@opencontent.org with the word subscribe in the body. 308 Appendix E Open Publication License Version 1.0 To post to the Open Publication Authors List, send email to opal@open content.org, or simply reply to a previous post. To unsubscribe from the Open Publication Authors List, send email to opal-request@opencontent.org with the word unsubscribe in the body.

363

364

Apndice F e GNU General Public License1


Version 2, June 1991 Copyright 1989, 1991 Free Software Foundation, Inc. 59 Temple Place-Suite 330, Boston, MA 02111-1307, USA Everyone is permitted to copy and distribute verbatim copies of this license docu- ment, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software to make sure the software is free for all its users.This General Public License applies to most of the Free Software Foundations software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. 310 Appendix F GNU/General Public License To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights.These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have.You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and
1

This license can also be found online at http://www.gnu.org/copyleft/gpl.html.

365

(2) oer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each authors protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modied by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reect on the original authors reputations. Finally, any free program is threatened constantly by software patents.We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in eect making the program proprietary.To prevent this, we have made it clear that any patent must be licensed for everyones free use or not licensed at all. The precise terms and conditions for copying, distribution and modication follow. Terms and Conditions for Copying, Distribution and Modication 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License.The Program below, refers to any such program or work, and a work based on the Program means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modications and/or trans- lated into another language. (Hereinafter, translation is included without limita- tion in the term modication.) Each licensee is addressed as you.Activities other than copying, distribution and modication are not covered by this License; they are outside its scope.The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program).Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Programs source code as you receive it, in any medium, provided that you conspicuously and appropri- ately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 311 of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option oer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modica- tions or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modied les to carry prominent notices stating n 366

that you changed the les and the date of any change. b) You must cause any work that you distribute or publish, that in whole n or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modied program normally reads commands interactively when n run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modied work as a whole. If identiable sec- tions of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 312 Appendix F GNU/General Public License 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable n source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written oer, valid for at least three years, to give n any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corre- sponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it 367

with the information you received as to the oer to dis- n tribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an oer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface denition les, plus the scripts used to control compilation and installation of the exe- cutable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating sys- tem on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by oering access to copy from a designated place, then oering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works.These actions are prohibited by law if you do not accept this License.Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 313 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions.You may not impose any further restrictions on the recipients exercise of the rights granted herein.You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the condi- tions of this 368

License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not per- mit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particu- lar circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribu- tion limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may dier in detail to address new problems or concerns. 314 Appendix F GNU/General Public License Each version is given a distinguishing version number. If the Program species a version number of this License which applies to it and any later version, you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are dierent, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free 369

status of all derivatives of our free software and of promoting the sharing and reuse of soft- ware generally. No Warranty 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE,THERE IS NO WARRANTY FOR THE PROGRAM,TO THE EXTENT PERMIT- TED BY APPLICABLE LAW. EXCEPT WHEN OTHER WISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM AS ISWITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE,YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. How to Apply These Terms to Your New Programs 315 End of Terms and Conditions How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source le to most eectively convey the exclusion of warranty; and each le should have at least the copyright line and a pointer to where the full notice is found. one line to give the programs name and an idea of what it does. Copyright yyyy name of author This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Pu370

blic License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place-Suite 330, Boston, MA 02111-1307, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type show w.This is free software, and you are welcome to redistribute it under certain conditions; type show c for details. The hypothetical commands show w and show c should show the appropriate parts of the General Public License. Of course, the commands you use may be called some- thing other than show w and show c; they could even be mouse-clicks or menu items whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a copyright disclaimer for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program Gnomovision (which makes passes at compilers) written by James Hacker. signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice 316 Appendix F GNU/General Public License This General Public License does not permit incorporating your program into propri- etary programs. If your program is a subroutine library, you may consider it more use- ful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. FSF & GNU inquiries & questions to gnu@gnu.org. Comments on these web pages to webmasters@www.gnu.org, send other questions to gnu@gnu.org. Copyright notice above. Free Software Foundation, Inc., 59 Temple Place-Suite 330, Boston, MA 02111, USA Updated: 31 Jul 2000 jonas

371

372

Apndice G e Sa das Diversas do /proc


Apndice inclu pelo tradutor. e do

G.1

cat /proc/cpuinfo

processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 42 model name : Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz stepping : 7 cpu MHz : 3392.495 cache size : 8192 KB physical id : 0 siblings : 8 core id : 0 cpu cores : 4 apicid : 0 initial apicid : 0 fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge 373

mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx rdtscp lm constant_tsc arch_perfmon pebs bts xtopology nonstop_tsc perfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 x2apic popcnt aes xsave avx lahf_lm ida arat tpr_shadow vnmi flexpriority ept vpid bogomips : 6784.99 clflush size : 64 cache_alignment : 64 address sizes : 36 bits physical, 48 bits virtual power management: processor : 1 vendor_id : GenuineIntel cpu family : 6 model : 42 model name : Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz stepping : 7 cpu MHz : 3392.495 cache size : 8192 KB physical id : 0 siblings : 8 core id : 1 cpu cores : 4 apicid : 2 initial apicid : 2 fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx rdtscp lm constant_tsc arch_perfmon pebs bts xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 x2apic popcnt aes xsave avx lahf_lm ida arat tpr_shadow vnmi flexpriority ept vpid bogomips : 6783.71 clflush size : 64 374

cache_alignment : 64 address sizes : 36 bits physical, 48 bits virtual power management: processor : 2 vendor_id : GenuineIntel cpu family : 6 model : 42 model name : Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz stepping : 7 cpu MHz : 3392.495 cache size : 8192 KB physical id : 0 siblings : 8 core id : 2 cpu cores : 4 apicid : 4 initial apicid : 4 fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx rdtscp lm constant_tsc arch_perfmon pebs bts xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 x2apic popcnt aes xsave avx lahf_lm ida arat tpr_shadow vnmi flexpriority ept vpid bogomips : 6783.71 clflush size : 64 cache_alignment : 64 address sizes : 36 bits physical, 48 bits virtual power management: processor : 3 vendor_id : GenuineIntel cpu family : 6 375

model : 42 model name : Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz stepping : 7 cpu MHz : 3392.495 cache size : 8192 KB physical id : 0 siblings : 8 core id : 3 cpu cores : 4 apicid : 6 initial apicid : 6 fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx rdtscp lm constant_tsc arch_perfmon pebs bts xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 x2apic popcnt aes xsave avx lahf_lm ida arat tpr_shadow vnmi flexpriority ept vpid bogomips : 6783.72 clflush size : 64 cache_alignment : 64 address sizes : 36 bits physical, 48 bits virtual power management: processor : 4 vendor_id : GenuineIntel cpu family : 6 model : 42 model name : Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz stepping : 7 cpu MHz : 3392.495 cache size : 8192 KB physical id : 0 siblings : 8 376

core id : 0 cpu cores : 4 apicid : 1 initial apicid : 1 fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx rdtscp lm constant_tsc arch_perfmon pebs bts xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 x2apic popcnt aes xsave avx lahf_lm ida arat tpr_shadow vnmi flexpriority ept vpid bogomips : 6783.72 clflush size : 64 cache_alignment : 64 address sizes : 36 bits physical, 48 bits virtual power management: processor : 5 vendor_id : GenuineIntel cpu family : 6 model : 42 model name : Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz stepping : 7 cpu MHz : 3392.495 cache size : 8192 KB physical id : 0 siblings : 8 core id : 1 cpu cores : 4 apicid : 3 initial apicid : 3 fdiv_bug : no hlt_bug : no f00f_bug : no 377

coma_bug : no fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx rdtscp lm constant_tsc arch_perfmon pebs bts xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 x2apic popcnt aes xsave avx lahf_lm ida arat tpr_shadow vnmi flexpriority ept vpid bogomips : 6783.71 clflush size : 64 cache_alignment : 64 address sizes : 36 bits physical, 48 bits virtual power management: processor : 6 vendor_id : GenuineIntel cpu family : 6 model : 42 model name : Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz stepping : 7 cpu MHz : 3392.495 cache size : 8192 KB physical id : 0 siblings : 8 core id : 2 cpu cores : 4 apicid : 5 initial apicid : 5 fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx 378

rdtscp lm constant_tsc arch_perfmon pebs bts xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 x2apic popcnt aes xsave avx lahf_lm ida arat tpr_shadow vnmi flexpriority ept vpid bogomips : 6783.71 clflush size : 64 cache_alignment : 64 address sizes : 36 bits physical, 48 bits virtual power management: processor : 7 vendor_id : GenuineIntel cpu family : 6 model : 42 model name : Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz stepping : 7 cpu MHz : 3392.495 cache size : 8192 KB physical id : 0 siblings : 8 core id : 3 cpu cores : 4 apicid : 7 initial apicid : 7 fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx rdtscp lm constant_tsc arch_perfmon pebs bts xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 x2apic popcnt aes xsave avx lahf_lm ida arat tpr_shadow vnmi flexpriority ept vpid bogomips : 6783.71 clflush size : 64 cache_alignment : 64 379

address sizes : 36 bits physical, 48 bits virtual power management:

G.2

Entradas de um Diretrio de Processo o

O comando ls -l executado dentro do diretrio de um processo, mostrando o seu contedo: u


total 0 dr-xr-xr-x -r---------w-------r--r--r--rw-r--r--rw-r--r-lrwxrwxrwx -r-------lrwxrwxrwx dr-x-----dr-x------r--r--r--r--------rw-r--r--r--r--r--rw-------r--r--r--r--r--r--r-------dr-xr-xr-x -rw-r--r--r--r--r--r--------r-------lrwxrwxrwx -rw-r--r--r--r--r--r--r--r--r--------r--r--r--r--r--r--r--r--r--r-------dr-xr-xr-x -r--r--r-2 1 1 1 1 1 1 1 1 2 2 1 1 1 1 1 1 1 1 6 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root root 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 2011-07-03 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:56 07:49 07:56 07:56 07:56 07:56 07:56 attr auxv clear_refs cmdline comm coredump_filter cwd -> /home/usu\ario/programa/slots/4 environ exe -> /home/usu\ario/programa/projects/xxx/execut\avel fd fdinfo io limits loginuid maps mem mountinfo mounts mountstats net oom_adj oom_score pagemap personality root -> / sched sessionid smaps stack stat statm status syscall task wchan

G.3

cat /proc/version

Segue um outro exemplo de cat /proc/version: %cat /proc/version Linux version 2.6.32-24-generic (buildd@palmer) (gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5) ) #43-Ubuntu SMP Thu Sep 16 14:17:33 UTC 2010 A sa acima indica que o sistema est executando um release 2.6.32 da a do kernel do GNU/Linux (reviso 24-generic), que foi compilado com um a release do gcc, GNU C Compiler, verso 4.4.3 especialmente modicado para a integrar a distribuio ubuntu. Podemos ver tambm que o usurio que o ca e a compilou pode ser identicado pelo cdigo buildd@palmer e a verso no fuso o a horrio UTC/GMT. a 380

$ cat /proc/sys/kernel/ostype Linux $ cat /proc/sys/kernel/osrelease 2.6.32-24-generic $ cat /proc/sys/kernel/version #43-Ubuntu SMP Thu Sep 16 14:17:33 UTC 2010

G.4

cat /proc/scsi/scsi

Segue um outro exemplo de cat /proc/scsi/scsi: $ cat /proc/scsi/scsi Attached devices: Host: scsi2 Channel: 00 Vendor: ATA Model: Type: Direct-Access Host: scsi2 Channel: 00 Vendor: HL-DT-ST Model: Type: CD-ROM Host: scsi3 Channel: 00 Vendor: ATA Model: Type: Direct-Access Host: scsi5 Channel: 00 Vendor: Kingston Model: Type: Direct-Access

Id: 00 Lun: 00 ST3160318AS Id: 01 Lun: 00 DVDRAM GH22NS40 Id: 00 Lun: 00 ST3160318AS

Rev: CC44 ANSI SCSI revision: 05 Rev: NL02 ANSI SCSI revision: 05 Rev: CC44 ANSI SCSI revision: 05

Id: 00 Lun: 00 DataTravelerMini Rev: PMAP ANSI SCSI revision: 00

G.5

cat /proc/sys/dev/cdrom/info

Segue um outro exemplo de cat /proc/sys/dev/cdrom/info: CD-ROM information, Id: cdrom.c 3.20 2003/12/17 drive name: sr0 drive speed: 48 drive # of slots: 1 Can close tray: 1 Can open tray: 1 Can lock tray: 1 Can change speed: 1 Can select disk: 0 381

Can read multisession: 1 Can read MCN: 1 Reports media changed: 1 Can play audio: 1 Can write CD-R: 1 Can write CD-RW: 1 Can read DVD: 1 Can write DVD-R: 1 Can write DVD-RAM: 1 Can read MRW: 1 Can write MRW: 1 Can write RAM: 1

G.6

cat /proc/mounts

Segue um outro exemplo de cat /proc/mounts:


rootfs / rootfs rw 0 0 none /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0 none /proc proc rw,nosuid,nodev,noexec,relatime 0 0 none /dev devtmpfs rw,relatime,size=993448k,nr_inodes=199859,mode=755 0 0 none /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0 /dev/disk/by-uuid/c5d4e917-f52d-4562-b312-7a9defab403e / ext4 rw,relatime,errors=remount-ro,barrier=1,data=ordered 0 0 none /sys/fs/fuse/connections fusectl rw,relatime 0 0 none /sys/kernel/debug debugfs rw,relatime 0 0 none /sys/kernel/security securityfs rw,relatime 0 0 none /dev/shm tmpfs rw,nosuid,nodev,relatime 0 0 none /var/run tmpfs rw,nosuid,relatime,mode=755 0 0 none /var/lock tmpfs rw,nosuid,nodev,noexec,relatime 0 0 none /lib/init/rw tmpfs rw,nosuid,relatime,mode=755 0 0 /dev/sda3 /compartilhar0 ext3 rw,relatime,errors=continue,data=ordered 0 0 rpc_pipefs /var/lib/nfs/rpc_pipefs rpc_pipefs rw,relatime 0 0 nfsd /proc/fs/nfsd nfsd rw,relatime 0 0 binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc rw,nosuid,nodev,noexec,relatime 0 0 192.168.5.120:/cp0 /cp1 nfs rw,relatime,vers=3,rsize=131072,wsize=131072,namlen=255,hard,proto=tcp,timeo=600,\ retrans=2,sec=sys,mountaddr=192.168.5.120,mountvers=3,mountproto=tcp,addr=192.168.5.120 0 0 gvfs-fuse-daemon /home/aluno/.gvfs fuse.gvfs-fuse-daemon rw,nosuid,nodev,relatime,user_id=1001,group_id=1001 0 0 /dev/sdd1 /media/KINGSTON vfat rw,nosuid,nodev,relatime,uid=1001,gid=1001,fmask=0022,dmask=0077,codepage=cp437,\ iocharset=iso8859-1,shortname=mixed,utf8,flush,errors=remount-ro 0 0

Gostaria de chamar a ateno para a linha que inicia-se com 192.168.5.120 ca que mostra uma partio remota nfs e para a linha com /dev/sdd1 que mostra ca um pendrive.

G.7

cat /proc/locks

Segue um outro exemplo de cat /proc/locks:


cat /proc/locks 1: POSIX ADVISORY 2: POSIX ADVISORY 3: POSIX ADVISORY 4: POSIX ADVISORY 5: POSIX ADVISORY 6: POSIX ADVISORY WRITE READ WRITE READ READ READ 2444 2444 2444 1248 1233 1233 08:01:1448371 1073741824 1073742335 08:01:1448361 1073741826 1073742335 08:01:1448351 0 EOF 00:11:5695 4 4 08:01:915898 4 4 00:11:5709 4 4

382

7: POSIX ADVISORY READ 1233 00:11:5695 4 4 8: POSIX ADVISORY WRITE 1233 00:11:5700 0 0 9: POSIX ADVISORY WRITE 1121 08:01:915815 0 EOF 10: POSIX ADVISORY WRITE 1135 00:11:4957 0 EOF 11: FLOCK ADVISORY WRITE 1111 00:11:4934 0 EOF 12: POSIX ADVISORY WRITE 699 00:11:3938 0 EOF

Gostaria de chamara ateno para a linha 11 que mostra uma entrada diferente. ca

383

384

Apndice H e Adicionais ao Cap tulo 8


Apndice inclu e do pelo tradutor.

H.1

strace hostname

execve("/bin/hostname", ["hostname"], [/* 53 vars */]) = 0 brk(0) = 0x804b000 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78d5000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/lib/tls/i686/sse2/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/lib/tls/i686/sse2", 0xbf7fec20) = -1 ENOENT (No such file or directory) open("/lib/tls/i686/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/lib/tls/i686", 0xbf7fec20) = -1 ENOENT (No such file or directory) open("/lib/tls/sse2/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/lib/tls/sse2", 0xbf7fec20) = -1 ENOENT (No such file or directory) open("/lib/tls/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/lib/tls", 0xbf7fec20) = -1 ENOENT (No such file or directory) open("/lib/i686/sse2/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/lib/i686/sse2", 0xbf7fec20) = -1 ENOENT (No such file or directory) open("/lib/i686/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/lib/i686", 0xbf7fec20) = -1 ENOENT (No such file or directory) open("/lib/sse2/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory) stat64("/lib/sse2", 0xbf7fec20) = -1 ENOENT (No such file or directory) open("/lib/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\340l\1\0004\0\0\0<"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=1649149, ...}) = 0 mmap2(NULL, 1452296, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7772000 mprotect(0xb78ce000, 4096, PROT_NONE) = 0 mmap2(0xb78cf000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x15c) = 0xb78cf000 mmap2(0xb78d2000, 10504, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb78d2000 close(3) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7771000 set_thread_area({entry_number:-1 -> 6, base_addr:0xb77716c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 mprotect(0xb78cf000, 8192, PROT_READ) = 0 mprotect(0xb78f3000, 4096, PROT_READ) = 0 brk(0) = 0x804b000 brk(0x806c000) = 0x806c000 open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory) open("/usr/share/locale/locale.alias", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=2570, ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7770000 read(3, "# Locale name alias data base.\n# "..., 4096) = 2570 read(3, ""..., 4096) = 0 close(3) = 0 munmap(0xb7770000, 4096) = 0 open("/usr/lib/locale/pt_BR.utf8/LC_IDENTIFICATION", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=351, ...}) = 0 mmap2(NULL, 351, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7770000 close(3) = 0 open("/usr/lib/gconv/gconv-modules.cache", O_RDONLY) = -1 ENOENT (No such file or directory) open("/usr/lib/gconv/gconv-modules", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=56028, ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb776f000 read(3, "# GNU libc iconv configuration.\n#"..., 4096) = 4096 read(3, "B1.002//\nalias\tJS//\t\t\tJUS_I.B1.00"..., 4096) = 4096

385

read(3, "59-3\t1\nmodule\tINTERNAL\t\tISO-8859-"..., 4096) = 4096 read(3, "859-14//\nalias\tISO-IR-199//\t\tISO-"..., 4096) = 4096 read(3, "CDIC-DK-NO-A//\tEBCDIC-DK-NO-A\t1\n\n"..., 4096) = 4096 read(3, "\t\tIBM281//\t\tIBM281\t\t1\n\n#\tfrom\t\t\tt"..., 4096) = 4096 read(3, "\tIBM863\t\t1\n\n#\tfrom\t\t\tto\t\t\tmodule\t"..., 4096) = 4096 read(3, "//\t\tIBM937//\nalias\tCSIBM937//\t\tIB"..., 4096) = 4096 read(3, "JAPANESE//\tEUC-JP//\nalias\tOSF0003"..., 4096) = 4096 read(3, "MACINTOSH//\t\tMACINTOSH\t1\n\n#\tfrom\t"..., 4096) = 4096 read(3, "367-BOX//\nalias\tISO_10367BOX//\t\tI"..., 4096) = 4096 read(3, "EUC-JISX0213//\t\tINTERNAL\t\tEUC-JIS"..., 4096) = 4096 read(3, "/\t\tIBM1130//\nalias\tCSIBM1130//\t\tI"..., 4096) = 4096 read(3, "\t1\n\n#\tfrom\t\t\tto\t\t\tmodule\t\tcost\nal"..., 4096) = 2780 read(3, ""..., 4096) = 0 close(3) = 0 munmap(0xb776f000, 4096) = 0 open("/usr/lib/locale/pt_BR.utf8/LC_MEASUREMENT", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=23, ...}) = 0 mmap2(NULL, 23, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb776f000 close(3) = 0 open("/usr/lib/locale/pt_BR.utf8/LC_TELEPHONE", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=51, ...}) = 0 mmap2(NULL, 51, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb776e000 close(3) = 0 open("/usr/lib/locale/pt_BR.utf8/LC_ADDRESS", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=127, ...}) = 0 mmap2(NULL, 127, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb776d000 close(3) = 0 open("/usr/lib/locale/pt_BR.utf8/LC_NAME", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=62, ...}) = 0 mmap2(NULL, 62, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb776c000 close(3) = 0 open("/usr/lib/locale/pt_BR.utf8/LC_PAPER", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=34, ...}) = 0 mmap2(NULL, 34, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb776b000 close(3) = 0 open("/usr/lib/locale/pt_BR.utf8/LC_MESSAGES", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 close(3) = 0 open("/usr/lib/locale/pt_BR.utf8/LC_MESSAGES/SYS_LC_MESSAGES", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=54, ...}) = 0 mmap2(NULL, 54, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb776a000 close(3) = 0 open("/usr/lib/locale/pt_BR.utf8/LC_MONETARY", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=290, ...}) = 0 mmap2(NULL, 290, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7769000 close(3) = 0 open("/usr/lib/locale/pt_BR.utf8/LC_COLLATE", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=1163682, ...}) = 0 mmap2(NULL, 1163682, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb764c000 close(3) = 0 open("/usr/lib/locale/pt_BR.utf8/LC_TIME", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=2358, ...}) = 0 mmap2(NULL, 2358, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb764b000 close(3) = 0 open("/usr/lib/locale/pt_BR.utf8/LC_NUMERIC", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=54, ...}) = 0 mmap2(NULL, 54, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb764a000 close(3) = 0 open("/usr/lib/locale/pt_BR.utf8/LC_CTYPE", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=256324, ...}) = 0 mmap2(NULL, 256324, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb760b000 close(3) = 0 uname({sys="Linux", node="computador", ...}) = 0 fstat64(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 5), ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb760a000 write(1, "computador\n"..., 6) = 6 exit_group(0) = ?

H.2

sysctl

No slackware 13.1 a pgina de manual para o comando ulimit informa que a ele est obsoleto. Resta ento o comando sysctl e as chamadas de sistema a a getrlimit e setrlimit para controlar os limites do sistema. Para modicar os limites do sistema no slackware 13.1 crie o /etc/sysctl.conf e coloque nele os 386

limites que voc deseja alterar. O formato do sysctl.conf basicamente o e e mesmo apresentado na sa do sysctl -a. Exemplo de sysctl.conf: da dev.cdrom.lock = 0 kernel.sysrq = 0 net.ipv4.conf.default.rp lter = 1 net.ipv4.conf.all.rp lter = 1 net.ipv4.ip forward = 1 net.ipv6.conf.all.forwarding = 1 net.ipv4.icmp echo ignore broadcasts = 1 net.ipv4.icmp echo ignore all = 1 net.ipv4.conf.all.accept redirects = 0 net.ipv6.conf.all.accept redirects = 0 net.ipv4.conf.all.send redirects = 0 net.ipv4.conf.all.accept source route = 0 A sa do sysctl -a: da
% sysctl -a kernel.sched_child_runs_first = 0 kernel.sched_min_granularity_ns = 4000000 kernel.sched_latency_ns = 20000000 kernel.sched_wakeup_granularity_ns = 4000000 kernel.sched_shares_ratelimit = 1000000 kernel.sched_tunable_scaling = 1 kernel.sched_shares_thresh = 4 kernel.sched_migration_cost = 500000 kernel.sched_nr_migrate = 32 kernel.sched_time_avg = 1000 kernel.timer_migration = 1 kernel.sched_rt_period_us = 1000000 kernel.sched_rt_runtime_us = 950000 kernel.sched_compat_yield = 0 kernel.panic = 0 kernel.core_uses_pid = 0 kernel.core_pattern = core kernel.core_pipe_limit = 0 kernel.tainted = 1 kernel.real-root-dev = 0 kernel.print-fatal-signals = 0 kernel.ctrl-alt-del = 0 kernel.ftrace_enabled = 1 kernel.ftrace_dump_on_oops = 0 kernel.modprobe = /sbin/modprobe kernel.modules_disabled = 0 kernel.hotplug = kernel.acct = 4 2 30 kernel.sysrq = 1 kernel.cad_pid = 1 kernel.threads-max = 58491 kernel.random.poolsize = 4096 kernel.random.entropy_avail = 2795 kernel.random.read_wakeup_threshold = 64 kernel.random.write_wakeup_threshold = 128 kernel.random.boot_id = eff50304-4b17-4071-9083-6a72e3ba0a1b kernel.random.uuid = 194c4e6a-88d8-45ad-876b-305e85cadba8 kernel.overflowuid = 65534 kernel.overflowgid = 65534 kernel.pid_max = 32768 kernel.panic_on_oops = 0 kernel.printk = 3 4 1 7 kernel.printk_ratelimit = 5 kernel.printk_ratelimit_burst = 10 kernel.printk_delay = 0 kernel.ngroups_max = 65536 kernel.unknown_nmi_panic = 0 kernel.nmi_watchdog = 0 kernel.panic_on_unrecovered_nmi = 0 kernel.panic_on_io_nmi = 0 kernel.bootloader_type = 2 kernel.bootloader_version = 2 kernel.kstack_depth_to_print = 24 kernel.io_delay_type = 0 kernel.randomize_va_space = 1 kernel.acpi_video_flags = 0 kernel.softlockup_panic = 0 kernel.softlockup_thresh = 60 kernel.hung_task_panic = 0 kernel.hung_task_check_count = 32768 kernel.hung_task_timeout_secs = 120 kernel.hung_task_warnings = 10 kernel.max_lock_depth = 1024

387

kernel.poweroff_cmd = /sbin/poweroff kernel.keys.maxkeys = 200 kernel.keys.maxbytes = 20000 kernel.keys.root_maxkeys = 200 kernel.keys.root_maxbytes = 20000 kernel.keys.gc_delay = 300 kernel.slow-work.min-threads = 2 kernel.slow-work.max-threads = 8 kernel.slow-work.vslow-percentage = 50 kernel.perf_event_paranoid = 1 kernel.perf_event_mlock_kb = 512 kernel.perf_event_max_sample_rate = 100000 kernel.blk_iopoll = 1 kernel.sched_domain.cpu0.domain0.min_interval = 1 kernel.sched_domain.cpu0.domain0.max_interval = 2 kernel.sched_domain.cpu0.domain0.busy_idx = 0 kernel.sched_domain.cpu0.domain0.idle_idx = 0 kernel.sched_domain.cpu0.domain0.newidle_idx = 0 kernel.sched_domain.cpu0.domain0.wake_idx = 0 kernel.sched_domain.cpu0.domain0.forkexec_idx = 0 kernel.sched_domain.cpu0.domain0.busy_factor = 64 kernel.sched_domain.cpu0.domain0.imbalance_pct = 110 kernel.sched_domain.cpu0.domain0.cache_nice_tries = 0 kernel.sched_domain.cpu0.domain0.flags = 687 kernel.sched_domain.cpu0.domain0.name = SIBLING kernel.sched_domain.cpu0.domain1.min_interval = 1 kernel.sched_domain.cpu0.domain1.max_interval = 4 kernel.sched_domain.cpu0.domain1.busy_idx = 2 kernel.sched_domain.cpu0.domain1.idle_idx = 0 kernel.sched_domain.cpu0.domain1.newidle_idx = 0 kernel.sched_domain.cpu0.domain1.wake_idx = 0 kernel.sched_domain.cpu0.domain1.forkexec_idx = 0 kernel.sched_domain.cpu0.domain1.busy_factor = 64 kernel.sched_domain.cpu0.domain1.imbalance_pct = 125 kernel.sched_domain.cpu0.domain1.cache_nice_tries = 1 kernel.sched_domain.cpu0.domain1.flags = 4655 kernel.sched_domain.cpu0.domain1.name = MC kernel.sched_domain.cpu1.domain0.min_interval = 1 kernel.sched_domain.cpu1.domain0.max_interval = 2 kernel.sched_domain.cpu1.domain0.busy_idx = 0 kernel.sched_domain.cpu1.domain0.idle_idx = 0 kernel.sched_domain.cpu1.domain0.newidle_idx = 0 kernel.sched_domain.cpu1.domain0.wake_idx = 0 kernel.sched_domain.cpu1.domain0.forkexec_idx = 0 kernel.sched_domain.cpu1.domain0.busy_factor = 64 kernel.sched_domain.cpu1.domain0.imbalance_pct = 110 kernel.sched_domain.cpu1.domain0.cache_nice_tries = 0 kernel.sched_domain.cpu1.domain0.flags = 687 kernel.sched_domain.cpu1.domain0.name = SIBLING kernel.sched_domain.cpu1.domain1.min_interval = 1 kernel.sched_domain.cpu1.domain1.max_interval = 4 kernel.sched_domain.cpu1.domain1.busy_idx = 2 kernel.sched_domain.cpu1.domain1.idle_idx = 0 kernel.sched_domain.cpu1.domain1.newidle_idx = 0 kernel.sched_domain.cpu1.domain1.wake_idx = 0 kernel.sched_domain.cpu1.domain1.forkexec_idx = 0 kernel.sched_domain.cpu1.domain1.busy_factor = 64 kernel.sched_domain.cpu1.domain1.imbalance_pct = 125 kernel.sched_domain.cpu1.domain1.cache_nice_tries = 1 kernel.sched_domain.cpu1.domain1.flags = 4655 kernel.sched_domain.cpu1.domain1.name = MC kernel.sched_domain.cpu2.domain0.min_interval = 1 kernel.sched_domain.cpu2.domain0.max_interval = 2 kernel.sched_domain.cpu2.domain0.busy_idx = 0 kernel.sched_domain.cpu2.domain0.idle_idx = 0 kernel.sched_domain.cpu2.domain0.newidle_idx = 0 kernel.sched_domain.cpu2.domain0.wake_idx = 0 kernel.sched_domain.cpu2.domain0.forkexec_idx = 0 kernel.sched_domain.cpu2.domain0.busy_factor = 64 kernel.sched_domain.cpu2.domain0.imbalance_pct = 110 kernel.sched_domain.cpu2.domain0.cache_nice_tries = 0 kernel.sched_domain.cpu2.domain0.flags = 687 kernel.sched_domain.cpu2.domain0.name = SIBLING kernel.sched_domain.cpu2.domain1.min_interval = 1 kernel.sched_domain.cpu2.domain1.max_interval = 4 kernel.sched_domain.cpu2.domain1.busy_idx = 2 kernel.sched_domain.cpu2.domain1.idle_idx = 0 kernel.sched_domain.cpu2.domain1.newidle_idx = 0 kernel.sched_domain.cpu2.domain1.wake_idx = 0 kernel.sched_domain.cpu2.domain1.forkexec_idx = 0 kernel.sched_domain.cpu2.domain1.busy_factor = 64 kernel.sched_domain.cpu2.domain1.imbalance_pct = 125 kernel.sched_domain.cpu2.domain1.cache_nice_tries = 1

388

kernel.sched_domain.cpu2.domain1.flags = 4655 kernel.sched_domain.cpu2.domain1.name = MC kernel.sched_domain.cpu3.domain0.min_interval = 1 kernel.sched_domain.cpu3.domain0.max_interval = 2 kernel.sched_domain.cpu3.domain0.busy_idx = 0 kernel.sched_domain.cpu3.domain0.idle_idx = 0 kernel.sched_domain.cpu3.domain0.newidle_idx = 0 kernel.sched_domain.cpu3.domain0.wake_idx = 0 kernel.sched_domain.cpu3.domain0.forkexec_idx = 0 kernel.sched_domain.cpu3.domain0.busy_factor = 64 kernel.sched_domain.cpu3.domain0.imbalance_pct = 110 kernel.sched_domain.cpu3.domain0.cache_nice_tries = 0 kernel.sched_domain.cpu3.domain0.flags = 687 kernel.sched_domain.cpu3.domain0.name = SIBLING kernel.sched_domain.cpu3.domain1.min_interval = 1 kernel.sched_domain.cpu3.domain1.max_interval = 4 kernel.sched_domain.cpu3.domain1.busy_idx = 2 kernel.sched_domain.cpu3.domain1.idle_idx = 0 kernel.sched_domain.cpu3.domain1.newidle_idx = 0 kernel.sched_domain.cpu3.domain1.wake_idx = 0 kernel.sched_domain.cpu3.domain1.forkexec_idx = 0 kernel.sched_domain.cpu3.domain1.busy_factor = 64 kernel.sched_domain.cpu3.domain1.imbalance_pct = 125 kernel.sched_domain.cpu3.domain1.cache_nice_tries = 1 kernel.sched_domain.cpu3.domain1.flags = 4655 kernel.sched_domain.cpu3.domain1.name = MC kernel.sched_domain.cpu4.domain0.min_interval = 1 kernel.sched_domain.cpu4.domain0.max_interval = 2 kernel.sched_domain.cpu4.domain0.busy_idx = 0 kernel.sched_domain.cpu4.domain0.idle_idx = 0 kernel.sched_domain.cpu4.domain0.newidle_idx = 0 kernel.sched_domain.cpu4.domain0.wake_idx = 0 kernel.sched_domain.cpu4.domain0.forkexec_idx = 0 kernel.sched_domain.cpu4.domain0.busy_factor = 64 kernel.sched_domain.cpu4.domain0.imbalance_pct = 110 kernel.sched_domain.cpu4.domain0.cache_nice_tries = 0 kernel.sched_domain.cpu4.domain0.flags = 687 kernel.sched_domain.cpu4.domain0.name = SIBLING kernel.sched_domain.cpu4.domain1.min_interval = 1 kernel.sched_domain.cpu4.domain1.max_interval = 4 kernel.sched_domain.cpu4.domain1.busy_idx = 2 kernel.sched_domain.cpu4.domain1.idle_idx = 0 kernel.sched_domain.cpu4.domain1.newidle_idx = 0 kernel.sched_domain.cpu4.domain1.wake_idx = 0 kernel.sched_domain.cpu4.domain1.forkexec_idx = 0 kernel.sched_domain.cpu4.domain1.busy_factor = 64 kernel.sched_domain.cpu4.domain1.imbalance_pct = 125 kernel.sched_domain.cpu4.domain1.cache_nice_tries = 1 kernel.sched_domain.cpu4.domain1.flags = 4655 kernel.sched_domain.cpu4.domain1.name = MC kernel.sched_domain.cpu5.domain0.min_interval = 1 kernel.sched_domain.cpu5.domain0.max_interval = 2 kernel.sched_domain.cpu5.domain0.busy_idx = 0 kernel.sched_domain.cpu5.domain0.idle_idx = 0 kernel.sched_domain.cpu5.domain0.newidle_idx = 0 kernel.sched_domain.cpu5.domain0.wake_idx = 0 kernel.sched_domain.cpu5.domain0.forkexec_idx = 0 kernel.sched_domain.cpu5.domain0.busy_factor = 64 kernel.sched_domain.cpu5.domain0.imbalance_pct = 110 kernel.sched_domain.cpu5.domain0.cache_nice_tries = 0 kernel.sched_domain.cpu5.domain0.flags = 687 kernel.sched_domain.cpu5.domain0.name = SIBLING kernel.sched_domain.cpu5.domain1.min_interval = 1 kernel.sched_domain.cpu5.domain1.max_interval = 4 kernel.sched_domain.cpu5.domain1.busy_idx = 2 kernel.sched_domain.cpu5.domain1.idle_idx = 0 kernel.sched_domain.cpu5.domain1.newidle_idx = 0 kernel.sched_domain.cpu5.domain1.wake_idx = 0 kernel.sched_domain.cpu5.domain1.forkexec_idx = 0 kernel.sched_domain.cpu5.domain1.busy_factor = 64 kernel.sched_domain.cpu5.domain1.imbalance_pct = 125 kernel.sched_domain.cpu5.domain1.cache_nice_tries = 1 kernel.sched_domain.cpu5.domain1.flags = 4655 kernel.sched_domain.cpu5.domain1.name = MC kernel.sched_domain.cpu6.domain0.min_interval = 1 kernel.sched_domain.cpu6.domain0.max_interval = 2 kernel.sched_domain.cpu6.domain0.busy_idx = 0 kernel.sched_domain.cpu6.domain0.idle_idx = 0 kernel.sched_domain.cpu6.domain0.newidle_idx = 0 kernel.sched_domain.cpu6.domain0.wake_idx = 0 kernel.sched_domain.cpu6.domain0.forkexec_idx = 0 kernel.sched_domain.cpu6.domain0.busy_factor = 64 kernel.sched_domain.cpu6.domain0.imbalance_pct = 110

389

kernel.sched_domain.cpu6.domain0.cache_nice_tries = 0 kernel.sched_domain.cpu6.domain0.flags = 687 kernel.sched_domain.cpu6.domain0.name = SIBLING kernel.sched_domain.cpu6.domain1.min_interval = 1 kernel.sched_domain.cpu6.domain1.max_interval = 4 kernel.sched_domain.cpu6.domain1.busy_idx = 2 kernel.sched_domain.cpu6.domain1.idle_idx = 0 kernel.sched_domain.cpu6.domain1.newidle_idx = 0 kernel.sched_domain.cpu6.domain1.wake_idx = 0 kernel.sched_domain.cpu6.domain1.forkexec_idx = 0 kernel.sched_domain.cpu6.domain1.busy_factor = 64 kernel.sched_domain.cpu6.domain1.imbalance_pct = 125 kernel.sched_domain.cpu6.domain1.cache_nice_tries = 1 kernel.sched_domain.cpu6.domain1.flags = 4655 kernel.sched_domain.cpu6.domain1.name = MC kernel.sched_domain.cpu7.domain0.min_interval = 1 kernel.sched_domain.cpu7.domain0.max_interval = 2 kernel.sched_domain.cpu7.domain0.busy_idx = 0 kernel.sched_domain.cpu7.domain0.idle_idx = 0 kernel.sched_domain.cpu7.domain0.newidle_idx = 0 kernel.sched_domain.cpu7.domain0.wake_idx = 0 kernel.sched_domain.cpu7.domain0.forkexec_idx = 0 kernel.sched_domain.cpu7.domain0.busy_factor = 64 kernel.sched_domain.cpu7.domain0.imbalance_pct = 110 kernel.sched_domain.cpu7.domain0.cache_nice_tries = 0 kernel.sched_domain.cpu7.domain0.flags = 687 kernel.sched_domain.cpu7.domain0.name = SIBLING kernel.sched_domain.cpu7.domain1.min_interval = 1 kernel.sched_domain.cpu7.domain1.max_interval = 4 kernel.sched_domain.cpu7.domain1.busy_idx = 2 kernel.sched_domain.cpu7.domain1.idle_idx = 0 kernel.sched_domain.cpu7.domain1.newidle_idx = 0 kernel.sched_domain.cpu7.domain1.wake_idx = 0 kernel.sched_domain.cpu7.domain1.forkexec_idx = 0 kernel.sched_domain.cpu7.domain1.busy_factor = 64 kernel.sched_domain.cpu7.domain1.imbalance_pct = 125 kernel.sched_domain.cpu7.domain1.cache_nice_tries = 1 kernel.sched_domain.cpu7.domain1.flags = 4655 kernel.sched_domain.cpu7.domain1.name = MC kernel.ostype = Linux kernel.osrelease = 2.6.33.4-smp kernel.version = #2 SMP Wed May 12 22:47:36 CDT 2010 kernel.hostname = papai kernel.domainname = (none) kernel.shmmax = 33554432 kernel.shmall = 2097152 kernel.shmmni = 4096 kernel.msgmax = 8192 kernel.msgmni = 1678 kernel.msgmnb = 16384 kernel.sem = 250 32000 32 128 kernel.auto_msgmni = 1 kernel.pty.max = 4096 kernel.pty.nr = 16 vm.overcommit_memory = 0 vm.panic_on_oom = 0 vm.oom_kill_allocating_task = 0 vm.oom_dump_tasks = 0 vm.overcommit_ratio = 50 vm.page-cluster = 3 vm.dirty_background_ratio = 10 vm.dirty_background_bytes = 0 vm.dirty_ratio = 20 vm.dirty_bytes = 0 vm.dirty_writeback_centisecs = 500 vm.dirty_expire_centisecs = 3000 vm.nr_pdflush_threads = 0 vm.swappiness = 60 vm.lowmem_reserve_ratio = 256 32 32 vm.drop_caches = 0 vm.min_free_kbytes = 3789 vm.percpu_pagelist_fraction = 0 vm.max_map_count = 65530 vm.laptop_mode = 0 vm.block_dump = 0 vm.vfs_cache_pressure = 100 vm.legacy_va_layout = 0 vm.stat_interval = 1 vm.mmap_min_addr = 4096 vm.vdso_enabled = 2 vm.highmem_is_dirtyable = 0 vm.scan_unevictable_pages = 0 fs.inode-nr = 183514 21755

390

fs.inode-state = 183514 21755 0 0 0 0 0 fs.file-nr = 3328 0 374104 fs.file-max = 374104 fs.nr_open = 1048576 fs.dentry-state = 164519 156162 45 0 0 0 fs.overflowuid = 65534 fs.overflowgid = 65534 fs.leases-enable = 1 fs.dir-notify-enable = 1 fs.lease-break-time = 45 fs.aio-nr = 0 fs.aio-max-nr = 65536 fs.inotify.max_user_instances = 128 fs.inotify.max_user_watches = 8192 fs.inotify.max_queued_events = 16384 fs.epoll.max_user_watches = 338510 fs.suid_dumpable = 0 fs.quota.lookups = 0 fs.quota.drops = 0 fs.quota.reads = 0 fs.quota.writes = 0 fs.quota.cache_hits = 0 fs.quota.allocated_dquots = 0 fs.quota.free_dquots = 0 fs.quota.syncs = 2 fs.nfs.nfs_callback_tcpport = 0 fs.nfs.idmap_cache_timeout = 600 fs.nfs.nfs_mountpoint_timeout = 500 fs.nfs.nfs_congestion_kb = 61888 fs.nfs.nlm_grace_period = 0 fs.nfs.nlm_timeout = 10 fs.nfs.nlm_udpport = 0 fs.nfs.nlm_tcpport = 0 fs.nfs.nsm_use_hostnames = 0 fs.nfs.nsm_local_state = 3 fs.xfs.irix_sgid_inherit = 0 fs.xfs.irix_symlink_mode = 0 fs.xfs.panic_mask = 0 fs.xfs.error_level = 3 fs.xfs.xfssyncd_centisecs = 3000 fs.xfs.inherit_sync = 1 fs.xfs.inherit_nodump = 1 fs.xfs.inherit_noatime = 1 fs.xfs.xfsbufd_centisecs = 100 fs.xfs.age_buffer_centisecs = 1500 fs.xfs.inherit_nosymlinks = 0 fs.xfs.rotorstep = 1 fs.xfs.inherit_nodefrag = 1 fs.xfs.filestream_centisecs = 3000 fs.xfs.stats_clear = 0 fs.ocfs2.nm.hb_ctl_path = /sbin/ocfs2_hb_ctl fs.mqueue.queues_max = 256 fs.mqueue.msg_max = 10 fs.mqueue.msgsize_max = 8192 debug.exception-trace = 1 dev.scsi.logging_level = 0 dev.raid.speed_limit_min = 1000 dev.raid.speed_limit_max = 200000 dev.hpet.max-user-freq = 64 dev.mac_hid.mouse_button_emulation = 0 dev.mac_hid.mouse_button2_keycode = 97 dev.mac_hid.mouse_button3_keycode = 100 dev.cdrom.info = CD-ROM information, Id: cdrom.c 3.20 2003/12/17 dev.cdrom.info = dev.cdrom.info = drive name: dev.cdrom.info = drive speed: dev.cdrom.info = drive # of slots: dev.cdrom.info = Can close tray: dev.cdrom.info = Can open tray: dev.cdrom.info = Can lock tray: dev.cdrom.info = Can change speed: dev.cdrom.info = Can select disk: dev.cdrom.info = Can read multisession: dev.cdrom.info = Can read MCN: dev.cdrom.info = Reports media changed: dev.cdrom.info = Can play audio: dev.cdrom.info = Can write CD-R: dev.cdrom.info = Can write CD-RW: dev.cdrom.info = Can read DVD: dev.cdrom.info = Can write DVD-R: dev.cdrom.info = Can write DVD-RAM: dev.cdrom.info = Can read MRW: dev.cdrom.info = Can write MRW:

391

dev.cdrom.info = Can write RAM: dev.cdrom.info = dev.cdrom.info = dev.cdrom.autoclose = 1 dev.cdrom.autoeject = 0 dev.cdrom.debug = 0 dev.cdrom.lock = 1 dev.cdrom.check_media = 0 dev.parport.default.timeslice = 200 dev.parport.default.spintime = 500 net.netfilter.nf_log.0 = NONE net.netfilter.nf_log.1 = NONE net.netfilter.nf_log.2 = ipt_LOG net.netfilter.nf_log.3 = NONE net.netfilter.nf_log.4 = NONE net.netfilter.nf_log.5 = NONE net.netfilter.nf_log.6 = NONE net.netfilter.nf_log.7 = NONE net.netfilter.nf_log.8 = NONE net.netfilter.nf_log.9 = NONE net.netfilter.nf_log.10 = NONE net.netfilter.nf_log.11 = NONE net.netfilter.nf_log.12 = NONE net.netfilter.nf_conntrack_generic_timeout = 600 net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 120 net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 60 net.netfilter.nf_conntrack_tcp_timeout_established = 432000 net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 120 net.netfilter.nf_conntrack_tcp_timeout_close_wait = 60 net.netfilter.nf_conntrack_tcp_timeout_last_ack = 30 net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120 net.netfilter.nf_conntrack_tcp_timeout_close = 10 net.netfilter.nf_conntrack_tcp_timeout_max_retrans = 300 net.netfilter.nf_conntrack_tcp_timeout_unacknowledged = 300 net.netfilter.nf_conntrack_tcp_loose = 1 net.netfilter.nf_conntrack_tcp_be_liberal = 0 net.netfilter.nf_conntrack_tcp_max_retrans = 3 net.netfilter.nf_conntrack_udp_timeout = 30 net.netfilter.nf_conntrack_udp_timeout_stream = 180 net.netfilter.nf_conntrack_icmp_timeout = 30 net.netfilter.nf_conntrack_acct = 1 net.netfilter.nf_conntrack_max = 65536 net.netfilter.nf_conntrack_count = 1 net.netfilter.nf_conntrack_buckets = 16384 net.netfilter.nf_conntrack_checksum = 1 net.netfilter.nf_conntrack_log_invalid = 0 net.netfilter.nf_conntrack_expect_max = 256 net.core.somaxconn = 128 net.core.xfrm_aevent_etime = 10 net.core.xfrm_aevent_rseqth = 2 net.core.xfrm_larval_drop = 1 net.core.xfrm_acq_expires = 30 net.core.wmem_max = 131071 net.core.rmem_max = 131071 net.core.wmem_default = 112640 net.core.rmem_default = 112640 net.core.dev_weight = 64 net.core.netdev_max_backlog = 1000 net.core.message_cost = 5 net.core.message_burst = 10 net.core.optmem_max = 10240 net.core.netdev_budget = 300 net.core.warnings = 1 error: permission denied on key net.ipv4.route.flush error: permission denied on key net.ipv6.route.flush net.ipv4.route.gc_thresh = 32768 net.ipv4.route.max_size = 524288 net.ipv4.route.gc_min_interval = 0 net.ipv4.route.gc_min_interval_ms = 500 net.ipv4.route.gc_timeout = 300 net.ipv4.route.gc_interval = 60 net.ipv4.route.redirect_load = 20 net.ipv4.route.redirect_number = 9 net.ipv4.route.redirect_silence = 20480 net.ipv4.route.error_cost = 1000 net.ipv4.route.error_burst = 5000 net.ipv4.route.gc_elasticity = 8 net.ipv4.route.mtu_expires = 600 net.ipv4.route.min_pmtu = 552 net.ipv4.route.min_adv_mss = 256 net.ipv4.route.secret_interval = 600

392

net.ipv4.neigh.default.mcast_solicit = 3 net.ipv4.neigh.default.ucast_solicit = 3 net.ipv4.neigh.default.app_solicit = 0 net.ipv4.neigh.default.retrans_time = 99 net.ipv4.neigh.default.base_reachable_time = 30 net.ipv4.neigh.default.delay_first_probe_time = 5 net.ipv4.neigh.default.gc_stale_time = 60 net.ipv4.neigh.default.unres_qlen = 3 net.ipv4.neigh.default.proxy_qlen = 64 net.ipv4.neigh.default.anycast_delay = 99 net.ipv4.neigh.default.proxy_delay = 79 net.ipv4.neigh.default.locktime = 99 net.ipv4.neigh.default.retrans_time_ms = 1000 net.ipv4.neigh.default.base_reachable_time_ms = 30000 net.ipv4.neigh.default.gc_interval = 30 net.ipv4.neigh.default.gc_thresh1 = 128 net.ipv4.neigh.default.gc_thresh2 = 512 net.ipv4.neigh.default.gc_thresh3 = 1024 net.ipv4.neigh.lo.mcast_solicit = 3 net.ipv4.neigh.lo.ucast_solicit = 3 net.ipv4.neigh.lo.app_solicit = 0 net.ipv4.neigh.lo.retrans_time = 99 net.ipv4.neigh.lo.base_reachable_time = 30 net.ipv4.neigh.lo.delay_first_probe_time = 5 net.ipv4.neigh.lo.gc_stale_time = 60 net.ipv4.neigh.lo.unres_qlen = 3 net.ipv4.neigh.lo.proxy_qlen = 64 net.ipv4.neigh.lo.anycast_delay = 99 net.ipv4.neigh.lo.proxy_delay = 79 net.ipv4.neigh.lo.locktime = 99 net.ipv4.neigh.lo.retrans_time_ms = 1000 net.ipv4.neigh.lo.base_reachable_time_ms = 30000 net.ipv4.neigh.eth0.mcast_solicit = 3 net.ipv4.neigh.eth0.ucast_solicit = 3 net.ipv4.neigh.eth0.app_solicit = 0 net.ipv4.neigh.eth0.retrans_time = 99 net.ipv4.neigh.eth0.base_reachable_time = 30 net.ipv4.neigh.eth0.delay_first_probe_time = 5 net.ipv4.neigh.eth0.gc_stale_time = 60 net.ipv4.neigh.eth0.unres_qlen = 3 net.ipv4.neigh.eth0.proxy_qlen = 64 net.ipv4.neigh.eth0.anycast_delay = 99 net.ipv4.neigh.eth0.proxy_delay = 79 net.ipv4.neigh.eth0.locktime = 99 net.ipv4.neigh.eth0.retrans_time_ms = 1000 net.ipv4.neigh.eth0.base_reachable_time_ms = 30000 net.ipv4.neigh.vboxnet0.mcast_solicit = 3 net.ipv4.neigh.vboxnet0.ucast_solicit = 3 net.ipv4.neigh.vboxnet0.app_solicit = 0 net.ipv4.neigh.vboxnet0.retrans_time = 99 net.ipv4.neigh.vboxnet0.base_reachable_time = 30 net.ipv4.neigh.vboxnet0.delay_first_probe_time = 5 net.ipv4.neigh.vboxnet0.gc_stale_time = 60 net.ipv4.neigh.vboxnet0.unres_qlen = 3 net.ipv4.neigh.vboxnet0.proxy_qlen = 64 net.ipv4.neigh.vboxnet0.anycast_delay = 99 net.ipv4.neigh.vboxnet0.proxy_delay = 79 net.ipv4.neigh.vboxnet0.locktime = 99 net.ipv4.neigh.vboxnet0.retrans_time_ms = 1000 net.ipv4.neigh.vboxnet0.base_reachable_time_ms = 30000 net.ipv4.tcp_timestamps = 1 net.ipv4.tcp_window_scaling = 1 net.ipv4.tcp_sack = 1 net.ipv4.tcp_retrans_collapse = 1 net.ipv4.ip_default_ttl = 64 net.ipv4.ip_no_pmtu_disc = 0 net.ipv4.ip_nonlocal_bind = 0 net.ipv4.tcp_syn_retries = 5 net.ipv4.tcp_synack_retries = 5 net.ipv4.tcp_max_orphans = 32768 net.ipv4.tcp_max_tw_buckets = 180000 net.ipv4.ip_dynaddr = 0 net.ipv4.tcp_keepalive_time = 7200 net.ipv4.tcp_keepalive_probes = 9 net.ipv4.tcp_keepalive_intvl = 75 net.ipv4.tcp_retries1 = 3 net.ipv4.tcp_retries2 = 15 net.ipv4.tcp_fin_timeout = 60 net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_tw_recycle = 0 net.ipv4.tcp_abort_on_overflow = 0 net.ipv4.tcp_stdurg = 0 net.ipv4.tcp_rfc1337 = 0

393

net.ipv4.tcp_max_syn_backlog = 1024 net.ipv4.ip_local_port_range = 32768 61000 net.ipv4.igmp_max_memberships = 20 net.ipv4.igmp_max_msf = 10 net.ipv4.inet_peer_threshold = 65664 net.ipv4.inet_peer_minttl = 120 net.ipv4.inet_peer_maxttl = 600 net.ipv4.inet_peer_gc_mintime = 10 net.ipv4.inet_peer_gc_maxtime = 120 net.ipv4.tcp_orphan_retries = 0 net.ipv4.tcp_fack = 1 net.ipv4.tcp_reordering = 3 net.ipv4.tcp_ecn = 2 net.ipv4.tcp_dsack = 1 net.ipv4.tcp_mem = 80544 107392 161088 net.ipv4.tcp_wmem = 4096 16384 3436544 net.ipv4.tcp_rmem = 4096 87380 3436544 net.ipv4.tcp_app_win = 31 net.ipv4.tcp_adv_win_scale = 2 net.ipv4.tcp_tw_reuse = 0 net.ipv4.tcp_frto = 2 net.ipv4.tcp_frto_response = 0 net.ipv4.tcp_low_latency = 0 net.ipv4.tcp_no_metrics_save = 0 net.ipv4.tcp_moderate_rcvbuf = 1 net.ipv4.tcp_tso_win_divisor = 3 net.ipv4.tcp_congestion_control = cubic net.ipv4.tcp_abc = 0 net.ipv4.tcp_mtu_probing = 0 net.ipv4.tcp_base_mss = 512 net.ipv4.tcp_workaround_signed_windows = 0 net.ipv4.tcp_dma_copybreak = 4096 net.ipv4.tcp_slow_start_after_idle = 1 net.ipv4.tcp_available_congestion_control = cubic reno net.ipv4.tcp_allowed_congestion_control = cubic reno net.ipv4.tcp_max_ssthresh = 0 net.ipv4.tcp_cookie_size = 0 net.ipv4.udp_mem = 80544 107392 161088 net.ipv4.udp_rmem_min = 4096 net.ipv4.udp_wmem_min = 4096 net.ipv4.netfilter.ip_conntrack_generic_timeout = 600 net.ipv4.netfilter.ip_conntrack_tcp_timeout_syn_sent = 120 net.ipv4.netfilter.ip_conntrack_tcp_timeout_syn_sent2 = 120 net.ipv4.netfilter.ip_conntrack_tcp_timeout_syn_recv = 60 net.ipv4.netfilter.ip_conntrack_tcp_timeout_established = 432000 net.ipv4.netfilter.ip_conntrack_tcp_timeout_fin_wait = 120 net.ipv4.netfilter.ip_conntrack_tcp_timeout_close_wait = 60 net.ipv4.netfilter.ip_conntrack_tcp_timeout_last_ack = 30 net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait = 120 net.ipv4.netfilter.ip_conntrack_tcp_timeout_close = 10 net.ipv4.netfilter.ip_conntrack_tcp_timeout_max_retrans = 300 net.ipv4.netfilter.ip_conntrack_tcp_loose = 1 net.ipv4.netfilter.ip_conntrack_tcp_be_liberal = 0 net.ipv4.netfilter.ip_conntrack_tcp_max_retrans = 3 net.ipv4.netfilter.ip_conntrack_udp_timeout = 30 net.ipv4.netfilter.ip_conntrack_udp_timeout_stream = 180 net.ipv4.netfilter.ip_conntrack_icmp_timeout = 30 net.ipv4.netfilter.ip_conntrack_max = 65536 net.ipv4.netfilter.ip_conntrack_count = 1 net.ipv4.netfilter.ip_conntrack_buckets = 16384 net.ipv4.netfilter.ip_conntrack_checksum = 1 net.ipv4.netfilter.ip_conntrack_log_invalid = 0 net.ipv4.conf.all.forwarding = 0 net.ipv4.conf.all.mc_forwarding = 0 net.ipv4.conf.all.accept_redirects = 1 net.ipv4.conf.all.secure_redirects = 1 net.ipv4.conf.all.shared_media = 1 net.ipv4.conf.all.rp_filter = 0 net.ipv4.conf.all.send_redirects = 1 net.ipv4.conf.all.accept_source_route = 0 net.ipv4.conf.all.accept_local = 0 net.ipv4.conf.all.src_valid_mark = 0 net.ipv4.conf.all.proxy_arp = 0 net.ipv4.conf.all.medium_id = 0 net.ipv4.conf.all.bootp_relay = 0 net.ipv4.conf.all.log_martians = 0 net.ipv4.conf.all.tag = 0 net.ipv4.conf.all.arp_filter = 0 net.ipv4.conf.all.arp_announce = 0 net.ipv4.conf.all.arp_ignore = 0 net.ipv4.conf.all.arp_accept = 0 net.ipv4.conf.all.arp_notify = 0 net.ipv4.conf.all.disable_xfrm = 0

394

net.ipv4.conf.all.disable_policy = 0 net.ipv4.conf.all.force_igmp_version = 0 net.ipv4.conf.all.promote_secondaries = 0 net.ipv4.conf.default.forwarding = 0 net.ipv4.conf.default.mc_forwarding = 0 net.ipv4.conf.default.accept_redirects = 1 net.ipv4.conf.default.secure_redirects = 1 net.ipv4.conf.default.shared_media = 1 net.ipv4.conf.default.rp_filter = 0 net.ipv4.conf.default.send_redirects = 1 net.ipv4.conf.default.accept_source_route = 1 net.ipv4.conf.default.accept_local = 0 net.ipv4.conf.default.src_valid_mark = 0 net.ipv4.conf.default.proxy_arp = 0 net.ipv4.conf.default.medium_id = 0 net.ipv4.conf.default.bootp_relay = 0 net.ipv4.conf.default.log_martians = 0 net.ipv4.conf.default.tag = 0 net.ipv4.conf.default.arp_filter = 0 net.ipv4.conf.default.arp_announce = 0 net.ipv4.conf.default.arp_ignore = 0 net.ipv4.conf.default.arp_accept = 0 net.ipv4.conf.default.arp_notify = 0 net.ipv4.conf.default.disable_xfrm = 0 net.ipv4.conf.default.disable_policy = 0 net.ipv4.conf.default.force_igmp_version = 0 net.ipv4.conf.default.promote_secondaries = 0 net.ipv4.conf.lo.forwarding = 0 net.ipv4.conf.lo.mc_forwarding = 0 net.ipv4.conf.lo.accept_redirects = 1 net.ipv4.conf.lo.secure_redirects = 1 net.ipv4.conf.lo.shared_media = 1 net.ipv4.conf.lo.rp_filter = 0 net.ipv4.conf.lo.send_redirects = 1 net.ipv4.conf.lo.accept_source_route = 1 net.ipv4.conf.lo.accept_local = 0 net.ipv4.conf.lo.src_valid_mark = 0 net.ipv4.conf.lo.proxy_arp = 0 net.ipv4.conf.lo.medium_id = 0 net.ipv4.conf.lo.bootp_relay = 0 net.ipv4.conf.lo.log_martians = 0 net.ipv4.conf.lo.tag = 0 net.ipv4.conf.lo.arp_filter = 0 net.ipv4.conf.lo.arp_announce = 0 net.ipv4.conf.lo.arp_ignore = 0 net.ipv4.conf.lo.arp_accept = 0 net.ipv4.conf.lo.arp_notify = 0 net.ipv4.conf.lo.disable_xfrm = 1 net.ipv4.conf.lo.disable_policy = 1 net.ipv4.conf.lo.force_igmp_version = 0 net.ipv4.conf.lo.promote_secondaries = 0 net.ipv4.conf.eth0.forwarding = 0 net.ipv4.conf.eth0.mc_forwarding = 0 net.ipv4.conf.eth0.accept_redirects = 1 net.ipv4.conf.eth0.secure_redirects = 1 net.ipv4.conf.eth0.shared_media = 1 net.ipv4.conf.eth0.rp_filter = 0 net.ipv4.conf.eth0.send_redirects = 1 net.ipv4.conf.eth0.accept_source_route = 1 net.ipv4.conf.eth0.accept_local = 0 net.ipv4.conf.eth0.src_valid_mark = 0 net.ipv4.conf.eth0.proxy_arp = 0 net.ipv4.conf.eth0.medium_id = 0 net.ipv4.conf.eth0.bootp_relay = 0 net.ipv4.conf.eth0.log_martians = 0 net.ipv4.conf.eth0.tag = 0 net.ipv4.conf.eth0.arp_filter = 0 net.ipv4.conf.eth0.arp_announce = 0 net.ipv4.conf.eth0.arp_ignore = 0 net.ipv4.conf.eth0.arp_accept = 0 net.ipv4.conf.eth0.arp_notify = 0 net.ipv4.conf.eth0.disable_xfrm = 0 net.ipv4.conf.eth0.disable_policy = 0 net.ipv4.conf.eth0.force_igmp_version = 0 net.ipv4.conf.eth0.promote_secondaries = 1 net.ipv4.conf.vboxnet0.forwarding = 0 net.ipv4.conf.vboxnet0.mc_forwarding = 0 net.ipv4.conf.vboxnet0.accept_redirects = 1 net.ipv4.conf.vboxnet0.secure_redirects = 1 net.ipv4.conf.vboxnet0.shared_media = 1 net.ipv4.conf.vboxnet0.rp_filter = 0 net.ipv4.conf.vboxnet0.send_redirects = 1 net.ipv4.conf.vboxnet0.accept_source_route = 1

395

net.ipv4.conf.vboxnet0.accept_local = 0 net.ipv4.conf.vboxnet0.src_valid_mark = 0 net.ipv4.conf.vboxnet0.proxy_arp = 0 net.ipv4.conf.vboxnet0.medium_id = 0 net.ipv4.conf.vboxnet0.bootp_relay = 0 net.ipv4.conf.vboxnet0.log_martians = 0 net.ipv4.conf.vboxnet0.tag = 0 net.ipv4.conf.vboxnet0.arp_filter = 0 net.ipv4.conf.vboxnet0.arp_announce = 0 net.ipv4.conf.vboxnet0.arp_ignore = 0 net.ipv4.conf.vboxnet0.arp_accept = 0 net.ipv4.conf.vboxnet0.arp_notify = 0 net.ipv4.conf.vboxnet0.disable_xfrm = 0 net.ipv4.conf.vboxnet0.disable_policy = 0 net.ipv4.conf.vboxnet0.force_igmp_version = 0 net.ipv4.conf.vboxnet0.promote_secondaries = 0 net.ipv4.ip_forward = 0 net.ipv4.xfrm4_gc_thresh = 262144 net.ipv4.ipfrag_high_thresh = 262144 net.ipv4.ipfrag_low_thresh = 196608 net.ipv4.ipfrag_time = 30 net.ipv4.icmp_echo_ignore_all = 0 net.ipv4.icmp_echo_ignore_broadcasts = 1 net.ipv4.icmp_ignore_bogus_error_responses = 1 net.ipv4.icmp_errors_use_inbound_ifaddr = 0 net.ipv4.icmp_ratelimit = 1000 net.ipv4.icmp_ratemask = 6168 net.ipv4.rt_cache_rebuild_count = 4 net.ipv4.ipfrag_secret_interval = 600 net.ipv4.ipfrag_max_dist = 64 net.ipv6.neigh.default.mcast_solicit = 3 net.ipv6.neigh.default.ucast_solicit = 3 net.ipv6.neigh.default.app_solicit = 0 net.ipv6.neigh.default.retrans_time = 1000 net.ipv6.neigh.default.base_reachable_time = 30 net.ipv6.neigh.default.delay_first_probe_time = 5 net.ipv6.neigh.default.gc_stale_time = 60 net.ipv6.neigh.default.unres_qlen = 3 net.ipv6.neigh.default.proxy_qlen = 64 net.ipv6.neigh.default.anycast_delay = 99 net.ipv6.neigh.default.proxy_delay = 79 net.ipv6.neigh.default.locktime = 0 net.ipv6.neigh.default.retrans_time_ms = 1000 net.ipv6.neigh.default.base_reachable_time_ms = 30000 net.ipv6.neigh.default.gc_interval = 30 net.ipv6.neigh.default.gc_thresh1 = 128 net.ipv6.neigh.default.gc_thresh2 = 512 net.ipv6.neigh.default.gc_thresh3 = 1024 net.ipv6.neigh.lo.mcast_solicit = 3 net.ipv6.neigh.lo.ucast_solicit = 3 net.ipv6.neigh.lo.app_solicit = 0 net.ipv6.neigh.lo.retrans_time = 1000 net.ipv6.neigh.lo.base_reachable_time = 30 net.ipv6.neigh.lo.delay_first_probe_time = 5 net.ipv6.neigh.lo.gc_stale_time = 60 net.ipv6.neigh.lo.unres_qlen = 3 net.ipv6.neigh.lo.proxy_qlen = 64 net.ipv6.neigh.lo.anycast_delay = 99 net.ipv6.neigh.lo.proxy_delay = 79 net.ipv6.neigh.lo.locktime = 0 net.ipv6.neigh.lo.retrans_time_ms = 1000 net.ipv6.neigh.lo.base_reachable_time_ms = 30000 net.ipv6.neigh.eth0.mcast_solicit = 3 net.ipv6.neigh.eth0.ucast_solicit = 3 net.ipv6.neigh.eth0.app_solicit = 0 net.ipv6.neigh.eth0.retrans_time = 1000 net.ipv6.neigh.eth0.base_reachable_time = 30 net.ipv6.neigh.eth0.delay_first_probe_time = 5 net.ipv6.neigh.eth0.gc_stale_time = 60 net.ipv6.neigh.eth0.unres_qlen = 3 net.ipv6.neigh.eth0.proxy_qlen = 64 net.ipv6.neigh.eth0.anycast_delay = 99 net.ipv6.neigh.eth0.proxy_delay = 79 net.ipv6.neigh.eth0.locktime = 0 net.ipv6.neigh.eth0.retrans_time_ms = 1000 net.ipv6.neigh.eth0.base_reachable_time_ms = 30000 net.ipv6.neigh.vboxnet0.mcast_solicit = 3 net.ipv6.neigh.vboxnet0.ucast_solicit = 3 net.ipv6.neigh.vboxnet0.app_solicit = 0 net.ipv6.neigh.vboxnet0.retrans_time = 1000 net.ipv6.neigh.vboxnet0.base_reachable_time = 30 net.ipv6.neigh.vboxnet0.delay_first_probe_time = 5 net.ipv6.neigh.vboxnet0.gc_stale_time = 60

396

net.ipv6.neigh.vboxnet0.unres_qlen = 3 net.ipv6.neigh.vboxnet0.proxy_qlen = 64 net.ipv6.neigh.vboxnet0.anycast_delay = 99 net.ipv6.neigh.vboxnet0.proxy_delay = 79 net.ipv6.neigh.vboxnet0.locktime = 0 net.ipv6.neigh.vboxnet0.retrans_time_ms = 1000 net.ipv6.neigh.vboxnet0.base_reachable_time_ms = 30000 net.ipv6.xfrm6_gc_thresh = 1024 net.ipv6.conf.all.forwarding = 0 net.ipv6.conf.all.hop_limit = 64 net.ipv6.conf.all.mtu = 1280 net.ipv6.conf.all.accept_ra = 1 net.ipv6.conf.all.accept_redirects = 1 net.ipv6.conf.all.autoconf = 1 net.ipv6.conf.all.dad_transmits = 1 net.ipv6.conf.all.router_solicitations = 3 net.ipv6.conf.all.router_solicitation_interval = 4 net.ipv6.conf.all.router_solicitation_delay = 1 net.ipv6.conf.all.force_mld_version = 0 net.ipv6.conf.all.use_tempaddr = 0 net.ipv6.conf.all.temp_valid_lft = 604800 net.ipv6.conf.all.temp_prefered_lft = 86400 net.ipv6.conf.all.regen_max_retry = 5 net.ipv6.conf.all.max_desync_factor = 600 net.ipv6.conf.all.max_addresses = 16 net.ipv6.conf.all.accept_ra_defrtr = 1 net.ipv6.conf.all.accept_ra_pinfo = 1 net.ipv6.conf.all.proxy_ndp = 0 net.ipv6.conf.all.accept_source_route = 0 net.ipv6.conf.all.disable_ipv6 = 0 net.ipv6.conf.all.accept_dad = 1 net.ipv6.conf.all.force_tllao = 0 net.ipv6.conf.default.forwarding = 0 net.ipv6.conf.default.hop_limit = 64 net.ipv6.conf.default.mtu = 1280 net.ipv6.conf.default.accept_ra = 1 net.ipv6.conf.default.accept_redirects = 1 net.ipv6.conf.default.autoconf = 1 net.ipv6.conf.default.dad_transmits = 1 net.ipv6.conf.default.router_solicitations = 3 net.ipv6.conf.default.router_solicitation_interval = 4 net.ipv6.conf.default.router_solicitation_delay = 1 net.ipv6.conf.default.force_mld_version = 0 net.ipv6.conf.default.use_tempaddr = 0 net.ipv6.conf.default.temp_valid_lft = 604800 net.ipv6.conf.default.temp_prefered_lft = 86400 net.ipv6.conf.default.regen_max_retry = 5 net.ipv6.conf.default.max_desync_factor = 600 net.ipv6.conf.default.max_addresses = 16 net.ipv6.conf.default.accept_ra_defrtr = 1 net.ipv6.conf.default.accept_ra_pinfo = 1 net.ipv6.conf.default.proxy_ndp = 0 net.ipv6.conf.default.accept_source_route = 0 net.ipv6.conf.default.disable_ipv6 = 0 net.ipv6.conf.default.accept_dad = 1 net.ipv6.conf.default.force_tllao = 0 net.ipv6.conf.lo.forwarding = 0 net.ipv6.conf.lo.hop_limit = 64 net.ipv6.conf.lo.mtu = 16436 net.ipv6.conf.lo.accept_ra = 1 net.ipv6.conf.lo.accept_redirects = 1 net.ipv6.conf.lo.autoconf = 1 net.ipv6.conf.lo.dad_transmits = 1 net.ipv6.conf.lo.router_solicitations = 3 net.ipv6.conf.lo.router_solicitation_interval = 4 net.ipv6.conf.lo.router_solicitation_delay = 1 net.ipv6.conf.lo.force_mld_version = 0 net.ipv6.conf.lo.use_tempaddr = -1 net.ipv6.conf.lo.temp_valid_lft = 604800 net.ipv6.conf.lo.temp_prefered_lft = 86400 net.ipv6.conf.lo.regen_max_retry = 5 net.ipv6.conf.lo.max_desync_factor = 600 net.ipv6.conf.lo.max_addresses = 16 net.ipv6.conf.lo.accept_ra_defrtr = 1 net.ipv6.conf.lo.accept_ra_pinfo = 1 net.ipv6.conf.lo.proxy_ndp = 0 net.ipv6.conf.lo.accept_source_route = 0 net.ipv6.conf.lo.disable_ipv6 = 0 net.ipv6.conf.lo.accept_dad = -1 net.ipv6.conf.lo.force_tllao = 0 net.ipv6.conf.eth0.forwarding = 0 net.ipv6.conf.eth0.hop_limit = 64 net.ipv6.conf.eth0.mtu = 1500

397

net.ipv6.conf.eth0.accept_ra = 1 net.ipv6.conf.eth0.accept_redirects = 1 net.ipv6.conf.eth0.autoconf = 1 net.ipv6.conf.eth0.dad_transmits = 1 net.ipv6.conf.eth0.router_solicitations = 3 net.ipv6.conf.eth0.router_solicitation_interval = 4 net.ipv6.conf.eth0.router_solicitation_delay = 1 net.ipv6.conf.eth0.force_mld_version = 0 net.ipv6.conf.eth0.use_tempaddr = 0 net.ipv6.conf.eth0.temp_valid_lft = 604800 net.ipv6.conf.eth0.temp_prefered_lft = 86400 net.ipv6.conf.eth0.regen_max_retry = 5 net.ipv6.conf.eth0.max_desync_factor = 600 net.ipv6.conf.eth0.max_addresses = 16 net.ipv6.conf.eth0.accept_ra_defrtr = 1 net.ipv6.conf.eth0.accept_ra_pinfo = 1 net.ipv6.conf.eth0.proxy_ndp = 0 net.ipv6.conf.eth0.accept_source_route = 0 net.ipv6.conf.eth0.disable_ipv6 = 0 net.ipv6.conf.eth0.accept_dad = 1 net.ipv6.conf.eth0.force_tllao = 0 net.ipv6.conf.vboxnet0.forwarding = 0 net.ipv6.conf.vboxnet0.hop_limit = 64 net.ipv6.conf.vboxnet0.mtu = 1500 net.ipv6.conf.vboxnet0.accept_ra = 1 net.ipv6.conf.vboxnet0.accept_redirects = 1 net.ipv6.conf.vboxnet0.autoconf = 1 net.ipv6.conf.vboxnet0.dad_transmits = 1 net.ipv6.conf.vboxnet0.router_solicitations = 3 net.ipv6.conf.vboxnet0.router_solicitation_interval = 4 net.ipv6.conf.vboxnet0.router_solicitation_delay = 1 net.ipv6.conf.vboxnet0.force_mld_version = 0 net.ipv6.conf.vboxnet0.use_tempaddr = 0 net.ipv6.conf.vboxnet0.temp_valid_lft = 604800 net.ipv6.conf.vboxnet0.temp_prefered_lft = 86400 net.ipv6.conf.vboxnet0.regen_max_retry = 5 net.ipv6.conf.vboxnet0.max_desync_factor = 600 net.ipv6.conf.vboxnet0.max_addresses = 16 net.ipv6.conf.vboxnet0.accept_ra_defrtr = 1 net.ipv6.conf.vboxnet0.accept_ra_pinfo = 1 net.ipv6.conf.vboxnet0.proxy_ndp = 0 net.ipv6.conf.vboxnet0.accept_source_route = 0 net.ipv6.conf.vboxnet0.disable_ipv6 = 0 net.ipv6.conf.vboxnet0.accept_dad = 1 net.ipv6.conf.vboxnet0.force_tllao = 0 net.ipv6.ip6frag_high_thresh = 262144 net.ipv6.ip6frag_low_thresh = 196608 net.ipv6.ip6frag_time = 60 net.ipv6.route.gc_thresh = 1024 net.ipv6.route.max_size = 4096 net.ipv6.route.gc_min_interval = 0 net.ipv6.route.gc_timeout = 60 net.ipv6.route.gc_interval = 30 net.ipv6.route.gc_elasticity = 0 net.ipv6.route.mtu_expires = 600 net.ipv6.route.min_adv_mss = 1 net.ipv6.route.gc_min_interval_ms = 500 net.ipv6.icmp.ratelimit = 1000 net.ipv6.bindv6only = 0 net.ipv6.ip6frag_secret_interval = 600 net.ipv6.mld_max_msf = 64 net.nf_conntrack_max = 65536 net.unix.max_dgram_qlen = 10 sunrpc.rpc_debug = 0 sunrpc.nfs_debug = 0 sunrpc.nfsd_debug = 0 sunrpc.nlm_debug = 0 sunrpc.transports = tcp 1048576 sunrpc.transports = udp 32768 sunrpc.udp_slot_table_entries = 16 sunrpc.tcp_slot_table_entries = 16 sunrpc.min_resvport = 665 sunrpc.max_resvport = 1023 sunrpc.tcp_fin_timeout = 15 crypto.fips_enabled = 0

H.3

Ano de 1970

Fonte: http://www.casadovideo.com/fatosedatas/livro.htm . Andre Agassi, tenista; nascimento, em 29-04-1970

398

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Argentina; presidente Ongania \e derrubado por um golpe militar, em 08-06-1970 Bertrand Russel; morte, em 02-02-1970 Bol\ivia; golpe militar leva ao poder o general nacionalista Juan Jos\e Torres, em 07-10-1970 Censura pr\evia a livros e peri\{o}dicos \e institu\ida por decreto-lei aprovado pela C\^amara, em 13-01-1970 Charles De Gaulle; morte, em 09-11-1970 Chile; Salvador Allende \e eleito presidente e tenta implementar "via pac\ifica para o socialismo", em 24-10-1970 Elei\c{c}\~oes parlamentares; Arena faz 223 deputados, contra 87, do MDB, em 15-11-1970 Futebol; Brasil conquista o tricampeonato mundial no M\exico; a ditadura explora a vit\{o}ria, em 21-06-1970 Gabriela Sabatini, tenista argentina; nascimento, em 16-05-1970 Guerrilha; avi\~ao da Cruzeiro \e seq\"uestrado, em 01-01-1970 Guerrilha; c\^onsul do Jap\~ao em SP \e seq\"uestrado e depois trocado pela liberta\c{c}\~ao de 5 presos pol\iticos, em 11-03-1970 Guerrilha; noticiado o cerco a Lamarca no Vale do Ribeira, SP, por 5 mil soldados, com a fuga dos guerrilheiros escapam, em 18-04-1970 Guerrilha; seq\"uestrado um boeing 737 da Vasp, em 25-04-1970 Guerrilha; embaixador alem\~ao \e seq\"uestrado no RJ e depois trocado pela liberta\c{c}\~ao de 40 presos pol\iticos, em 11-06-1970 Guerrilha; c\^onsul brasileiro, A. Gomide, \e seq\"uestrado em Montevid\eu por guerrilheiros Tupamaros, em 31-07-1970 Guerrilha; Joaquim da C\^amara Ferreira, o "Velho", dirigente da ALN, \e preso em SP e morto horas depois, em 23-10-1970 Guerrilha; a VPR seq\"uestra o embaixador su\i\c{c}o no RJ (depois, trocado pela liberta\c{c}\~ao de 70 presos pol\iticos), em 07-12-1970 Guerrilha; Eduardo Leite, o Bacuri, da VPR, morre sob tortura no Dops-SP, em 08-12-1970 Incra - Instituto Nacional de Coloniza\c{c}\~ao e Reforma Agr\aria; cria\c{c}\~ao, em 09-07-1970 Jaime Oncins, tenista; nascimento, em 16-06-1970 Janis Joplin, cantora norte-americana; morte, em 04-10-1970 Jimi Hendrix (James Marshall Hendrix), guitarrista e cantor norte-americano; \ultimo concerto, em 04-09-1970 Jimi Hendrix; morte, em 18-09-1970 M\ario Alves, l\ider do PCBR, \e morto sob tortura no primeiro Batalh\~ao da Pol\icia do Ex\ercito, no RJ, em 16-01-1970 M\edici diz em Porto Alegre que "o homem n\~ao foi feito para a democracia", em 08-10-1970 Moeda; cruzeiro novo volta a chamar-se cruzeiro, em 15-05-1970 O Pasquim; governo M\edici manda prender toda a "turma do Pasquim", em 04-11-1970 OEA recebe den\uncia de torturas no Brasil da Comiss\~ao Internacional de Juristas, de Genebra, em 24-07-1970 Olavo Hansen, oper\ario, \e preso em SP e encontrado morto uma semana depois, em 01-05-1970 Oscarito, um dos principais atores das chanchadas; morte, em 04-08-1970 Paquist\~ao; enchentes deixam o saldo de 300 mil v\itimas, em 13-11-1970 Paulo Evaristo Arns assume a arquidiocese de S\~ao Paulo, em 22-10-1970 Portugal; golpe derruba a Primeira Rep\ublica e leva Salazar ao poder (at\e a morte, em 1970), em 28-05-1926 Recenseamento; o Brasil tem 93.139.037 habitantes, em 01-09-1970 Rodovia Transamaz\^onica; in\icio da constru\c{c}\~ao, em 09-10-1970 Salazar (Ant\^onio Carlos de Oliveira), ditador portugu\^es; morte, em 27-07-1970 Saques e invas\~oes no CE, RN, PE, PI e PB s\~ao iniciados por flagelados da seca, em 08-04-1970 Televis\~ao; inaugura\c{c}\~ao da TV Gazeta, em 25-01-1970 Televis\~ao; encerramento das transmiss\~oes da TV Excelsior, em 30-09-1970

399

400

Apndice I e Assembly
Apndice inclu e do pelo tradutor. No slackware temos o as, o yasm e o nasm.

I.1
Usando:

Al Mundo o

gcc -O2 -S bit-pos-loop.c Voc consegue: e

.file "bit-pos-loop.c" .text .p2align 4,,15 .globl main .type main, @function main: .LFB18: .cfi_startproc subq $24, %rsp .cfi_def_cfa_offset 32 movq 8(%rsi), %rdi movl $10, %edx xorl %esi, %esi call strtol movslq %eax, %rsi xorl %edx, %edx movl $1, %ecx testq %rsi, %rsi jle .L3 addq $1, %rcx movl %edx, 12(%rsp) cmpq %rcx, %rsi jl .L3 .p2align 4,,10 .p2align 3 .L6: movq %rcx, %rax xorl %edx, %edx sarq %rax .p2align 4,,10 .p2align 3 .L4: addl $1, %edx sarq %rax jne .L4 addq $1, %rcx movl %edx, 12(%rsp) cmpq %rcx, %rsi jge .L6 .L3: xorl %eax, %eax addq $24, %rsp

401

.cfi_def_cfa_offset 8 ret .cfi_endproc .LFE18: .size main, .-main .ident "GCC: (GNU) 4.5.2" .section .note.GNU-stack,"",@progbits Seja o nosso tradicional programa alo.c: #include <stdio.h> main() { printf("Al\^o Mundo!\n"); } Usando o comando: gcc -S -masm=intel -mtune=native alo.c Teremos a seguinte sa da em assembly x86 : .file "alo.c" .intel_syntax noprefix .section .rodata .LC0: .string "Al\303\264 Mundo!" .text .globl main .type main, @function main: .LFB0: .cfi_startproc push rbp .cfi_def_cfa_offset 16 mov rbp, rsp .cfi_offset 6, -16 .cfi_def_cfa_register 6 mov edi, OFFSET FLAT:.LC0 call puts leave .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (GNU) 4.5.2" .section .note.GNU-stack,"",@progbits Usando o comando abaixo gera-se o executvel a.out: a gcc alo.s

I.2

bsrl

bsr/bsf - bit scan forward e bit scan reverse - bsrl - sintaxe AT & T using as the GNU Assembler - verso 2.14 - Dean Elsner, Jay Fenlason & friends , p 128 a Em http://sourceware.org/binutils/docs/as/i386 002dSyntax.html#i386 002dSyntax temos:

In AT&T syntax the size of memory operands is determined from the last character of the instruction mnemonic. Mnemonic suffixes of b, w, l and q specify byte (8-bit), word (16-bit), long (32-bit) and quadruple word (64-bit) memory references. Intel syntax accomplishes this by prefixing memory operands (not the instruction mnemonics) with byte ptr, word ptr, dword ptr and qword ptr. Thus, Intel mov al, byte ptr foo is movb foo, %al in AT&T syntax. Na http://linuxgazette.net/94/ramankutty.html temos: From C To Assembly Language By Hiran Ramankutty

402

Apndice J e Segurana c
Apndice inclu e do pelo tradutor.

J.1
mostra setuid 01 -rwsr-sr-x 02 -rwsr-sr-x 03 -rwsr-sr-x mostra setuid 01 -rwsr-xr-x 02 -rwsr-xr-x 03 -rwsr-xr-x 04 -rwsr-xr-x 05 -rwsr-xr-x 06 -rwsr-xr-x 07 -rwsr-sr-x 08 -rwsr-xr-x 09 -rwsr-xr-x 10 -rwsr-xr-x 11 -rwsr-xr-x 12 -rwsr-xr-x 13 -rwsr-xr-x 14 -rwsr-xr-x 15 -rwsr-sr-x 16 -rwsr-xr-x 17 -rwsr-xr-x 18 -rwsr-sr-x 19 -rwsr-xr-20 -rwsr-xr-x 21 -rwsr-xr-x 22 -rwsr-xr-x 23 -rwsr-xr-x 24 -rwsr-xr-x mostra setuid 01 -rwxr-sr-x 02 -rwsr-sr-x 03 -rwxr-sr-x 04 -rwxr-sr-x 05 -rwxr-sr-x 06 -rwxr-sr-x 07 -rwxr-sr-x 08 -rwxr-sr-x 09 -rwxr-sr-x 10 -rwxr-sr-x 11 -rwsr-sr-x 12 -rwxr-sr-x 13 -rwxr-sr-x 14 -rwsr-sr-x 15 -rwxr-sr-x 16 -rwxr-sr-x 17 -rwxr-sr-x

Setuid no Debian 6.0.2


ativado em usu\arios e grupos e outros daemon daemon /usr/bin/at root mail /usr/bin/procmail root root /usr/bin/X ativado em usu\arios root root /bin/mount root root /bin/ping root root /bin/ping6 root root /bin/su root root /bin/umount root root /sbin/mount.nfs daemon daemon /usr/bin/at root root /usr/bin/chfn root root /usr/bin/chsh root root /usr/bin/gpasswd root lpadmin /usr/bin/lppasswd root root /usr/bin/newgrp root root /usr/bin/passwd root root /usr/bin/pkexec root mail /usr/bin/procmail root root /usr/bin/sudo root root /usr/bin/sudoedit root root /usr/bin/X root messagebus /usr/lib/dbus-1.0/dbus-daemon-launch-helper root root /usr/lib/eject/dmcrypt-get-device root root /usr/lib/openssh/ssh-keysign root root /usr/lib/policykit-1/polkit-agent-helper-1 root root /usr/lib/pt_chown root root /usr/sbin/exim4 ativado em grupos root shadow /sbin/unix_chkpwd daemon daemon /usr/bin/at root tty /usr/bin/bsd-write root shadow /usr/bin/chage root crontab /usr/bin/crontab root mail /usr/bin/dotlockfile root shadow /usr/bin/expiry root mail /usr/bin/lockfile root mlocate /usr/bin/mlocate root mail /usr/bin/mutt_dotlock root mail /usr/bin/procmail root ssh /usr/bin/ssh-agent root tty /usr/bin/wall root root /usr/bin/X root mail /usr/lib/evolution/camel-lock-helper-1.2 root utmp /usr/lib/libvte9/gnome-pty-helper root tty /usr/lib/mc/cons.saver

403

404

Apndice K e Anexos aos Apndices e


Apndice inclu e do pelo tradutor.

K.1
#define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define /* #define */ #define #define #define

Signal.h

O trecho abaixo foi retirado do /usr/include/asm/signal.h de um Ubuntu 10.04 LTS 32 bits:

SIGHUP 1 SIGINT 2 SIGQUIT 3 SIGILL 4 SIGTRAP 5 SIGABRT 6 SIGIOT 6 SIGBUS 7 SIGFPE 8 SIGKILL 9 SIGUSR1 10 SIGSEGV 11 SIGUSR2 12 SIGPIPE 13 SIGALRM 14 SIGTERM 15 SIGSTKFLT 16 SIGCHLD 17 SIGCONT 18 SIGSTOP 19 SIGTSTP 20 SIGTTIN 21 SIGTTOU 22 SIGURG 23 SIGXCPU 24 SIGXFSZ 25 SIGVTALRM 26 SIGPROF 27 SIGWINCH 28 SIGIO 29 SIGPOLL SIGIO SIGLOST 29 SIGPWR 30 SIGSYS 31 SIGUNUSED 31 */

/* These should not be considered constants from userland. #define SIGRTMIN 32 #define SIGRTMAX _NSIG

K.2

Analizadores de Cdigo o
405

Retirado de http://www.ccppbrasil.org/wiki/Analisadores_de_C%C3%B3digo

* * * * * * * * * * * * *

CQual A tool for adding type qualifiers in C. SNav Red Hat Source Navigator. Sparse a tool designed to find faults in the Linux kernel. Splint an open source evolved version of Lint (C language). Frama-C Frama-C is a suite of tools dedicated to the analysis of the source code of software written in C. Astr\ee - A tool for proving the absence of runtime errors (overflows, failed assertions, etc.), taylored to critical embedded control code (was applied to Airbus A340 and A380 avionics code) Deputy - Deputy is a C compiler that is capable of preventing common C programming errors, including out-of-bounds memory accesses as well as many other common type-safety errors. CCured - CCured is a source-to-source translator for C. It analyzes the C program to determine the smallest number of run-time checks that must be inserted in the program to prevent all memory safety violations. RATS - RATS is a tool for scanning C, C++, Perl, PHP and Python source code and flagging common security related programming errors such as buffer overflows and TOCTOU (Time Of Check, Time Of Use) race conditions. LLVM/Clang Static Analyzer - standalone tool that find bugs in C and Objective-C programs. MOPS - MOPS is a tool for finding security bugs in C programs and for verifying conformance to rules of defensive programming. BOON - BOON is a tool for automatically finding buffer overrun vulnerabilities in C source code. BLAST - BLAST is a software model checker for C programs.

C/C++

406

* * * * * * * * * * *

ABRAXAS Software codeCheck programmable C/C++ Standards Checking Tool. CHECKMARX CxSuite - a Source Code Analysis suite of products allowing developers and auditors identify software security vulnerabilities. CMT++ code metrics tool for C/C++ (also for Java). CP Miner, sold commercially as Pattern Miner detects copy-paste errors and provides refactoring support for C and C++ code. FlexeLint and PC-Lint Multi-platform static code analysis tools for C and C++ code. Green Hills Software DoubleCheck static analysis for C and C++ code. HP Code Advisor A static analysis tool for C and C++ programs LDRA Testbed A software analysis and testing tool suite for C & C++. QA-C (and QA-C++) deep static analysis of C for quality assurance and guideline enforcement. SPARROW Semantic-based static analysis tool for C/C++ which automatically detects buffer overruns, memory leaks, etc. Viva64 analyzes C, C++ code for detect 64-bit portability issues.

Apndice L e Licena de Livre Publicao c ca


Apndice inclu e do pelo tradutor 1. Licena de Livre Publicao Esta uma traduo no-ocial da Open Publication Licence verso 1.0, de 8 de c ca e ca a a junho de 1999, e no substituto legal para a Licena original, dispon a e c vel em http://www.opencontent.org/openpub. Entretanto, esta traduo poder auxiliar pessoas que falem Portugus a entender melhor a licena Openpub. ca a e c E permitido a qualquer pessoa copiar e distribuir cpias desse documento de licena, desde que sem a implementao o c ca de qualquer mudana. c OPEN PUBLIC LICENCE Draft v1.0, 8 june 1999 1.1. Requisitos comuns `s verses no-modicada e modicada Os trabalhos protegidos a o a pela Licena de Livre Publicao (Open Publication Licence) podem ser reproduzidos e distribu c ca dos no todo ou em parte, em qualquer meio f sico ou eletrnico, desde que os termos desta licena estejam inclu o c dos, e que esta licena ou c uma incorporao dela por referncia (com quaisquer das opes escolhidas pelo autor ou editor) estejam presentes na ca e co reproduo. ca A forma apropriada para uma incorporao por referncia : ca e e Note: Copyright(c) (ano) (nome do autor ou proprietrio da obra). Este material somente poder ser distribu a a do se sujeito aos termos e condies rmados na Licena de Livre Publicao (Open Publication Licence), verso X.Y ou co c ca a superior (a verso mais atual encontra-se dispon a vel em http://www.opencontent.org/openpub/). Esta referncia, devidamente preenchida com os dados da publicao, deve ser seguida imediatamente com quaisquer e ca opes escolhidas pelos autores ou editor do documento. co E permitida a redistribuio comercial de material licenciado pela Licena de Livre Publicao (Open Publication ca c ca Licence). Qualquer publicao no formato livro padro (papel) requer obrigatoriamente a citao dos autores e editor originais. ca a ca Os nomes dos autores e do editor devem aparecer em todas as superf cies externas do livro. Em todas as faces externas do livro, o nome do editor original deve estar impresso em tamanho to grande quanto o t a tulo do trabalho, e citado como proprietrio em relao `quele t a ca a tulo. Copyright O copyright de todo trabalho protegido pela Licena de Livre Publicao (Open Publication Licence) pertence aos c ca autores ou proprietrios. a Escopo desta licena c Os termos de licena a seguir aplicam-se a todos os trabalhos protegidos pela Licena de Livre Publicao (Open c c ca Publication Licence), a no ser que explicitamente indicado no trabalho. a A mera adio de trabalhos protegidos pela Licena de Livre Publicao (Open Publication Licence) ou partes de ca c ca trabalhos protegidos pela Licena de Livre Publicao (Open Publication Licence) em uma mesma m c ca dia que contenha outros trabalhos ou programas no protegidos por essa licena no decorre em aplicao da Licena de Livre Publicao a c a ca c ca (Open Publication Licence) para esses outros trabalhos. O trabalho resultante deve explicitamente conter uma nota especicando a incluso do material protegido pela Licena de Livre Publicao (Open Publication Licence) e o aviso de a c ca copyright apropriado. APLICABILIDADE. Se alguma parte desta licena no puder ser aplicada em alguma jurisdio, as partes restantes c a ca deste documento continuam sendo aplicadas. AUSENCIA DE GARANTIA. Os trabalhos protegidos pela Licena de Livre Publicao (Open Publication Licence) c ca so fornecidos como esto, sem garantias de qualquer tipo, expl a a cita ou impl cita, incluindo, mas no limitado a, as a garantias impl citas de comercializao e convenincia para um propsito particular, ou garantia de no-infrao. ca e o a ca Requisitos para trabalhos modicados Todas as verses modicadas de documentos cobertos por esta licena, incluindo tradues, antologias, compilaes o c co co e documentao parcial, deve seguir os requisitos abaixo: ca A verso modicada deve ser indicada como tal. a As pessoas que zerem as modicaes e as datas de modicao devem ser identicadas. co ca O reconhecimento dos autores e editor originais (se aplicvel) deve ser mantido de acordo com as prticas acadmicas a a e usuais de citao. ca O local da verso no-modicada do documento deve ser indicado. a a Os nomes originais dos autores no devem ser utilizados para indicar ou garantir seu endosso ao documento resultante a sem a autorizao expressa dos autores. ca Prticas recomendadas a Em adio aos requisitos desta licena, solicitado e extremamente recomendado aos redistribuidores que: ca c e Se os trabalhos protegidos pela Licena de Livre Publicao (Open Publication Licence) estiverem sendo distribu c ca dos em impressos ou CD-ROM, os autores sejam informados por email, ao menos trinta dias antes, para que os autores tenham tempo de providenciar documentao atualizada. Esta noticao deve descrever as modicaoes introduzidas no ca ca c documento, se existirem.

407

Todas as modicaes substanciais (incluindo excluses) devem ser marcadas claramente no documento, ou ento co o a descritas em um anexo ao documento. Finalmente, mesmo no sendo obrigatrio sob esta licena, considerado de bom tom oferecer uma cpia sem nus a o c e o o de todo o material modicado (impresso e CD-ROM) para os autores originais. Termos opcionais Os autores e editores de documentos protegidos pela Licena de Livre Publicao (Open Publication Licence) podem c ca escolher certas opes de licena simplesmente incluindo alguns pargrafos aps a cpia da licena ou sua referncia. Estas co c a o o c e opes so consideradas parte da licena e devem ser inclu co a c das com ela (ou com a referncia a ela) nos trabalhos derivados. e As opes que se aplicam a este trabalho so: co a A: E vedada a distribuio de verses com modicaes substanciais deste documento sem a expressa permisso dos ca o co a proprietrios do direito autoral. a B: E vedada a distribuio deste trabalho ou qualquer derivado seu em qualquer formato de livro padro (papel) ca a sem a prvia autorizao dos proprietrios do direito autoral. e ca a Pol ticas de Publicaes Livres co (O texto a seguir no considerado parte da licena.) a e c Os trabalhos protegidos pela Licena de Livre Publicao (Open Publication Licence) esto dispon c ca a veis na home page da Open Publication. Os autores de trabalhos protegidos pela Licena de Livre Publicao (Open Publication Licence) podem incluir suas c ca prprias licenas nesses trabalhos, desde que os termos dessa licena no sejam mais restritrivos que os da Licena de o c c a c Livre Publicao (Open Publication Licence). ca Em caso de d vidas sobre a Licena de Livre Publicao (Open Publication Licence), contactar David Wiley ou a u c ca lista de autores de publicaes livres via email. co Para se inscrever na lista de autores de publicaes livres (Open Publication Authors List), mande um email para co opal-request@opencontent.org com a palavra subscribe no corpo da mensagem. Para enviar mensagens para a lista de autores de publicaes livres (Open Publication Authors List), mande um co email para opal@opencontent.org ou simplesmente responda a uma mensagem postada. Para se desinscrever na lista de autores de publicaes livres (Open Publication Authors List), mande um email co para opal-request@opencontent.org com a palavra unsubscribe no corpo da mensagem.

408

Apndice M e A Licena P blica Geral do c u GNU - pt BR


Apndice inclu e do pelo tradutor. Licena P blica Geral do GNU (GPL) [General Public License] c u This is an unocial translation of the GNU General Public License into Portuguese. It was not published by the Free Software Foundation, and does not legally state the distribution terms for software that uses the GNU GPLonly the original English text of the GNU GPL does that. However, we hope that this translation will help Portuguese speakers understand the GNU GPL better. Esta uma traduo no-ocial da GNU General Public License para o Portugus. Ela no publicada pela Free e ca a e a e Software Foundation e no traz os termos de distribuio legal do software que usa a GNU GPL estes termos esto a ca a contidos apenas no texto da GNU GPL original em ingls. No entanto, esperamos que esta traduo ajudar no melhor e ca a entendimento da GNU GPL em Portugus. e Verso 2, Junho de 1991 Direitos Autorais Reservados 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, a Suite [conjunto] 330, Boston, MA [Massachusetts] 02111-1307 USA [Estados Unidos da Amrica] e permitido a qualquer pessoa copiar e distribuir cpias sem alteraes deste documento de licena, sendo vedada, E o co c entretanto, qualquer modicao. ca Introduo ca As licenas da maioria dos softwares so elaboradas para suprimir sua liberdade de compartilh-los e modic-los. A c a a a Licena P blica Geral do GNU, ao contrrio, visa garantir sua liberdade de compartilhar e modicar softwares livres c u a para assegurar que o software seja livre para todos os seus usurios. Esta Licena P blica Geral aplicvel ` maioria a c u e a a dos softwares da Free Software Foundation [Fundao do Software Livre] e a qualquer outro programa cujos autores se ca comprometerem a us-la. (Em vez dela, alguns outros softwares da Free Software Foundation so cobertos pela Licena a a c P blica Geral de Biblioteca do GNU). Voc tambm poder aplic-la aos seus programas. u e e a a Quando falamos de software livre, estamos nos referindo ` liberdade, no ao preo. Nossas Licenas P blicas Gerais a a c c u visam garantir que voc tenha a liberdade de distribuir cpias de software livre (e cobrar por isso se desejar), que receba e o cdigo-fonte ou possa obt-lo se desejar, que possa modic-lo ou usar partes dele em novos programas livres; o e a nalmente, que voc tenha cincia de que pode fazer tudo isso. e e Para proteger seus direitos, necessitamos fazer restries que pro co bem que algum negue esses direitos a voc ou que e e solicite que voc renuncie a eles. Essas restries se traduzem em determinadas responsabilidades que voc dever e co e a assumir, se for distribuir cpias do software ou modic-lo. o a Por exemplo, se voc distribuir cpias de algum desses programas, tanto gratuitamente como mediante uma taxa, voc e o e ter de conceder aos receptores todos os direitos que voc possui. Voc ter de garantir que, tambm eles, recebam ou a e e a e possam obter o cdigo-fonte. E voc ter a obrigao de exibir a eles esses termos, para que eles conheam seus direitos. o e a ca c Protegemos seus direitos atravs de dois passos: (1) estabelecendo direitos autorais sobre o software e (2) concedendo a e voc esta licena, que d permisso legal para copiar, distribuir e/ou modicar o software. e c a a Alm disso, para a proteo de cada autor e a nossa, queremos ter certeza de que todos entendam que no h nenhuma e ca a a garantia para este software livre. Se o software for modicado por algum e passado adiante, queremos que seus e receptores saibam que o que receberam no o original, de forma que quaisquer problemas introduzidos por terceiros a e no afetem as reputaes dos autores originais. a co Finalmente, qualquer programa livre constantemente ameaado por patentes de software. Queremos evitar o risco de e c que redistribuidores de um programa livre obtenham individualmente licenas sob uma patente, tornando o programa, c com efeito, proprietrio. Para impedir isso, deixamos claro que qualquer patente deve ser licenciada para o uso livre por a parte de qualquer pessoa ou, ento, simplesmente no deve ser licenciada. a a Os exatos termos e condies para cpia, distribuio e modicao seguem abaixo. co o ca ca TERMOS E CONDICOES PARA CPIA, DISTRIBUICAO E MODIFICACAO 0.Esta Licena se aplica a qualquer programa ou outra obra que contenha um aviso inserido pelo respectivo titular dos c direitos autorais, informando que a referida obra pode ser distribu da em conformidade com os termos desta Licena c P blica Geral. O termo Programa, utilizado abaixo, refere-se a qualquer programa ou obra, e o termo obras baseadas u no Programasignica tanto o Programa, como qualquer obra derivada nos termos da legislao de direitos autorais: isto ca , uma obra contendo o Programa ou uma parte dele, tanto de forma idntica como com modicaes, e/ou traduzida e e co para outra linguagem. (Doravante, o termo modicaoinclui tambm, sem reservas, a traduo). Cada licenciado, ca e ca doravante, ser denominado voc. a e Outras atividades que no a cpia, distribuio e modicao, no so cobertas por esta Licena; elas esto fora de seu a o ca ca a a c a escopo. O ato de executar o Programa no tem restries e o resultado gerado a partir do Programa encontra-se coberto a co

409

somente se seu conte do constituir uma obra baseada no Programa (independente de ter sido produzida pela execuo u ca do Programa). Na verdade, isto depender daquilo que o Programa faz. a 1.Voc poder fazer cpias idnticas do cdigo-fonte do Programa ao receb-lo e distribui-las, em qualquer m e a o e o e dia ou meio, desde que publique, de forma ostensiva e adequada, em cada cpia, um aviso de direitos autorais (ou copyright) o apropriado e uma noticao sobre a exonerao de garantia; mantenha intactas as informaes, avisos ou noticaes ca ca co co referentes a esta Licena e ` ausncia de qualquer garantia; e fornea a quaisquer outros receptores do Programa uma c a e c cpia desta Licena junto com o Programa. o c Voc poder cobrar um valor pelo ato f e a sico de transferir uma cpia, e voc pode oferecer, se quiser, a proteo de uma o e ca garantia em troca de um valor. 2.Voc poder modicar sua cpia ou cpias do Programa ou qualquer parte dele, formando, dessa forma, uma obra e a o o baseada no Programa, bem como copiar e distribuir essas modicaes ou obra, de acordo com os termos da Clusula 1 co a acima, desde que voc tambm atenda a todas as seguintes condies: e e co a.Voc deve fazer com que os arquivos modicados contenham avisos, em destaque, informando que voc modicou os e e arquivos, bem como a data de qualquer modicao. ca b.Voc deve fazer com que qualquer obra que voc distribuir ou publicar, que no todo ou em parte contenha o Programa e e ou seja dele derivada, ou derivada de qualquer parte dele, seja licenciada como um todo sem qualquer custo para todos terceiros nos termos desta licena. c c.Se o programa modicado normalmente l comandos interativamente quando executado, voc dever fazer com que ele, e e a ao comear a ser executado para esse uso interativo em sua forma mais simples, imprima ou exiba um aviso incluindo o c aviso de direitos autorais (ou copyright) apropriado, alm de uma noticao de que no h garantia (ou, ento, e ca a a a informando que voc oferece garantia) e informando que os usurios podero redistribuir o programa de acordo com e a a essas condies, esclarecendo ao usurio como visualizar uma cpia desta Licena. (Exceo: se o Programa em si for co a o c ca interativo mas no imprimir normalmente avisos como esses, no obrigatrio que a sua obra baseada no Programa a a e o imprima um aviso). Essas exigncias se aplicam ` obra modicada como um todo. Se partes identicveis dessa obra no forem derivadas do e a a a Programa e puderem ser consideradas razoavelmente como obras independentes e separadas por si prprias, nesse caso, o esta Licena e seus termos no se aplicaro a essas partes quando voc distribui-las como obras separadas. Todavia, c a a e quando voc distribui-las como parte de um todo que constitui uma obra baseada no Programa, a distribuio deste todo e ca ter de ser realizada em conformidade com esta Licena, cujas permisses para outros licenciados se estendero ` obra a c o a a por completo e, conseq entemente, a toda e qualquer parte, independentemente de quem a escreveu. u Portanto, esta clusula no tem a intenao de armar direitos ou contestar os seus direitos sobre uma obra escrita a a c inteiramente por voc; a inteno , antes, de exercer o direito de controlar a distribuio de obras derivadas ou obras e ca e ca coletivas baseadas no Programa. Alm do mais, a simples agregao de outra obra que no seja baseada no Programa a ele (ou a uma obra baseada no e ca a Programa) em um volume de m dia ou meio de armazenamento ou distribuio, no inclui esta outra obra no mbito ca a a desta Licena. c 3.Voc poder copiar e distribuir o Programa (ou uma obra baseada nele, de acordo com a Clusula 2) em cdigo-objeto e a a o ou formato executvel de acordo com os termos das Clusulas 1 e 2 acima, desde que voc tambm tome uma das a a e e providncias seguintes: e a.Incluir o cdigo-fonte correspondente completo, pass o vel de leitura pela mquina, o qual ter de ser distribu a a do de acordo com as Clusulas 1 e 2 acima, em um meio ou m a dia habitualmente usado para intercmbio de software; ou, a b.Incluir uma oferta por escrito, vlida por pelo menos trs anos, para fornecer a qualquer terceiro, por um custo que a e no seja superior ao seu custo de sicamente realizar a distribuio da fonte, uma cpia completa pass a ca o vel de leitura pela mquina, do cdigo-fonte correspondente, a ser distribu a o do de acordo com as Clusulas 1 e 2 acima, em um meio ou a m dia habitualmente usado para intercmbio de software; ou, a c.Incluir as informaes recebidas por voc, quanto ` oferta para distribuir o cdigo-fonte correspondente. (Esta co e a o alternativa permitida somente para distribuio no-comercial e apenas se voc tiver recebido o programa em e ca a e cdigo-objeto ou formato executvel com essa oferta, de acordo com a letra b, acima). o a O cdigo-fonte de uma obra signica o formato preferencial da obra para que sejam feitas modicaes na mesma. Para o co uma obra executvel, o cdigo-fonte completo signica o cdigo-fonte inteiro de todos os mdulos que ela contiver, mais a o o o quaisquer arquivos de denio de interface associados, alm dos scripts usados para controlar a compilao e instalao ca e ca ca do executvel. Entretanto, como uma exceo especial, o cdigo-fonte distribu a ca o do no precisa incluir nada que no seja a a normalmente distribu do (tanto no formato fonte como no binrio) com os componentes principais (compilador, kernel e a assim por diante) do sistema operacional no qual o executvel executado, a menos que este componente em si a e acompanhe o executvel. a Se a distribuio do executvel ou cdigo-objeto for feita mediante a permisso de acesso para copiar, a partir de um ca a o a local designado, ento, a permisso de acesso equivalente para copiar o cdigo-fonte a partir do mesmo local ser a a o a considerada como distribuio do cdigo-fonte, mesmo que os terceiros no sejam levados a copiar a fonte junto com o ca o a cdigo-objeto. o 4.Voc no poder copiar, modicar, sublicenciar ou distribuir o Programa, exceto conforme expressamente estabelecido e a a nesta Licena. Qualquer tentativa de, de outro modo, copiar, modicar, sublicenciar ou distribuir o Programa ser c a invlida, e automaticamente rescindir seus direitos sob esta Licena. Entretanto, terceiros que tiverem recebido cpias a a c o ou direitos de voc de acordo esta Licena no tero suas licenas rescindidas, enquanto estes terceiros mantiverem o seu e c a a c pleno cumprimento. 5.Voc no obrigado a aceitar esta Licena, uma vez que voc no a assinou. Porm, nada mais concede a voc e a e c e a e e permisso para modicar ou distribuir o Programa ou respectivas obras derivativas. Tais atos so proibidos por lei se a a voc no aceitar esta Licena. Conseq entemente, ao modicar ou distribuir o Programa (ou qualquer obra baseada no e a c u Programa), voc estar manifestando sua aceitao desta Licena para faz-lo, bem como de todos os seus termos e e a ca c e condies para copiar, distribuir ou modicar o Programa ou obras nele baseadas. co 6.Cada vez que voc redistribuir o Programa (ou obra baseada no Programa), o receptor receber, automaticamente, e a uma licena do licenciante original, para copiar, distribuir ou modicar o Programa, sujeito a estes termos e condies. c co Voc no poder impor quaisquer restrioes adicionais ao exerc e a a c cio, pelos receptores, dos direitos concedidos por este instrumento. Voc no tem responsabilidade de promover o cumprimento por parte de terceiros desta licena. e a c 7.Se, como resultado de uma sentena judicial ou alegao de violao de patente, ou por qualquer outro motivo (no c ca ca a restrito `s questes de patentes), forem impostas a voc condies (tanto atravs de mandado judicial, contrato ou a o e co e qualquer outra forma) que contradigam as condies desta Licena, voc no estar desobrigado quanto `s condies co c e a a a co desta Licena. Se voc no puder atuar como distribuidor de modo a satisfazer simultaneamente suas obrigaes sob esta c e a co licena e quaisquer outras obrigaes pertinentes, ento, como conseqncia, voc no poder distribuir o Programa de c co a ue e a a nenhuma forma. Por exemplo, se uma licena sob uma patente no permite a redistribuio por parte de todos aqueles c a ca que tiverem recebido cpias, direta ou indiretamente de voc, sem o pagamento de royalties, ento, a unica forma de o e a cumprir tanto com esta exigncia quanto com esta licena ser deixar de distribuir, por completo, o Programa. e c a

410

Se qualquer parte desta Clusula for considerada invlida ou no executvel, sob qualquer circunstncia espec a a a a a ca, o restante da clusula dever continuar a ser aplicado e a clusula, como um todo, dever ser aplicada em outras a a a a circunstncias. a Esta clusula no tem a nalidade de induzir voc a infringir quaisquer patentes ou direitos de propriedade, nem de a a e contestar a validade de quaisquer reivindicaes deste tipo; a unica nalidade desta clusula proteger a integridade do co a e sistema de distribuio do software livre, o qual implementado mediante prticas de licenas p blicas. Muitas pessoas ca e a c u tm feito generosas contribuies ` ampla gama de software distribu e co a do atravs desse sistema, conando na aplicao e ca consistente deste sistema; cabe ao autor/doador decidir se deseja distribuir software atravs de qualquer outro sistema e e um licenciado no pode impor esta escolha. a Esta clusula visa deixar absolutamente claro o que se acredita ser uma conseqncia do restante desta Licena. a ue c 8.Se a distribuio e/ou uso do Programa for restrito em determinados pa ca ses, tanto por patentes ou por interfaces protegidas por direito autoral, o titular original dos direitos autorais que colocar o Programa sob esta Licena poder c a acrescentar uma limitao geogrca de distribuio expl ca a ca cita excluindo esses pa ses, de modo que a distribuio seja ca permitida somente nos pa ses ou entre os pa ses que no foram exclu a dos dessa forma. Nesse caso, esta Licena passa a c incorporar a limitao como se esta tivesse sido escrita no corpo desta Licena. ca c 9.A Free Software Foundation poder de tempos em tempos publicar novas verses e/ou verses revisadas da Licena a o o c P blica Geral. Essas novas verses sero semelhantes em esp u o a rito ` presente verso, mas podem diferenciar-se, porm, a a e em detalhe, para tratar de novos problemas ou preocupaes. co Cada verso recebe um n mero de verso distinto. Se o Programa especicar um n mero de verso desta Licena que se a u a u a c aplique a ela e a qualquer verso posterior, voc ter a opo de seguir os termos e condies tanto daquela verso a e a ca co a como de qualquer verso posterior publicada pela Free Software Foundation. Se o Programa no especicar um n mero a a u de verso desta Licena, voc poder escolher qualquer verso j publicada pela Free Software Foundation. a c e a a a 10.Se voc desejar incorporar partes do Programa em outros programas livres cujas condies de distribuio sejam e co ca diferentes, escreva ao autor solicitando a respectiva permisso. Para software cujos direitos autorais sejam da Free a Software Foundation, escreva para ela; algumas vezes, abrimos excees para isso. Nossa deciso ser guiada pelos dois co a a objetivos de preservar a condio livre de todos os derivados de nosso software livre e de promover o compartilhamento e ca reutilizao de software, de modo geral. ca EXCLUSAO DE GARANTIA 11.COMO O PROGRAMA E LICENCIADO SEM CUSTO, NAO HA NENHUMA GARANTIA PARA O PROGRAMA, NO LIMITE PERMITIDO PELA LEI APLICAVEL. EXCETO QUANDO DE OUTRA FORMA ESTABELECIDO POR ESCRITO, OS TITULARES DOS DIREITOS AUTORAIS E/OU OUTRAS PARTES, FORNECEM O PROGRAMA NO ESTADO EM QUE SE ENCONTRA, SEM NENHUMA GARANTIA DE QUALQUER TIPO, TANTO EXPRESSA COMO IMPL ICITA, INCLUINDO, DENTRE OUTRAS, AS GARANTIAS IMPL ICITAS DE ` COMERCIABILIDADE E ADEQUACAO A UMA FINALIDADE ESPEC IFICA. O RISCO INTEGRAL QUANTO A QUALIDADE E DESEMPENHO DO PROGRAMA E ASSUMIDO POR VOCE. CASO O PROGRAMA CONTENHA DEFEITOS, VOCE ARCARA COM OS CUSTOS DE TODOS OS SERVICOS, REPAROS OU CORRECOES NECESSARIAS. 12.EM NENHUMA CIRCUNSTANCIA, A MENOS QUE EXIGIDO PELA LEI APLICAVEL OU ACORDADO POR ESCRITO, QUALQUER TITULAR DE DIREITOS AUTORAIS OU QUALQUER OUTRA PARTE QUE POSSA MODIFICAR E/OU REDISTRIBUIR O PROGRAMA, CONFORME PERMITIDO ACIMA, SERA RESPONSAVEL PARA COM VOCE POR DANOS, INCLUINDO ENTRE OUTROS, QUAISQUER DANOS GERAIS, ESPECIAIS, FORTUITOS OU EMERGENTES, ADVINDOS DO USO OU IMPOSSIBILIDADE DE USO DO PROGRAMA (INCLUINDO, ENTRE OUTROS, PERDAS DE DADOS OU DADOS SENDO GERADOS DE FORMA IMPRECISA, PERDAS SOFRIDAS POR VOCE OU TERCEIROS OU A IMPOSSIBILIDADE DO PROGRAMA DE OPERAR COM QUAISQUER OUTROS PROGRAMAS), MESMO QUE ESSE TITULAR, OU OUTRA PARTE, TENHA SIDO ALERTADA SOBRE A POSSIBILIDADE DE OCORRENCIA DESSES DANOS. FINAL DOS TERMOS E CONDICOES Como Aplicar Estes Termos para Seus Novos Programas Se voc desenvolver um programa novo e quiser que ele seja da maior utilidade poss e vel para o p blico, o melhor u caminho para obter isto fazer dele um software livre, o qual qualquer pessoa pode redistribuir e modicar sob os e presentes termos. Para fazer isto, anexe as noticaes seguintes ao programa. E mais seguro anex-las ao comeo de cada arquivo-fonte, co a c de modo a transmitir do modo mais eciente a excluso de garantia; e cada arquivo deve ter ao menos a linha de a direitos autorais reservados e uma indicao de onde a noticao completa se encontra. ca ca uma linha para informar o nome do programa e uma breve idia do que ele faz. e Direitos Autorais Reservados (c) ano nome do autor Este programa software livre; voc pode redistribu e e -lo e/ou modic-lo sob os termos da Licena P blica Geral GNU a c u conforme publicada pela Free Software Foundation; tanto a verso 2 da Licena, como (a seu critrio) qualquer verso a c e a posterior. Este programa distribu e do na expectativa de que seja util, porm, SEM NENHUMA GARANTIA; nem mesmo a e garantia impl cita de COMERCIABILIDADE OU ADEQUACAO A UMA FINALIDADE ESPEC IFICA. Consulte a Licena P blica Geral do GNU para mais detalhes. c u Voc deve ter recebido uma cpia da Licena P blica Geral do GNU junto com este programa; se no, escreva para a e o c u a Free Software Foundation, Inc., no endereo 59 Temple Street, Suite 330, Boston, MA 02111-1307 USA. c Inclua tambm informaes sobre como contatar voc por correio eletrnico e por meio postal. e co e o Se o programa for interativo, faa com que produza uma pequena noticao como esta, quando for iniciado em um c ca modo interativo: Verso 69 do Gnomovision, Direitos Autorais Reservados (c) ano nome do autor. O Gnomovision NAO POSSUI a QUALQUER TIPO DE GARANTIA; para detalhes, digite show w. Este um software livre e voc bem-vindo para e e e redistribu -lo sob certas condies; digite show c para detalhes. co Os comandos hipotticos show w e show c devem mostrar as partes apropriadas da Licena P blica Geral. e c u Naturalmente, os comandos que voc utilizar podero ter outras denominaes que no show w e show c; eles podero e a co a a at ser cliques do mouse ou itens de um menu - o que for adequado ao seu programa. e Voc tambm pode solicitar a seu empregador (se voc for um programador) ou sua instituio acadmica, se for o caso, e e e ca e para assinar uma ren ncia de direitos autorais sobre o programa, se necessrio. Segue um exemplo; altere os nomes: u a A Yoyodyne Ltda., neste ato, renuncia a todos eventuais direitos autorais sobre o programa Gnomovision (que realiza passagens em compiladores), escrito por James Hacker. Assinatura de Ty Coon 1 de abril de 1989, Ty Coon, Presidente Esta Licena P blica Geral no permite a incorporaao do seu programa a programas proprietrios. Se seu programa c u a c a e uma biblioteca de sub-rotinas, voc poder considerar ser mais util permitir a ligao de aplicaes proprietrias ` sua e a ca co a a biblioteca. Se isso o que voc deseja fazer, utilize a Licena P blica Geral de Biblioteca do GNU, ao invs desta e e c u e Licena. c

411

412

Referncias Bibliogrcas e a
[K & R (1989)] KERNIGHAN, B. W. & RITCHIE, D. M.; Traduo de Daniel Vieira. C, A Linguagem De Programao: ca ca Padrao ANSI. Rio de Janeiro: Editora Campus,1989. [Gorman (2004)] Gorman, Mel. Understanding the Linux Virtual Memory Manager.p. cm.(Bruce Perens Open source series). ISBN 0-13-145348-3 [Djairo (1985)] Figueiredo, Djairo Guedes de. Nmeros Irracionais e Trancendentes.Bras u lia, Sociedade Brasileira de Matemtica, pref. 1980. a

413

Indice Remissivo
Descritores de arquivo, 30, 31, 37, 42, 43, 45, 77, 78, 133, 135, 138141, 147149, 155, 167, 172, 181, 182, 187, 193195, 203, 204, 212, 214, 217, 219, 229, 230, 269, 281, 287, 292, 295, 301, 334, 335, 337 339, 341, 342, 345350 GCC, 811, 19, 48, 52, 198, 235, 238241, 244 Internet, 35, 51, 55, 89, 145, 147, 153155, 245, 263, 269, 276, 287, 291, 304, 318, 359 NULL, 16, 27, 34, 55, 63, 79, 82, 90, 93, 98, 99, 102, 126, 133, 190, 221, 227, 351

414

Colofo As runas das casas de banho Stabian em Pompia, capturada pelo fotgrafo Mel Curtis, so ostradas na capa desse livro. Diz-se serem as maiores e mais antigas casas de banho, os banhos Stabian tambm oferecia mensagens e leituras poticas. Os moradores de Pompia visitaram esses banhos pblicos diriamente. Os banhos receberam esse nome pelo fato de estarem localizados na rua Stabian. Esse livro foi escrito e editado em LaTeX, e ento convertido para Microsoft Word pela New Riders e liberados na QuarkXPress. A fonte usada para o corpo do texto a Bembo e a MCPdigital. O livro foi impresso em papel 50# Husky Oset Smooth na R.R. Donnelley & Sons em Crawfordsville, Indiana. A pr-impresso consistiu da tecnologia PostScript computerto-plate (processo lmless). A capa foi impressa na Moore Langen Printing em Terre Haute, Indiana, na Carolina, somente em um lado da folha.

415

You might also like