:. Kernel com suporte a .exe e .class Java

 Por Germano Barreiro
 
 09/08/2004


Não é novidade para ninguém que, com o uso do wine, e as configurações corretas, e possível executar muitos binários windows (.exe) no Linux. Quanto a executar um compilado java (.class), também não é em nada diferente de qualquer outra plataforma com suporte a java, ou seja, basta passar o nome da classe como argumento para o interpretador java.

Agora, o que acharia se eu dissesse que é possível configurar o kernel de tal forma que, para executar qualquer um desses formatos, bastaria digitar na linha de comando algo como:

/mnt/fat/windows/notepad.exe

ou

./alomundo.class

Interessante não? E não somente interessante, mas perfeitamente possível através de uma configuração que permite ao próprio kernel chamar um interpretador adequado para certos gêneros de arquivo. Ou seja, a dependência do wine e do interpretador java continuarão existindo,mas a diferença é que você não vai mais precisar se preocupar com eles, chamando diretamente o nome do binário. Para tanto você vai precisar de certo conhecimento na compilação do kernel (dependendo se sua distro já vem com a característica que descreverei a seguir compilada no kernel ou não), além de já ter configurados o ambiente java e/ou o wine na sua máquina (nada impede que você use este roteiro para configurar o suporte a apenas um dos tipos descritos).

:. Onde o kernel guarda o segredo

Após baixar os fontes do kernel, dependendo se está usando o kernel 2.4 ou 2.6, procure pelos seguintes menus:

kernel 2.4 > General Setup -> Kernel support for MISC binaries
kernel 2.6 > Executable file formats -> Kernel support for MISC binaries

Habilitar este item e recompilar o kernel é o primeiro passo para tornar isto possível. Esse item pode ser compilado direto no kernel ou como módulo, caso em que você terá que carregar o módulo com modprobe. Todos os testes que eu fiz foi com esse recurso já compilado dentro do próprio kernel, e este roteiro vai se ater a essa situação. As configurações mostradas foram testadas utilizando uma máquina Slackware 10, rodando ora kernel 2.4.26 ora kernel 2.6.7, que eram as versões mais recentes disponíveis para download em www.kernel.org no momento da finalização deste documento. Entretanto, se voce preferiria pular a etapa de recompilar o kernel caso sua distribuição ja tivesse esse recurso, e deseja fazer um teste para determinar isso, execute o comando mount da proxima sessão. Se ele executar sem erros, então você provávelmente pode pular esta etapa e ir direto para a parte fácil :).

:. Conversando com o kernel

Decerto muitos já sabem que o diretório /proc é uma interface com o kernel, já que a maioria já deu cat em "arquivos" ali como cpuinfo,meminfo, e outros conhecidos. O que talvez vá ser novidade para alguns é que é possível também executar algo como:

echo parametro > /proc/alguma_coisa

De forma realmente configurar um parâmetro do kernel. Sim, o kernel também e configurável enquanto está executando, modificações não estão limitadas ao momento da compilação do mesmo. E é justamente através deste recurso que se pode informar o kernel de outros formatos binários suportados pela instalação do linux e onde está o interpretador para o mesmo. Primeiro, antes de executar um comando como o acima, e preciso montar a parte do /proc onde se irá atuar e, para tanto, execute o comando:

mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc

Se este comando retornar sem erros, você terá a partir daí dentro do diretório:

/proc/sys/fs/binfmt_misc

as entradas: register e status.

Se você executar um cat em /proc/sys/fs/binfmt_misc/status, receberá apenas o texto "enabled" como resposta, dizendo que o suporte a binfmt_mis está habilitado. Mas é register que nos interessa mais agora, pois será ele que usaremos para notificar o kernel de novos formatos binários. Mas antes uma última coisa sobre este mount: e possivel fazer com que ele seja executado automaticamente no boot apenas adicionando a seguinte linha ao /etc/fstab:

none /proc/sys/fs/binfmt_misc binfmt_misc defaults 0 0

Seja lá qual tenha sido o método usado, uma vez montado esse diretório, o próximo comando será o "echo" falado hà pouco:

echo REGISTRO > /proc/sys/fs/binfmt_misc/register

Sendo que REGISTRO será um conjunto de campos separados pelo caracter ':' no seguinte formato:

:NOME:TIPO:OFFSET:PADRAO:MASCARA:INTERPRETADOR:

Desses 6 registros, apenas 4 são realmente necessários, mas segue uma breve explicação de cada um:

NOME = (necessário) Um identificador para este registro, escolha um nome que lembre o tipo de executável que você estará configurando como JAVA_CLASSE ou WINDOWSEXE. Surgirá um novo arquivo no mesmo diretório onde estão o status e register, com o mesmo nome deste identificador.

TIPO = (necessário) Diz ao kernel que mecanismo será utilizado para reconhecer o arquivo como deste tipo binário. Este campo só tem uma letra, sendo E ou M. Se for E, o kernel discernirá o binário por sua extensão, tal como .exe ou .class. Se for M, o kernel olhará dentro do arquivo procurando por uma determinada sequência de bits para reconhecer o formato. Por ser relativamente mais complexo, este último caso não será abordado aqui, e todas as configurações serão feitas de forma que o kernel reconheça o arquivo por sua extensão.

OFFSET = (opcional) Este campo só faria sentido se o anterior fosse M, pois trata-se da distância a partir do início do arquivo onde começar a olhar para procurar pelo padrão binário.

