Executar um comando Linux em uma aplicação Desktop

Olá a todos, estou tentando executar alguns comandos Linux em uma aplicação desktop Java, mas não estou conseguindo. Dei uma pesquisada por ai, mas achei basicamente, explicando como realizar esse procedimento no Windows apenas. Sei que no Windows eu faço assim:

Runtime.getRuntime().exec("cmd /C shutdown -s -t " + segundosAteReinicio);

E no Linux, mais especificamente o Ubuntu 9.10 64bits já tentei vários comandos no lugar do “cmd /C” mas nenhum surtiu efeito.
Por isso peço a ajuda dos colegas do fórum.

O equivalente do cmd /c no Linux é mais ou menos /bin/bash -c ‘comando’.

http://www.gnu.org/software/bash/manual/bashref.html

Que outros comandos você ficou tentando? Não se esqueça que comandos que contém “rundll” no Windows normalmente não são portáveis - você precisa saber o que o comando faz e então você tem de achar um equivalente.

No seu caso em particular, onde você precisa executar um comando que é exclusivo de um usuário com permissões administrativas, você precisa usar o sudo.

Opa, muito obrigado pela resposta. Como não estou em casa até as 18:00, só poderei testar sua solução a noite.

Obrigado…

Infelizmente ainda não obtive sucesso. O código que usei foi i seguinte:

Runtime.getRuntime().exec("/bin/bash -c sudo shutdown -r now");

Com o código acima, nenhum erro é gerado, mas nada acontece…

Creio que meu erro deva ser besta, espero.

tente: Runtime.getRuntime().exec("#! /bin/bash -c sudo shutdown -r now");

Poxa… agora eatá lançando uma exceção:

Runtime.getRuntime().exec("#! /bin/bash -c sudo shutdown -r now");

O código acima lança a seguinte exceção:

java.io.IOException: Cannot run program "#!": java.io.IOException: error=2, No such file or directory at java.lang.ProcessBuilder.start(ProcessBuilder.java:459) at java.lang.Runtime.exec(Runtime.java:593) at java.lang.Runtime.exec(Runtime.java:431) at java.lang.Runtime.exec(Runtime.java:328) at br.fpj.ad.Visao.Principal$2.run(Principal.java:125) at java.lang.Thread.run(Thread.java:619) Caused by: java.io.IOException: java.io.IOException: error=2, No such file or directory at java.lang.UNIXProcess.<init>(UNIXProcess.java:148) at java.lang.ProcessImpl.start(ProcessImpl.java:65) at java.lang.ProcessBuilder.start(ProcessBuilder.java:452) ... 5 more

Para executar apenas o comando XYZ não é preciso explicitar o shell primeiro (porque o comando já é executado no shell padrão). Isso significa que o “cmd /C” e o “/bin/bash -c” podem ser omitidos. Tente simplesmente:

Runtime.getRuntime().exec("gksudo reboot");

O ‘gksudo’ é usado pois ele é um front-end para o comando ‘sudo’ (se o sudo for usado a senha do usuário deve ser inserido via OutputStream do processo, pois esse é um comando de CLI).

Só complementando, se isso for rodar em outros ambientes de trabalho, os comandos podem variar (no KDE, por exemplo, usa-se o kdesudo).

Caro marcobiscaro2112, sua dica funcionou, mas no momento que executei meu programa, a senha de root foi necessária para reiniciar a máquina. Tentei também com o comando shutdown -r, mas este não funcionou.

Estive pensando em fazer essa função de agendamento através de um script. Fiz um teste para criar um diretório através da aplicação Java chamando este script, e funcionou. Só que empaquei em outro problema: Existe alguma maneira de passar um parâmetro para um script?

Quanto à necessidade da senha de root (ou senha de usuário, caso o usuário seja um sudoer) é normal e não há como evitar essa situação já que os comandos de desligamento/reinicialização só podem ser executados por superusuário.

Quanto à questão do script, não entendi muito bem. Mas respondendo à sua pergunta: sim, é possível passar um parâmetro para o script. Basta adicionar esse parâmetro logo após o nome do script (assim como você faz com comandos). Por exemplo, se você quer listar o conteúdo (comando ls) do arquivo /, basta usar:

Runtime.getRuntime().exec("ls /");

