Arquivo

Archive for the ‘C’ Category

Obtendo o tempo ocioso em uma sessão do X


Recentemente me deparei com uma pergunta no VOL a respeito do tempo ocioso em uma sessão em modo gráfico. A ideia era que estando o usuário sem realizar qualquer atividade na frente do PC depois de um determinado tempo, fosse deslogado automaticamente. Em modo texto, é possível fazer isso  através da variável TMOUT, mas isso não funciona em modo gráfico.  Em modo gráfico seria necessário obter o tempo ocioso de um usuário que estivesse usando KDE, GNOME, etc, verificar se esse tempo era maior ou igual a um tempo limite e caso fosse, executar um script que desconecta o usuário. A parte de desconectar o usuário não é difícil, mas obter o tempo ocioso do usuário se fez mais complicado. A saída do comando w tinha informações para as sessões em modo texto, mas nada de uma sessão do X. Pensei em obter esse tempo também via D-Bus, perguntando ao gnome-screensaver (no caso de um usuário estiver usando o GNOME ou XFCE), mas notei que o método GetIdleTime, não estava mais disponível.

Dessa maneira, decidi escrever um humilde programa em C usando a Xlib para obter essa informação e então aproveitá-la em um script. Não sou um expert com essa biblioteca, mas o procedimento era bem simples. O programa xidle, como chamei, retorna o tempo ocioso de uma sessão do X em segundos. Segue abaixo o programa, bem como uma explicação nos comentários sobre como compilar ele:

/*---------------------------------------------------------------------
 *    Imprime o tempo de inatividade de uma sessão do X em segundos.
 *
 *    Obs: Compile esse programa com o comando:
 *         $ gcc -o xidle xidle.c -lX11 -lXss
 *
 *         Depois mova-o para um diretório no seu PATH (um bom local
 *         seria o diretório /usr/local/bin)
 *
 *    No Fedora, é necessário instalar o pacote 'libXScrnSaver-devel'
 *    e 'libX11-devel' para poder seguir com a compilação.
 *
 *                 Autor: Elder Marco <eldermarco@gmail.com>
 *                 Data : 13/09/2010
 *    Última modificação: 07/11/2010
 *---------------------------------------------------------------------*/
#include <X11/extensions/scrnsaver.h>
#include <X11/Xlib.h>
#include <X11/Xlibint.h>
#include <stdio.h>

int main() {
     XScreenSaverInfo *info;
     Display *display;

     info = XScreenSaverAllocInfo();
     display = XOpenDisplay(NULL);

     XScreenSaverQueryInfo(display,
                           DefaultRootWindow(display),
                           info);
     printf("%.0f s\n", (float)info->idle/1000);

     Xfree(info);
     XCloseDisplay(display);

     return 0;
}

Considerando que você moveu o programa compilado para algum diretório no seu PATH, basta fazer:

cut -f 1 -d' ' <(xidle)

para obter esse tempo. 🙂

Obviamente, se você executar o programa xidle a partir do terminal, ele sempre vai retornar 0s, já que você acabou de dar um ENTER… mas se quer testar, você pode usar o comando sleep para esperar um tempo e depois executar o xidle (só não toque no teclado e nem mexa no mouse enquanto isso!). Veja:

$ sleep 11 && xidle
11 s
$ sleep 11 && cut -f 1 -d ' ' <(xidle)
11

E pra finalizar, depois que terminei esse programa, encontrei um outro que embora não retorne o tempo ocioso — até onde pude ver –, ele executa um script depois de um tempo de ociosidade do usuário. Procure por xautolock no Google.

Tratando argumentos passados a um programa em C


Recentemente, tive de escrever um programa em C na minha iniciação científica e o objetivo principal do programa era ler o arquivo de um outro e retirar dele, algumas informações. Assim, eu precisaria passar o nome do programa e mais algumas opções que se fizessem necessárias como argumentos para o meu programa, mas queria fazer isso de uma maneira mais organizada e então resolvi procurar alguma função que fosse capaz de tratar desses argumentos.  Tive sorte de encontrar a função getopt da biblioteca unistd.h. Essa função é muito similar ao comando getopts em shell script. De fato, é a cópia dela em linguagem C (ou seria a getopts a cópia da getopt em shell script? Bah! Deixa pra lá!)

A sintaxe dessa função é:

int getopt (int argc, char **argv, const char *options)
extern char *optarg;
extern int optind, opterr, optopt;

A função getopt retorna o próximo caractere passado como argumento ou -1 quando a lista de argumentos passados termina. Se o caractere é desconhecido ou não foi passado o argumento a uma opção que requer, será retornado  ‘?’.  O argumento options é uma string que irá dizer quais são as opções válidas para o seu programa.  Se uma opção requer um argumento, você precisa especificar isso colocando um ‘:’ na frente dessa opção.

