Há umas três semanas comecei a usar um smartphone. É um ótimo aparelho, até que se tenha que usá-lo como celular.
De qualquer forma, uma das grandes vantagens do Android é que o sistema operacional por baixo de tudo é um Linux mais ou menos normal (sem GNU, todavia), e portanto é possível rodar praticamente qualquer coisa que rode em Linux/ARM em um smartphone com Android.
E se não fosse pelo teclado virtual, já teria instalado o Nethack.
As condições mínimas para diversão são um terminal e os utilitários padrão (ls, cp, grep, etc.). Existe um pacote pronto com um emulador de terminal, Busybox, e cliente e servidor de ssh e rsync. Infelizmente, esse pacote requer o Android 2.3 ou superior (no meu brinquedo, que vem com um Android 2.2, ele inicia o terminal, dá três vibradas seguidas e congela). É possível, entretanto, obter as partes separadamente elsewhere e juntá-las.
O emulador de terminal pode ser encontrado no Android Market, mas se você é pagão e não tem conta no Google, pode obtê-lo diretamente da forja. A instalação é trivial e deixada como exercício para o leitor.
Tendo o terminal, podemos instalar o Busybox. Encontrei binários pré-compilados do Busybox para o Android neste site super-confiável. Esse binário deverá ser colocado na memória principal do aparelho, já que aparentemente o Android não dá permissão de execução a binários no /sdcard por padrão. Para tanto, você deverá se tornar root do mal, o que exige um equipamento rooteado. Obtive meu smartphone de segunda mão, e ele já veio rooteado, mas guias de como rootear não faltam. Assumindo um aparelho já rooteado:
for i in $(./busybox | ./busybox sed -n 's/,//gp' | ./busybox sed 1d); do ln -s busybox $i; done
Pronto! A partir de agora, quando você iniciar o terminal, o Busybox abrirá automaticamente, e os comandos nele contidos estarão disponíveis.
Por último, instalemos o Dropbear, um cliente/servidor de ssh más pequeño del mundo. Os binários podem ser obtidos aqui (link no final do post). Baixe-o e faça o seguinte:
E está feito! Agora você já pode derrubar a Internet de onde quer que você esteja.
Por padrão, ao ser executado como root, o VLC prestativamente imprime a seguinte mensagem:
VLC is not supposed to be run as root. Sorry. If you need to use real-time priorities and/or privileged TCP ports you can use vlc-wrapper (make sure it is Set-UID root and cannot be run by non-trusted users first).
"Sorry, Dave. I'm afraid you can't do that."
Há duas soluções para esse problema. A solução limpa é recompilar o VLC passando --enable-run-as-root para o ./configure. A solução suja é a sacada genial desse cara: substituir na mão a chamada de geteuid por getppid no binário do VLC. A idéia por trás disso é que os nomes geteuid e getppid têm o mesmo tamanho, e portanto é possível sobrescrever um com o outro no binário sem alterar as posições das coisas no resto do arquivo. geteuid retorna o UID efetivo do processo, que é 0 para o root. getppid retorna o PID do processo pai do processo atual, que nunca é zero, exceto para o /sbin/init [citation needed]. A treta é enganar o VLC fazendo-o pensar que o UID do processo atual é um número qualquer diferente de zero. O artigo original usa o Vim para isso, mas qualquer editor que não estrague binários serve – inclusive o sed sem locale Unicode:
# LC_ALL=C sed 's/geteuid/getppid/g' /usr/bin/vlc >/usr/bin/vlc-hacked # chmod 755 /usr/bin/vlc-hacked
Pronto! Agora você tem um vlc-hacked, que aceita rodar como root. Você pode apagar/mover o vlc original e colocar o vlc-hacked no lugar, mas eu não recomendaria; melhor que para rodar o vlc como root você tenha que expressar explicitamente o desejo chamando o binário alternativo.
Caveat: Procurando por soluções para esse problema, encontrei um camarada dizendo que o VLC tem mil falhas de segurança, permitindo inclusive a execução de código arbitrário dependendo da fase da lua. (O que eu concluo dessa afirmação é que eu não deveria rodar o VLC at all, mas enfim.) Use por sua conta e risco.
Antes de destruir a máquina à minha frente e morrer de desgosto, compartilho com vocês o que eu descobri tentando fazer o cooler do PC parar de fazer barulho de espremedor de laranja.
Algumas máquinas permitem controlar a velocidade do fan, por meio dos arquivos pwm1 e pwm1_enable nos diretórios/sys/class/hwmon/hwmon*. echo 1 >pwm1_enable habilita o controle do fan por software (ao invés de deixar o firmware trabalhar sozinho), e echo N >pwm1, onde N costuma ser um valor entre 0 e 255, controla a velocidade do fan. No EeePC, a configuração funcionava temporariamente até o firmware resolver que era melhor que o OS e ligar o fan de novo; para desligar o fan, era necessário então setá-lo de novo para a velocidade máxima e de volta para zero (ou o valor que se quisesse; o EeePC só tinha o modo "ligado" e "desligado" por software, entretanto). Os arquivos se chamavam fan1 e fan1_enable no kernel 2.6.159265358979 e anteriores.
Outras máquinas não têm suporte ao PWM, mas possuem alguns controles interessantes nos diretórios /sys/class/thermal/cooling_device*. Cada um desses diretórios contém, entre outros, os arquivos: type, que diz o tipo do dispositivo em questão; cur_state, o estado atual do dispositivo; e max_state, o valor máximo que o estado pode assumir. Na máquina que estou usando agora (um Toshiba Satellite de uns cinco ou seis anos atrás), aparecem cinco dispositivos dos seguintes tipos:
# grep '' /sys/class/thermal/cooling_device*/type /sys/class/thermal/cooling_device0/type:Processor /sys/class/thermal/cooling_device1/type:Processor /sys/class/thermal/cooling_device2/type:Fan /sys/class/thermal/cooling_device3/type:LCD /sys/class/thermal/cooling_device4/type:LCD
Você pode dar echo N >/sys/class/thermal/cooling_devicex/cur_state para alterar o estado do dispositivo.
Nesta máquina, o estado do fan fica sempre em 1 (ligado), e o valor não pode ser alterado. Os processadores/cores, porém, possuem um estado padrão 0 e um valor máximo 7; alterando esse valor, os processadores diminuem de velocidade, conseqüentemente aquecendo menos (e possivelmente gastando menos bateria, mas não cheguei a testar). Com um core desativado e o outro no estado máximo de economia, a máquina levou uns dez minutos para subir a temperatura (verificável em /sys/class/hwmon/hwmon*/temp*_input) de 50 a 80 graus (versus um minuto com dois cores no estado normal).
Outra regulagem de freqüência que pode ser feita independentemente é através do cpufreq. cpufreq-info mostra a freqüência atual e a "política de freqüência" em vigor. As configurações podem ser alteradas com cpufreq-set: cpufreq-set -c 0 -u 1G seta a velocidade máxima do core 0 para 1GHz, por exemplo. (Cada modelo de processador aceita apenas certos valores de freqüência; este aqui, por exemplo, aceita 1GHz, 1.33GHz e 1.66GHz. O cpufreq seleciona o valor mais próximo que satisfaz o limite de velocidade especificado, ou retorna um erro.)
Mais uma coisa: é possível desligar um core executando echo 0 >/sys/devices/system/cpu/cpuN/online (e reativá-lo trocando 0 por 1). Não testei o que acontece mandando desligar todos.
Se sua máquina é capaz de ligar e desligar o fan, o que você pode fazer é criar um script para ligar o fan sempre que a temperatura passar de um certo limite (e.g., 80 graus) e desligá-lo quando ela voltar a uma temperatura baixa (e.g., 50 graus). Assim, você só vai ter que ouvir o fan de vez em quando. Na verdade, aparentemente existe um pacote chamado fancontrol que faz basicamente isso. Aqui, entretanto, o fan tem vontade própria e escolhe a velocidade que quer; para pará-lo, tive que impedi-lo de girar. A máquina esquenta igual, apenas mais devagar, com as configurações alteradas, o que não me resolve nada. Obviously it is Allah's will that I throw the Unix box out the window. I submit to the will of Allah.
P.S.: Não, o Unix não tem nada que ver com o problema.
P.P.S.: Aparentemente leitores prospectivos do blog esperam alguma coisa mais interessante da tag mundane. Ela apenas marca os posts sobre "arrumar PC" (i.e., o que sua família pensa que você faz quando diz que estuda Ciência da Computação) e resolução de problemas de mortal (por oposição aos posts sobre programação, por exemplo). Além disso, há uma tag mundane e uma worldly, completamente não-relacionadas, embora as palavras sejam sinônimos. There are no rules anywhere. The Goddess Prevails.
Ofereço este post com conteúdo útil como sacrifício aos leitores, de modo a ter crédito para escrever posts reclamando da vida mais tarde.
O prompt padrão do bash na maior parte das distribuições de GNU/Linux costuma ser algo do tipo username@hostname diretório$ . Esse prompt pode ser customizado alterando-se o valor das variáveis PS1 ("prompt string 1") e companhia:
vitor@eukleides ~$ PS1='oi? ' oi? pwd /home/vitor oi?
Você pode experimentar prompts diferentes alterando essa variável até achar um que seja do seu agrado, e então alterar um dos arquivos de configuração do bash (e.g., ~/.bashrc) para setar a variável para o valor desejado na inicialização do shell.
Como você pode imaginar, o conteúdo de PS1 não precisa ser texto estático. O bash substitui certas seqüências de \ seguido de um caractere (e.g., \u) na definição do prompt por valores específicos (e.g., o nome do usuário). O prompt padrão apresentado acima pode ser obtido pela string \u@\h \W\$ :
Uma lista completa das seqüências expandidas pelo bash no prompt pode ser obtida procurando por PROMPTING no manual (man bash). Outras seqüências úteis incluem \w (caminho completo do diretório atual) e \! (número do comando atual no histórico; útil para quem gosta de usar os comandos de recuperação do histórico, e.g., !42 para reexecutar o comando de número 42).
Uma das maravilhas do terminal (que talvez seja digna de um post a respeito no futuro) são as escape sequences: seqüências de caracteres especiais que podem produzir toda sorte de firula, desde cores e outros efeitos de texto até alterações no título da janela de terminal. Por exemplo, a seqüência ESC [ 3 número m, onde ESC é o caractere ASCII número 27, seleciona a cor de texto com o número especificado (que varia de 0 a 7); a seqüência ESC [ 0 m retorna as cores e outros atributos para seus valores padrão. O caractere ESC pode ser representado no prompt pela seqüência \e. Assim:
PS1='\e[34m\u@\h \W\$ \e[0m'
lhe dará um prompt idêntico ao padrão, mas em azul. Existe uma manpage (man console_codes) com uma lista de seqüências ESC suportadas por diversos terminais.
Só tem um problema: o bash usa o tamanho da string de prompt expandida para calcular o tamanho que o prompt ocupa na tela; ele precisa dessa informação para determinar onde ocorre a quebra de linha, caso o comando digitado possua mais de uma linha, e para saber onde posicionar o cursor caso você tecle Home, entre outras coisas. O problema é que os caracteres de uma seqüência ESC não ocupam espaço na tela, mas aumentam o tamanho da prompt string. Para o bash poder calcular corretamente o tamanho do prompt, é necessário demarcar os trechos de seqüências ESC no prompt entre \[ e \]:
PS1='\[\e[34m\]u@\h \W\$ \[\e[0m\]'
Provavelmente a coisa mais útil que se costuma fazer com seqüências ESC no prompt é setar o título da janela de terminal para conter o diretório atual:
PS1='\[\e]0;\w\a\]\u@\h \W\$ '
ESC ] 0 ; título BEL é a seqüência que muda o título da janela do xterm e outros terminais gráficos. (BEL, representado no prompt por \a, é o caractere ASCII número 7; em situações normais, ele é o caractere que faz o terminal emitir um beep.)
Se você nem sempre acessa o terminal via interface gráfica, pode ser uma boa idéia testar se o terminal atual é gráfico antes de adicionar seqüências ESC no prompt:
case "$TERM" in xterm*|gnome*|konsole*) PS1='\[\e]0;\w\a\]\u@\h \W\$ ' ;; *) PS1='\u@\h \W\$ ' ;; esac
Ou, alternativamente, para evitar duplicação:
# Primeiro adiciona a seqüência ESC. case "$TERM" in xterm*|gnome*|konsole*) PS1='\[\e]0;\w\a\]' ;; *) PS1='' ;; esac # Depois, o resto do prompt (igual em ambos os casos). PS1+='\u@\h \W\$ '
Além de backslash sequences, o bash substitui variáveis presentes na prompt string. Por exemplo, PS1='$USER@$HOSTNAME $PWD\$ ' tem mais ou menos o mesmo efeito que PS1='\u@\h \w\$ '. Ao se usar variáveis no prompt, é importante usar aspas simples em volta do valor que está sendo atribuído a PS1:
O bash também expande comandos (usando a sintaxe $(comando) ou `comando`) presentes na string de prompt. Novamente, é importante cuidar para usar aspas simples caso se queira que o comando execute toda vez que o prompt é impresso, e não apenas uma vez durante a definição do prompt. De modo geral, executar um comando (criar um processo) cada vez que o prompt é impresso não me parece uma boa idéia; normalmente, executar o comando uma vez só resolve a maior parte dos problemas e é menos custoso computacionalmente. (Se bem que hoje em dia criar um processo provavelmente não vai fazer uma diferença palpável na execução do shell ou do sistema; eu recomendaria não fazer isso com o prompt do root, entretanto. A gente nunca sabe quando vai ter que matar uma fork bomb ou um processo mal-comportado no sistema.)
Uma utilidade de usar variáveis e/ou comandos é incluir nome da tty atual no prompt. Isso é particularmente útil quando se está trabalhando no modo texto, pois pelo nome da tty sabe-se o número do console virtual (e lembrando o número pode-se rapidamente voltar para o console em questão teclando Alt-Fn).
tty="$(tty)" # Recupera o nome completo da tty (e.g., /dev/tty1) if [[ $tty == */pts/* ]]; then ttybase="pts${tty##*/}" # Transforma /dev/pts/0 em pts0 else ttybase="${tty##*/}" # Transforma /dev/tty1 em tty1 fi PS1='\u@$ttybase \W\$ ' # Usa o nome da tty ao invés do hostname.
Ganhamos o nome da tty, mas perdemos o hostname. Uma possibilidade é testar se a conexão atual é via ssh, e usar o hostname nesse caso:
tty="$(tty)" if [[ $SSH_CONNECTION ]]; then ttybase="$HOSTNAME" elif [[ $tty == */pts/* ]]; then ttybase="pts${tty##*/}" else ttybase="${tty##*/}" fi PS1='\u@$ttybase \W\$ '
Outra informação útil de se incluir no prompt (uma que eu já não consigo viver sem, a ponto de alterar o prompt de outras máquinas quando vou usá-las por mais do que alguns minutos) é o exit status do último comando. O exit status é um valor ente 0 e 255 que cada processo retorna ao terminar. (É por isso que a main() retorna int, e não void, em C.) Por convenção, um programa retorna 0 se foi bem-sucedido, e um valor diferente de zero caso tenha ocorrido um erro (valores diferentes podem ser usados para erros diferentes). O exit status do último comando vive na pseudo-variável $?:
PS1='\u@$ttybase \W($?)\$ '
A presença do exit status no prompt é útil por mil razões. Primeiro, se você costuma escrever shell scripts, freqüentemente deseja saber que valor um comando retorna em certa situação. Além disso, o exit status presente no prompt dá um feedback imediato quanto ao sucesso ou falha do último comando, sem ter que ler toda a saída do comando. Por exemplo, ao copiar um diretório com muitos arquivos com cp -v, pode ser que uma mensagem de erro passe desapercebida no meio da saída normal do cp; com o exit status no prompt, o erro é imediatamente visível. Com o tempo, verificar o exit status é um ato inconsciente; para mim, hoje em dia, ele é um feedback tão importante quanto a saída do comando. Finalmente, existem alguns programas cretinos que não imprimem mensagens de erro, apenas retornam 1 para indicar que falharam. (Lamentavelmente, com o exit status no prompt, você possivelmente se sentirá inclinado a escrever programas que fazem o mesmo. Eu não tenho o direito de atirar pedras.)
A última maravilha promptística que tenho a apresentar é a variável PROMPT_COMMAND: se essa variável for setada, seu valor é interpretado como um comando a ser executado antes de imprimir o prompt. Você pode usá-la para chamar alguma função que seta uma variável usada na string do prompt.
Eis uma possibilidade: nos doces tempos do bash 1.14, o comportamento do \W era diferente: não havia abreviação do diretório home para ~; além disso, se o diretório estivesse diretamente abaixo do raiz (e.g., /mnt), o bash imprimia a / no início do nome, e não apenas mnt. O comportamento mudou no bash 2, e me foi a mi mui mal. Felizmente, é possível corrigir esse problema usando o PROMPT_COMMAND e uma variável no prompt:
reduced_pwd() { case "$PWD" in /*/*) REDPWD="${PWD##*/}" ;; *) REDPWD="$PWD" ;; esac } PROMPT_COMMAND="reduced_pwd" PS1='\u@$ttybase $REDPWD($?)\$ '
Pode-se adaptar a reduced_pwd, com uma pequena dose de falcatrua, para mostrar os últimos dois itens do diretório atual, ao invés do caminho completo ou do último item:
reduced_pwd() { local prefix case "$PWD" in /*/*/*) # Se PWD = /mnt/foo/bar/baz/quux: prefix="${PWD%/*/*}" # prefix = /mnt/foo/bar REDPWD="${PWD#"$prefix"/}" # REDPWD = baz/quux ;; *) REDPWD="$PWD" ;; esac }
Pode-se obter a temperatura da CPU, ou a carga da bateria da máquina, a partir dos arquivos em /sys. Pode-se baixar periodicamente informação climática de algum site e adicionar a temperatura ao prompt, mudando a cor dependendo de se o tempo está ensolarado ou nublado ou chuvoso. As possibilidades são infinitas.
Há um bom tempo atrás eu li um cara argumentando que logar como root não é necessariamente ruim. Na época não pensei muito sobre o assunto, mas agora acho que o camarada tem razão. Em uma máquina com múltiplos usuários, ou um servidor, é importante proteger os dados de um usuário dos outros, e proteger o sistema dos usuários. Mas em um sistema com um único usuário, as vantagens de usar um usuário comum ao invés do root são de mínimas a nulas.
Ameaças à segurança do sistema incluem:
O que isso nos demonstra é que os mecanismos de segurança tradicionais do Unix são largamente inúteis nos ambientes atuais. Eles não me permitem dar direito a um programa de ler seus arquivos de configuração sem também dar direito de apagar meus arquivos pessoais, nem dar direito a um programa de alterar o relógio do sistema sem também dar direito de formatar o disco. Em um mundo ideal, quando eu dou um comando do tipo cp whatever.txt /home/docs/text/, o programa cp deveria receber não strings, mas sim handlers referindo-se ao arquivo e ao diretório em questão, e só teria acesso a esses dois itens, através dos handlers, e a mais nada. (Integrar isso em uma interface gráfica e garantir acesso a arquivos de configuração e outros recursos implícitos sem causar a loucura do usuário é deixado como um exercício para o leitor.) Essa é a idéia de segurança por capabilities (não confundir com as capabilities de mortal do POSIX).
Ainda não me convenci a me logar sempre como root, mas estou em vias de. Contrapontos são bem-vindos.
Unix is dead. Long live Unix.
[* Ok, um possível objetivo de adulterar o sistema é tornar futuros ataques invisíveis, coisa que não é em princípio possível sem acesso de root. Hmmrgh.]
[P.S.: O primeiro que reclamar do "há um tempo atrás" será sumariamente apedrejado.]
Um camarada estava tendo problemas para acessar um certo livro de faces, entre outras páginas, no Ubuntu 10.10 e 11.04, tanto no Firefox quanto no Chromium. Solução? Diminuir o MTU da interface de rede em questão:
sudo ifconfig wlan0 mtu 1492
substituindo wlan0 pela interface usada para acessar a Internet. Se não funcionar, você pode experimentar valores menores para o MTU. Se alguém souber explicar por que alguns sites funcionam com o valor de MTU errado e outros não, tenha a bondade.
Quem me contou foi esse cara.
Há um tempo atrás, em um momento de distração, dei um comando do tipo:
$ gcc -o h[Tab] h[Tab]
que os tabs completaram para:
$ gcc -o hello.c hello.c
Em situações normais, o gcc compila fonte e o sobrescreve com o executável nesse caso, o que definitivamente não é o que eu queria e me faria ter perdido umas boas linhas de código. Para minha surpresa, entretanto, a máquina pareceu ter criado consciência própria e me respondeu:
$ gcc -o hello.c hello.c gcc -o hello.c? $ _
Levei alguns segundos para entender o que estava acontecendo.
Meu eu do passado é um cara muito legal.
Mais ou menos um ano antes, eu tinha adicionado as seguintes linhas ao meu /etc/bash.bashrc:
# Preventing chaos. gcc() { local args=("$@") out="" while [[ $# -gt 0 ]]; do case "$1" in -o) out="$2" ;; -o*) out="${1#-o}" ;; esac shift done if [[ $out == *.c ]]; then echo "gcc -o $out?" >&2 return 1 else command gcc "${args[@]}" fi }
Essa rica função intercepta as chamadas ao gcc e, se o argumento da opção -o tiver a extensão .c, impede que o gcc seja executado. Também seria possível escrever um script independente ao invés de uma função, colocando-o em algum lugar antes do gcc real no PATH (e.g., /usr/local/bin/gcc), com o conteúdo da função (o trecho entre chaves), substituindo o command gcc pelo caminho do gcc real (e.g., /usr/bin/gcc) e o return por exit. Porém, a função tem a vantagem de afetar apenas shells interativos, deixando em paz scripts, Makefiles e afins.
De brinde, você pode aproveitar para adicionar -Wall automaticamente à linha de comando do gcc (o que teria me economizado mais de oito mil horas de debugging durante a vida).
Muitas pessoas já me perguntaram qual é a diferença entre um hard link e um link simbólico. No intuito de elucidar este duradouro mistério sobre a natureza do Unix, apresento-vos este singelo post.
No Unix, cada arquivo é associado a um inode. O inode é uma estrutura que contém diversas meta-informações sobre o arquivo, tais como seu tamanho, dono, grupo, permissões, datas de acesso e modificação, e ponteiros para o conteúdo do arquivo do disco. O inode, entretanto, não contém o nome do arquivo. Cada inode possui um número que o identifica dentro de um dado sistema de arquivos.
Um diretório é um arquivo que contém uma lista de nomes de arquivos e os números de seus respectivos inodes. Cada entrada dessa lista é um hard link para o arquivo em questão. É possível que haja mais de uma entrada, no mesmo diretório ou não, para o mesmo arquivo; o inode contém uma contador de referências (o valor na segunda coluna do ls -l, conhecido como link count), que indica quantas entradas apontam para ele. Enquanto houver referências para o arquivo, ele continuará existindo, mesmo que a referência "original" seja apagada. Apenas quando o contador de referências atingir zero (e nenhum processo estiver com o arquivo aberto), ele será removido do sistema de arquivos. Isso explica por que a syscall que "apaga" um arquivo no Unix se chama unlink.
Enquanto um hard link é uma referência direta ao arquivo, um link simbólico, ou symlink, é uma referência a um nome de arquivo. Essencialmente, um symlink é como um "atalho" em um suposto sistema operacional, com a diferença de que o symlink é tratado transparentemente pelo sistema. Se a entrada para a qual um symlink aponta for apagada, o symlink fica quebrado. É possível criar symlinks entre sistemas de arquivos (pois apenas o nome é usado), mas não um hard link (pois o inode deve estar no mesmo sistema de arquivos que a referência).
Uma observação interessante é que o link count de um diretório é igual ao número de subdiretórios que possui mais 2. Isso acontece porque, além da entrada no diretório que o contém, o diretório contém uma entrada . apontando para si mesmo, e cada subdiretório possui uma entrada .. apontando para o diretório pai. A maior parte dos sistemas não permite a criação de novos hard links para um diretório, para evitar ciclos na "árvore" de diretórios.
E termina assim o conto.
Copyright © 2010-2024 Vítor De Araújo
O conteúdo deste blog, a menos que de outra forma especificado, pode ser utilizado segundo os termos da licença Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International.
Powered by Blognir.