PADRAO = (necessário) Se TIPO for E, como será em todas as configurações que faremos, este campo deve conter a extensão sem o ponto. Ou seja, exe ou EXE para executáveis windows, class para java. Se TIPO fosse M, aqui seria colocada a sequência de bytes a ser procurada no arquivo.

MÁSCARA = (opcional) Também somente faria sentido se TIPO fosse M, pois este campo permite desabilitar (mascarar) alguns bits da sequência a ser procurada.

INTERPRETADOR = (necessário) trata-se do nome e caminho completo do interpretador para esse tipo de arquivo, tal como, por exemplo, /usr/lib/java/bin/java. Por fim, repare bem que o registro começa e termina com o caracter ':'. Uma vez dado o comando echo para salvar esse registro em /proc/sys/fs/binfmt_misc/register, aparecerá um novo arquivo em /proc/sys/fs/binfmt_misc com o mesmo nome do campo NOME no registro. Se não aparecer, veja se foi feita alguma incorreção na hora de formar o registro. Conceitos assimilados, está na hora de por isto na prática...

:. Fazendo o kernel "executar" o Windows

Os executáveis do windows na verdade :). No meu ambiente, eu instalei o wine baixando os fontes e executando wineinstall. O wine foi configurado para usar uma partição do Windows 98(R) como diretório do windows, que no meu linux ficou montado em /mnt/fat com direitos de acesso para leitura e escrita por usuários comuns. Segue a linha do meu fstab referente a essa partição:

/dev/hda1 /mnt/fat vfat user,umask=000,exec,dev,suid 1 0

Assim, o próximo passo foi executar:

$ echo :WINDOWS_EXE:E::exe::/usr/local/bin/wine: > /proc/sys/fs/binfmt_misc/register

E, como primeiro teste para ver se deu certo, executar:

$ cat /proc/sys/fs/binfmt_misc/WINDOWS_EXE
enabled
interpreter /usr/local/bin/wine
extension .exe

Até aqui tudo bem, então o teste final foi:

$/mnt/fat/windows/notepad.exe

E voilá, o notepad apareceu bem diante dos meus olhos :)

:. Domando o Java

Bom, agora talvez alguém pensasse que nem é preciso explicar o java, pois o procedimento seria análogo ao usado com o wine, correto? Incorreto! Simplesmente registrar o caminho para o interpretador java seguindo a receita mostrada e tentar executar o arquivo class desta vez não vai dar certo. E não vai dar certo por um motivo simples: quando o kernel reconhece um tipo que deve ser tratado por um interpretador especificado deste modo, ele simplesmente executa o interpretador passando para o mesmo o nome e caminho para o arquivo. Agora eu pergunto aos ententidos de java de plantão, se eu executar algo como:

java /home/germano/minhaclasse.class

Isso vai funcionar? Não vai porque para o interpretador java não deve ser passado o nome do arquivo da classe, mas o nome da classe em si e apenas, sem diretórios. E o diretório onde está o arquivo .class deve estar configurado numa variável de ambiente chamada CLASSPATH. Bem, infelizmente ensinar java prolongaria demais este roteiro, de forma que me limitarei apenas a dizer que, no meu ambiente de teste, o interpretador está em /usr/lib/java/bin/java e minha variável de ambiente CLASSPATH está configurada como segue:

$echo $CLASSPATH
/usr/lib/java/lib:./

Para resolver esse tipo de situação a saída é escrever um wrapper, que nada mais é que um script que chama o interpretador com o argumento correto, e registrar esse wrapper no kernel como sendo o interpretador. No caso do java, eu escrevi o seguinte script e salvei em /usr/local/bin/javawrapper.sh

#!/bin/bash
NOMECLASSE=`echo $1 | tr \/ . | awk -F. '{print $(NF-1)}'`
/usr/lib/java/bin/java $NOMECLASSE

Este script é que será chamado pelo kernel e receberá como argumento o nome e caminho para o arquivo .class. As duas linhas de código cortam a extensão e o caminho do argumento recebido deixando apenas o nome da classe, e usa esse valor como argumento para o interpretador java.Contornada essa peculiaridade do java, bastou registrar o wrapper como teria feito com o próprio interpretador:

echo :JAVACLASS:E::class::/usr/local/bin/javawrapper.sh: >/proc/sys/fs/binfmt_misc/register

Depois disso compilei o seguinte programa java estilo alo mundo:

public class binfmt{
       public static void main(String args[]){
     System.out.println("O Linux e muito esperto
");
     }
}

E por fim foi só chamar diretamente o arquivo .class para testar:


$ /home/germano/binfmt.class

O Linux e muito esperto
$ ./binfmt.class

O Linux e muito esperto



:. Onde achar mais informação

No diretório dos fontes do kernel há uma pasta chamada Documentation, onde se encontrará dois arquivos: binfmt_misc.txt e java.txt. Este roteiro é, em sua maioria, baseado no conteúdo desses arquivos.

Wine baixado de:
http://www.winehq.com/
E instalado a partir dos fontes como descrito na seção sobre windows exe.

O java utilizado foi o que veio já pré instalado no Slackware 10.

Note que o java e o wine foram utilizados aqui principalmente como ilustração para um conceito, na verdade, muito mais genérico, pois é possível utilizar esse recurso do kernel para registrar no sistema literalmente qualquer formato binário executável, desde que haja instalado no linux um interpretador para o mesmo.




Copyright 2003 Carlos E. Morimoto, http://www.guiadohardware.net - Todos os direitos reservados