O mesmo se aplica à scripts. Imagine que você quer executar o script /usr/bin/audiofile-config (que já vem com várias distribuições) passando os parâmetros –version (que apenas mostra informações de versão:

Runtime.getRuntime().exec("audiofile-config --version");

Resumindo, basta fazer exatamente como você faria se estivesse trabalhando direto no terminal.

[quote=marcobiscaro2112]Quanto à necessidade da senha de root (ou senha de usuário, caso o usuário seja um sudoer) é normal e não há como evitar essa situação já que os comandos de desligamento/reinicialização só podem ser executados por superusuário.

[/quote]

Existe sim uma forma de abrir uma sessão superusuário (root) sem precisar digitar a password… desde que devidamente configurado e autorizado. Totalmente seguro.
Esta configuração é feita usando o ssh e permitirá que o usuário autorizado abra uma sessão em nome do root e execute os comandos necessários. O pacote ssh é necessário e deve estar devidamente configurado e operacional (geralmente está na maioria das distribuições linux);
Receita:

  1. abra uma sessão com usuário que vai ser autorizado (userX);
  2. vá até o diretório $HOME/.ssh (se não existir crie a pasta .ssh), gere o par de chaves ssh para o usuário:

$ ssh-keygen -t rsa
(quando solicitar “passphrase” deixe em branco)
Verifique os arquivos gerados (id_rsa e id_rsa.pub);

  1. as permissões das pastas $HOME e $HOME.ssh devem ser 775 (rwxr-xr-x) para funcionar, ou seja outros usuários não podem alterar arquivos nestas pastas;
  2. abra uma sessão com superusuário (root);
  3. vá até o diretório $HOME/.ssh, inclua a chave publica do usuário autorizado (userX) no arquivo “authorized_keys”,
    (supondo que $HOME do userX seja (/users/userx):

cat /users/userX/.ssh/id_rsa.pub >> authorized_keys

PRONTO!
teste:
na sessão do usuário userX execute o comando (servername pode ser “localhost”, ip ou nome do servidor):

$ ssh root@servername
No primeiro acesso deve aparecer uma pergunta sobre se o servidor é conhecido… responda “yes”. Uma nova sessão com usuário root deve ter sido aberta sem pedir senha… se a senha foi solicitada então o teste ainda não deu certo (reveja os passos da configuração);
Depois deste primeiro teste você poderá testar a execução de comandos, exemplo:
$ ssh root@servername pwd
Vai executar o comando “pwd” na conta do root, deve mostrar /root…
ou…
$ ssh root@servername /sbin/shutdown -r now

Boa sorte.

[quote=ctdaa][quote=marcobiscaro2112]Quanto à necessidade da senha de root (ou senha de usuário, caso o usuário seja um sudoer) é normal e não há como evitar essa situação já que os comandos de desligamento/reinicialização só podem ser executados por superusuário.

[/quote]

Existe sim uma forma de abrir uma sessão superusuário (root) sem precisar digitar a password… desde que devidamente configurado e autorizado. Totalmente seguro.
Esta configuração é feita usando o ssh e permitirá que o usuário autorizado abra uma sessão em nome do root e execute os comandos necessários. O pacote ssh é necessário e deve estar devidamente configurado e operacional (geralmente está na maioria das distribuições linux);
Receita:

  1. abra uma sessão com usuário que vai ser autorizado (userX);
  2. vá até o diretório $HOME/.ssh (se não existir crie a pasta .ssh), gere o par de chaves ssh para o usuário:

$ ssh-keygen -t rsa
(quando solicitar “passphrase” deixe em branco)
Verifique os arquivos gerados (id_rsa e id_rsa.pub);

  1. as permissões das pastas $HOME e $HOME.ssh devem ser 775 (rwxr-xr-x) para funcionar, ou seja outros usuários não podem alterar arquivos nestas pastas;
  2. abra uma sessão com superusuário (root);
  3. vá até o diretório $HOME/.ssh, inclua a chave publica do usuário autorizado (userX) no arquivo “authorized_keys”,
    (supondo que $HOME do userX seja (/users/userx):

cat /users/userX/.ssh/id_rsa.pub >> authorized_keys

PRONTO!
teste:
na sessão do usuário userX execute o comando (servername pode ser “localhost”, ip ou nome do servidor):

$ ssh root@servername
No primeiro acesso deve aparecer uma pergunta sobre se o servidor é conhecido… responda “yes”. Uma nova sessão com usuário root deve ter sido aberta sem pedir senha… se a senha foi solicitada então o teste ainda não deu certo (reveja os passos da configuração);
Depois deste primeiro teste você poderá testar a execução de comandos, exemplo:
$ ssh root@servername pwd
Vai executar o comando “pwd” na conta do root, deve mostrar /root…
ou…
$ ssh root@servername /sbin/shutdown -r now

Boa sorte.

[/quote]
Imagine fazer essa configuração em cada computador onde o programa for rodar, para cada usuário… e sem contar que nesse processo a senha de root é necessária de qualquer forma.

Talvez uma entrada no cron, nessa caso, seja extremamente mais simples (se aplicável, é claro).

A configuração é necessária apenas no “servidor” que está sendo administrado pelo programa. E a senha de root é necessária mesmo para esta configuração. Por isto a solução é segura. Como é que você deixaria um programa qualquer fazer shutdown no servidor se não conhece nem a senha do root???

Eu uso o Fedora e ele não pede senha de root para reiniciar o PC, o Ubuntu eu sei que também não.

Esse negócio de precisar de senha de root pra desligar ou reiniciar deve ser a configuração padrão para distros voltadas para servidores, mas nas distros voltadas mais ao desktop isso não é necessário.

O que eu acho que se pode fazer é executar primeiro sem o gksudo, se for retornado um código de erro devido à falta de permissão, aí executa com o gksudo.

é simples, é só dar permissão para o usuário para reiniciar ou desligar o computador.

# chmod 4750 /sbin/shutdown

[quote=alessandrofalls]é simples, é só dar permissão para o usuário para reiniciar ou desligar o computador.

# chmod 4750 /sbin/shutdown

Por quê 475? Na verdade o /sbin/shutdown já tem permissão de execução para qualquer usuário:

$ ls -nl /sbin/shutdown 
-rwxr-xr-x 1 0 0 87844 2009-12-10 14:19 /sbin/shutdown

O que vai ser preciso ser feito nesse caso é usar um SETUID:

# chmod u+s /sbin/shutdown

De qualquer forma, isso também deve ser executado como root em todas as máquinas nas quais o programa rodará (sem contar que user setUID pode ser perigoso em alguns caso devido a possível exploração de vulnerabilidade, tomando controle do superusuário da máquina).