As variáveis externas apresentadas acima carecem de uma explicação:

  • opterr – Se a função getopt encontra algum erro como um caractere de opção inválido ou a falta de algum argumento que não foi passado para uma opção, ela imprime uma mensagem de erro. Para desativar essas mensagens e você mesmo tratar elas, você pode definir a variável com um valor zero no seu programa.
  • optarg –  Você passa ao seu programa opções, mas algumas delas requerem algum argumento. Por exemplo, uma opção como -o poderia necessitar que você especificasse um arquivo de saída. A variável optarg é um ponteiro para a string que contém o argumento passado a opção retornada pela função getopt.
  • optind – Essa variável é utilizada como forma de saber qual o próximo elemento de argv deve ser processado. Ele é bastante útil para você tratar argumentos que não são opções e nem argumentos de opções. O programa abaixo irá mostrar um exemplo.
  • optopt – Se a função getopt encontrar um caractere de opção desconhecido ou o usuário não passou o argumento que deveria para uma determinada opção,  será retornado ‘?’ e  a função getopt irá armazenar caractere nessa variável.

Assim, vamos considerar um programa que aceite  as opções x, y e z, sendo que z necessita de um argumento a ser passado.  Esse programa poderia se chamar testagetopt e ser como abaixo:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>

int main ( int argc, char *argv[] )
{
	int opcao;		// Opção passada pelo usuário ao programa.
	int indice;		// Usado para pegar argumentos que não são opções
				    // Nem argumentos usados em opções.

	int xflag =  0;		// Opção -x desativada por default
	int yflag =  0;		// Opção -y desativada por default

	char *zarg = NULL;      // Irá apontar para o argumento de z
				            // se for passado.

	// Desativa as mensagens de erro da função getopt
	opterr = 0;

	// Faz um loop pegando as opções passados pelo usuário. Note
	// o ':' depois do 'z'. Isso quer dizer que deve haver um
	// argumento depois dessa opção.
	while ( ( opcao = getopt ( argc, argv, "xyz:" ) ) != -1 )
	{
		switch ( opcao )
		{
			// Usuário passou a opção -x, habilita:
			case 'x':
				xflag = 1;
				break;

			// Usuário passou a opção -y, habilita:
			case 'y':
				yflag = 1;
				break;

			// Usuário escolheu a opção -z, pegar o argumento
			case 'z':
				zarg = optarg;
				break;

			// Se houve algum problema, vamos diagnosticar e enviar
			// nossas próprias mensagens de erro.
			case '?':
				if ( optopt == 'z' )	// Esqueceu um argumento
					fprintf (stderr, "Opção '-%c' requer argumento.\n",
					optopt);
				else if ( isprint ( optopt ) )
				     	fprintf( stderr, "Opção '-%c' desconhecida.\n",
				        optopt );
			        else
			            fprintf( stderr, "Caractere '\\x%x' de opção desconhecido.\n",
				            optopt );
				exit ( 1 );
		}
	}

	printf ( "         xflag = %s\n", xflag ? "sim" : "não" );
	printf ( "         yflag = %s\n", yflag ? "sim" : "não" );
	printf ( "          zarg = %s\n", zarg  ?  zarg : "nenhum" );

	printf ( "Outros argumentos:\n" );

	for ( indice = optind; indice < argc; indice++ )
		printf ( "                 %s\n", argv[indice]);

	return 0;
}

Compile o programa:

$ gcc -o testagetopt testagetopt.c

Executando com algumas opções teríamos:

shell> ./testagetopt -xy -z topgear.txt testagetopt blabla
         xflag = sim
         yflag = sim
          zarg = topgear.txt
 Outros argumentos:
                 testagetopt
                 blabla

shell> ./testagetopt -x -z topgear.txt testagetopt blabla
         xflag = sim
         yflag = não
          zarg = topgear.txt
Outros argumentos:
                 testagetopt
                 blabla

shell> ./testagetopt -y -z topgear.txt testa?.txt
         xflag = não
         yflag = sim
          zarg = topgear.txt
Outros argumentos:
                 testa1.txt
                 testa2.txt
                 testa3.txt
                 testa4.txt
shell> ./testagetopt -z
Opção '-z' requer argumento.

$ ./testagetopt -c
Opção '-c' desconhecida.

shell> ./testagetopt -xy topgear.txt
         xflag = sim
         yflag = sim
          zarg = nenhum
Outros argumentos:
                 topgear.txt

Bem mais prático!

Referências:

Using getopt – Documentação oficial da função

Documentação relacionada:

Getopt Long Options –  Para o caso de você querer usar opções longas, não somente com uma letra.

Argp – Um função que permite tanto opções longas quanto curtas, além de criar uma saída para as opções --help e --version automaticamente.