Raccolta di howto, informazioni, consigli, trucchi e documentazione di varia utilità per ricordare tante cose utili

venerdì 18 dicembre 2009

Collegarsi ad un target iSCSI da MSWindows

Per potersi collegare ad un target iSCSI da un PC con Windows è necessario avere un software specifico. Tale software è preinstallato sul sistema in Windows Vista e Windows 7 mentre per XP e 2000 è necessario prelevarlo dal sito microsoft ed installarlo.
Dopo aver installato il software, se necessario, si deve controllare che il servizio denominato "Servizio inizializzatore iSCSI Microsoft" sia avviato o se necessario avviarlo. Andare poi in "Pannello di controllo \ Strumenti di amministrazione" e avviare l'"Inizializzatore iSCSI"; qui sul tab "Destinazioni" possiamo vedere un elenco dei target iSCSI individuati automaticamente, nel caso (molto probabile) il nostro target non sia presente possiamo inserire il suo indirizzo IP nella textbox "Destinazione" del riquadro "Connessione Rapida" e premere il relativo bottone. A questo punto in caso il sistema rlevi un singolo iqn la connessione avverrà automaticamente, in caso contrario selezionare l'iqn voluto ed effettuare la connessione. A connessione avvenuta sarà disponibile un nuovo disco sul nostro PC corrispondente al target iSCSI connesso.
La pagina di riferimento di Microsoft per il protocollo iSCSI è questa.

mercoledì 16 dicembre 2009

Collegarsi ad un target iSCSI al boot del sistema

Dopo aver configurato un nodo iSCSI, come descritto in questo post, può tornare utile avviarlo al boot del sistema.
Il primo passo e di avviare il servizio iscsid al boot, nel caso di un Gentoo Linux occorre utilizzare il comando
rc-update add iscsid default
Occorre poi indicare che il nel file di configurazione del nodo che lo si vuole attivare automaticamente all'avvio del servizio. Il file in questione, nel caso di un Gentoo Linux è
/etc/iscsi/nodes/<iqn_nodename>/<target_ip_and_port>/ifaceX
dove <iqn_nodename> è il qualified name del nodo al quale ci si vuole connettere, <target_ip_and_port> è un nome composto dall'indirizzo ip della macchina ospitante il target iSCSI e ifaceX è il nome dell'interfaccia che abbiamo assegnato al momento della configurazione.
In questo file la voce da modificare è
node.startup=automatic
per evitare lunghi tempi di attesa al boot nel caso il target iSCSI non siia raggiungibile è possibile modificare anche le due seguenti voci:
node.session.initial_login_retry_max
che imposta il massimo numero di retry di connessione iniziale al target
node.conn[0].timeo.login_timeout
che imposta il tempo massimo in secondi che l'initiator attende per ricevere la risposta dal target alla richiesta di login; naturalmente è opportuno ridurre questi parametri solo se initiator e target sono sulla stessa affidabile lan.
Importante notare che il servizio iscsid parte solo quando i filesystem messi in modalità auto in fstab sono già stati montati, per tanto un file system su un device iSCSI non va montato come auto in fstab ma solo successivamente all'avvio di iscsid (per esempio in local)

Configurare un "iscsi initiator" in Linux

L'"iSCSI initiator" è il componente che permette ad un computer di collegarsi ad un disk server mediante il protocollo iSCSI. L'esempio proposto si riferisce ad una distribuzione Gentoo.
Come prima cosa e necessario installare i pacchetti contenenti il software necessario mediante il comando emerge:
emerge sys-block/open-iscsi
Successivamente si deve assegnare un nome al nostro client iSCSI nel file /etc/iscsi/initiatorname.iscsi impostando le due righe
InitiatorName=iqn.2009-12.local.domain.mioclient:LinuxInitiator
InitiatorAlias=MioAlias
Il valore di InitiatorName dovrebbe seguire le convenzioni del protocollo iSCSI per i gli "iSCSI Qualified Name" (iqn). Un riferimento sulla struttura degli iqn e consultabile qui: http://www.cuddletech.com/articles/iscsi/ar01s02.html
Avviare il servizio iscsid con il comando
/etc/init.d/iscsid start
Aggiungere le interfacce di rete da utilizzare alla configurazione con i comandi
iscsiadm -m iface -I iface0 --op=new
iscsiadm -m iface -I iface0 --op=update -n iface.hwaddress -v <mac_address>
dove iface0 è un nome a nostro piacimento che individuerà l'interfaccia di rete per il protocollo iSCSI e <mac_address> è l'effettivo mac address dell'interfaccia di rete da associare.
Per recuperare la lista dei servizi disponibili su una macchina con indirizzo ip noto diamo il comando
iscsiadm -m discovery -t st -p <ip_address> -P 1
l'opzione -P imposta un livello di verbosità tale del comando che ci permette di vedere stampati i servizi target (server) presenti sulla macchina individuata dall' <ip_address> voluto.
Per terminare creiamo un nodo con il comando
iscsiadm -m node -T <target_iqn> -l
dove <target_iqn> è il "qualified name" del target voluto individuato con il precedente comando di discovery; lo switch -l richiede di effettuare immediatamente il login.
Effettuata questa operazione troveremo un nuovo device del tipo /dev/sdX che punta al servizio iscsi appena configurato con gli eventuali device delle partizioni già presenti. A questo punto il disco è utilizzabile in tutto e per tutto come un disco locale.

giovedì 10 dicembre 2009

Ricezione di pacchetti UDP in C

Di seguito la procedura per ricevere un pacchetto UDP attraverso un socket in un sorgente C per linux/unix.
Iniziamo definendo gli opportuni include generici:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
gli include specifici per il funzionamento dei socket
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
e le definizione dell'indirizzo ip e della porta sulla quale porci in ascolto
#define PORT (5000)
Successivamente creiamo il socket UDP
int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == -1) {
  perror("Creazione socket fallita");
  exit(1);
}
definiamo e valorizziamo la struttura contenente le informazioni sulla porta sul quale effettuare il bind del socket
struct sockaddr_in addr_loc;
memset((char *)&addr, sizeof(addr), 0);
addr_loc.sin_family = AF_INET;
addr_loc.sin_port = htons(PORT);
addr_loc.sin_addr.s_addr = htonl(INADDR_ANY);
bind(s, (sockaddr *)&addr_loc, sizeof(addr_loc));
per porci in ascolto dobbiamo prima creare una struttura nella quale la funzione recvfrom ci restituisca l'indirizzo dal quale proviene il pacchetto
struct sockaddr_in addr_rem;
socklen_t slen = sizeof(addr_rem);
char buf[1500];
int r = recvfrom(s, buf, 1500, 0, (sockaddr *)&addr_rem, &slen);  
ed infine possiamo leggere il contenuto del pacchetto e il suo indirizzo di provenienza
printf("Received packet from %s:%d\nData: %s\n\n", inet_ntoa(addr_rem.sin_addr), ntohs(addr_rem.sin_port), buf);
Per concludere chiudiamo il socket
close(s);
Da notare che l'indirizzo ip della sorgente viene conservato nella variabile  addr_rem.sin_addr.s_addr in forma di intero a 32 bit (4 byte) dove il byte meno significativo è il primo dell'indirizzo ip nella forma numerica standard
dcba (4 byte) = a.b.c.d

mercoledì 9 dicembre 2009

Invio di pacchetti UDP in C (unix)

Di seguito la procedura per inviare un pacchetto UDP attraverso un socket in un sorgente C per linux/unix.
Iniziamo definendo gli opportuni include generici:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
gli include specifici per il funzionamento dei socket
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
e le definizione dell'indirizzo ip e della porta di destinazione
#define IPADDR "192.168.1.100"
#define PORT (5000)
Successivamente creiamo il socket UDP
int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == -1) {
  perror("Creazione socket fallita");
  exit(1);
}
definiamo e valorizziamo la struttura contenente la destinazione del pacchetto
struct sockaddr_in addr;
memset((char *)&addr, sizeof(addr), 0);
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
inet_aton(IPADDR, &addr.sin_addr);
Creiamo e valorizziamo il buffer con i dati da inviare
int buf[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
ed infine inviamo il pacchetto sulla rete alla destinazione voluta
int len=sendto(s, buf, 10*sizeof(int), 0, (struct sockaddr *)&addr, sizeof(addr));
if(len < (10*sizeof(int))) perror("Invio fallito o incompleto");
Per concludere chiudiamo il socket
close(s);
Di seguito il sorgente completo

#include <stdlib.h>
#include <stdio.h>;
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define IPADDR "192.168.1.100"
#define PORT (5000)

int main() {

  int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  if (s == -1) {
    perror("Creazione socket fallita");
    exit(1);

  }

  struct sockaddr_in addr;
  memset((char *)&addr, sizeof(addr), 0);

  addr.sin_family = AF_INET;
  addr.sin_port = htons(PORT);
  inet_aton(IPADDR, &addr.sin_addr);


  int buf[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

  int len=sendto(s, buf, 10*sizeof(int), 0, (struct sockaddr *)&addr, sizeof(addr));
  if(len < (10*sizeof(int))) perror("Invio fallito o incompleto");

  close(s);

  return 0;
}

mercoledì 2 dicembre 2009

Modifica delle dimensioni del product_model in osCommerce

Nell'installazione di default osCommerce permette un massimo di 12 caratteri nel product model, limite che spesso si ha la necessità di incrementare.
Per ottenere il risultato voluto bisogna incrementare le dimensioni dei seguenti due campi:
  1. Tabella 'products' campo 'products_model'
  2. Tabella 'orders_products' campo 'products_model'
Per il corretto funzionamento del sistema è necessario che questi due campi di tipo varchar siano della stessa dimensione in quanto all'effetuazione di un ordine il 'product_model' viene letto dalla tabella 'products' per essere registrato  nella tabella 'orders_products'.

martedì 24 novembre 2009

Usare cURL in in programma multithread

cURL è una libreria quasi del tutto thread-safe. Tuttavia è indispensabile prestare attenzione ad alcune cose nello svilupo pena frequenti ed inspiegabili crash dell'applicazione. Le indicazione seguenti sono date nell'ipotesi di lavorare con le curl_easy, tuttavia sono più generalmente valide.
  1. Prima di tutto è necessario inizializzare la libreria con la funzione curl_global_init(CURL_GLOBAL_ALL) prima della creazione di qualsiasi thread del programma, indipendentemente dal fatto che in uno specifico thread vengano o non vengano utilizzate funzioni cURL.
  2. Gli handle alla libreria CURL *cl = curl_easy_init(); vanno tenuti locali al singolo thread, non vanno mai dichiarati globali o utilizzati da più thread.
  3. Prima di eseguire ogni transazione (con curl_easy_perform) e necessario impostare l'opzione CURLOPT_NOSIGNAL ad 1 con la funzione curl_easy_setopt(cl, CURLOPT_NOSIGNAL, 1). Questa operazione comporta una piccola controindicazione: potrebbero non venire più gestiti i timeout di connessione al DNS nella fase di risoluzione dei nomi. Sono possibili due soluzioni a questo problema: la prima e risolvere i nomi con una chiamata esterna alla libreria ed inserire nell'url esclusivamente indirizzi numerici; la seconda e compilare la libreria con il supporto c-ares che assicura una corretta gestione dei timeout.
  4. Altri problemi possono insorgere nell'uso di comunicazioni cifrate con SSL/TLS (e.g. https). Le librerie openSSL e GnuTLS richiedeno delle specifiche attenzioni per una corretta gestione del multithreading mentre la libreria NSS dovrebbe essere nativamente thread-safe. Per verificare le richieste delle due librerie usate per la cifrartura fare riferimento a questi link: OpenSSL, GnuTLS

Un bel tacer non fu mai scritto

Chi ha detto/scritto per primo questa frase?
Sembra che sia stato Claudio Monteverdi, compositore italiano vissuto a cavallo del XVI e XVII secolo ne "Il ritorno di Ulisse in patria" composta dall'autore nel 1640 poco prima della sua morte.

mercoledì 18 novembre 2009

Introduzione a cURL

La breria cURL ci permette di effettuare in modo semplice connessioni HTTP, FTP ed altro da programmi scritti in C. La libreria insieme alla documentazione completa è possibile trovarla sul sito ufficiale: http://curl.haxx.se/. Il modo più semplice per iniziare ad utilizzare la libreria è di usale la cosiddetta "easy interface" un set ridotto di API per un uso semplice e veloce. Tutto l'esempio descritto di seguito fa riferimento a un sistema Linux, sotto Windows possono essere richieste modifiche più o meno grandi a seconda del compilatore e dell'ambiente di sviluppo utilizzato.
Primo passo è di inserire nel sorgente l'opportuno include:
#include
si deve definire un buffer per la ricezione dei dati di ritorno
char buf[1024];
si deve poi inizializzare la libreria con la funzione
CURL *cl = curl_easy_init();
if(!cl) {
    cout<<"Fallito l'uso di CURL"<
    return 0;

}
Si devono poi impostare le opzioni che descrivono il tipo di trasferimento
Impostiamo l'opzione verbose per avere nello stdout il log di quello che sta facendo la libreria, utile sostanzialmente in fase di debug
curl_easy_setopt(cl, CURLOPT_VERBOSE, 1);
Impostiamo l'url al quale effettuare la connessione
curl_easy_setopt(cl, CURLOPT_URL, "http://192.168.0.10/");
La parte più complessa e come farci restituire il risultato della pagina. Dobbiamo definire una funzione di callback che la libreria chiama quando riceve dei dati di ritorno
curl_easy_setopt(cl, CURLOPT_WRITEFUNCTION, curlwf);
e dobbiamo indicare alla libreria dove posizionare i dati ricevuti in attesa di elaborazione
curl_easy_setopt(cl, CURLOPT_WRITEDATA, buf);
Dopo aver definito tutte le impostazioni si effettua la chiamata voluta
curl_easy_perform(cl);
ed al termine si liberano le risorse allocate chiudendo la connessione
curl_easy_cleanup(cl);

La funzione di callback da passare alla cURL deve seguire il seguente prototipo
size_t curlwf (void *ptr, size_t size, size_t nmemb, void *stream);
i dati ricevuti sono all'indirizzo puntato da *ptr ed hanno una dimensione di size*nmemb; stream contiene il puntatore definito con l'opzione CURLOPT_WRITEDATA (nell'esempio specifico buf). Da notare che i dati ricevuti e posti in *ptr non sono null terminated, se si vogliono utilizzare come stringa è necessario aggiungere lo zero al fondo. Un esempio di funzione di callback può essere il seguente:
size_t curlwf (void *ptr, size_t size, size_t nmemb, void *stream) {
    size_t fulllen = size * nmemb;
    if (fulllen > 1000) fulllen=1000;
    memcpy(stream, ptr, fulllen);
    char *x=(char *)stream;
    x[fulllen]=0;
    return size*nmemb;
}
Infine bisogna ricordarsi di aggiungere per il linking la libreria libcurl (opzione -lcurl del compilatore/linker)

Il sorgente completo del programma di esempio è
#include

size_t curlwf (void *ptr, size_t size, size_t nmemb, void *stream);
int main()
{

    char buf[1024];
    CURL *cl = curl_easy_init();
    if(!cl) {
        cout<<"Fallito l'uso di CURL"<
        return 0;
    }
    curl_easy_setopt(cl, CURLOPT_VERBOSE, 1);
    curl_easy_setopt(cl, CURLOPT_FOLLOWLOCATION, 1);
    curl_easy_setopt(cl, CURLOPT_URL, "http://10.39.125.75/");
    curl_easy_setopt(cl, CURLOPT_WRITEFUNCTION, curlwf);
    curl_easy_setopt(cl, CURLOPT_WRITEDATA, buf);

    curl_easy_perform(cl);

    curl_easy_cleanup(cl);

    cout<<

    cout << "Finito con CURL!" << endl;
}


size_t curlwf (void *ptr, size_t size, size_t nmemb, void *stream) {
    size_t fulllen = size * nmemb;
    if (fulllen > 1000) fulllen=1000;
    memcpy(stream, ptr, fulllen);
    char *x=(char *)stream;
    x[fulllen]=0;
    return size*nmemb;
}

martedì 17 novembre 2009

Eseguire un thread POSIX da C++

Per eseguire un thread POSIX dobbiamo chiamare la funzione
pthread_create(pthread_t *thread, const pthread_attr *attr, void *(*start_routine)(void *), void *arg)
Il problema nell'utilizzare questa cfunzione C in un programma C++ e che la funzione che deve essere eseguita dal nuovo thread
void * start_routine(void *arg)
deve essere una funzione C standard e non può dunque essere un metodo di una classe.
Per poter eseguire un metodo di uno specifico oggetto come nuovo thread, cosa che molto presumibilmente si vuole fare se si è deciso di utilizzare il C++, si deve utilizzare un piccolo trucco: si deve utilizzare una funzione C che richiama il metodo voluto.
In particolare supponiamo di voler richiamare il metodo Start dell'oggetto obj appartenete alla classe myClass ; si deve prima di tutto definire la funzione incaricata di avviare il thread
void * start_routine(void *p)
{
    myClass *pObj = (myClass *)p;
    pObj->Start();
    delete pObj;

    pthread_exit(NULL);
}
Nella funzione principale del programma (o dovunque si voglia far partire il nuovo thread) si deve inserire il seguente codice:
pthread_t pTh;
myClass *obj = new myClass();
obj->setParam(a, b, c);
pthread_create(&pTh, NULL, start_routine, (void *)obj);
Il metodo setParam può ovviamente essere un qualsiasi metodo utile per inizializzare lo stato dell'oggetto. La chiamata a delete dentro la start_routine è del tutto opzionale e serve esclusivamente se si vuole distruggere l'oggetto al terminare del thread.

lunedì 16 novembre 2009

Checksum Offloading

Grazie all'uso delle moderne schede di rete i sistemi operativi moderni possono delegare il calcolo delle checksum UDP/TCP direttamente al chipset della scheda sgravando parzialmente il lavoro della CPU. Tuttavia almeno due inconvenienti possono capitare: il primo (che può capitare solo alle persone più tecnice e che quindi dovrebbero conoscere problema e risposta) e che andando a effettuare uno sniff dei pacchetti di rete in uscita si rileva una "cheksum error", errore per altro non più presente sulla macchina di destinazione.
Il secondo e che in taluni casi kernel e driver possono essere ingannati dalle schede e cercare di utilizzare il "checksum offloading" anche con schede di rete non in grado di supportarlo con conseguenti rallentamenti e malfunzionamenti di rete

Sotto Linux il "checksum offloading" è presente in tutti i kernel 2.6 a seconda del driver della scheda di rete utilizzato, è tuttavia possibile disabilitarlo con il comando
ethtool -K eth0 rx on tx off

Sotto Windows questa caratteristica esiste a partire da XP/server 2003. Il "checksum offloading" è abilitato/disabilitato a livello di driver, per tanto in caso di malfunzionamenti è opportuno cercare un driver più aggiornato o verificare se il diver supporta l'abilitazione/disabilitazione della caratteristica.
Per fare questo occorre andare nelle proprietà della scheda di rete, premere il pulsante "Configura" accanto al nome della scheda, andare nel tab "Avanzate" e cercare un proprietà con un nome del tipo del tipo "UDP/TCP checksum offload" oppure del tipo "TCP offload".

E opportuno disabilitare queste opzioni solo in caso di effettivi problemi, altrimenti il risultato è esclusivamente un appesantimento del carico della CPU con conseguente rallentamento del sistema

mercoledì 4 novembre 2009

Ripristino del MBR e del Boot Sector di Windows

Il ripristino del Master Boot Record e del Boot Sector di un'installazione di Windows può essere effettuato mediante il comando bootrec.exe.
Tale comando è presente nel DVD di installazione originale di Windows (nella cartella \windows\system32\) ed è raggiungibile effettuando il boot dal DVD scegliendo "Ripristina il computer" e nella finestra delle opzioni di ripristino del sistema scegliendo "Prompt dei comandi".

Una spiegazione dell'uso di questo comando la s può trovare nella knowledge base di Microsoft Qui

Avviare Linux dal boot manager di Windows Vista

Solitamente quando sullo stesso PC si vuole installare sia Windows che Linux si usa GRUB per decidere al boot quale sistema avviare sulla macchina. Può tuttavia in alcune situazioni risultare utile utilizzare il boot manager di Windows per avviare entrambi i sistemi operativi (per esempio in presenza di alcuni software di sicurezza che hanno il brutto vizio di riscrivere il MBR se non trovano quello originale di Windows). Per raggiungere questo risultato bisogna procedere comedescritto di seguito.
L'esempio si basa sull'ipotesi di un di un disco sata con una partizione primaria dove è installato Windows e tre estese per Linux e lo swap e per condividere i dati tra i duo S.O. Ovvero le partizioni seguono il seguente schema
/dev/sda1     Windows Vista NTFS
/dev/sda5     Linux ext3
/dev/sda6     swap linux
/dev/sda7     FAT32
Per prima cosa dobbiamo installare il GRUB non più nel MBR (in quanto windows lo sovrascrive con il suo) ma direttamente nella partizione dove è installato Linux. Dopo aver avviato Linux (eventualmente tramite un liveCD se nessun boot manager è funzionante) avviare grub e dare i seguenti comandi
grub> root(hd0,4)
grub> setup(hd0,4)
grub> quit
Successivamente per poter istruire correttamente il Windows Boot Manager dobbiamo effettuare una copia del boot sector di Linux (sempre rimanendo in Linux) con il comando
dd if=/dev/sda5 of=/tmp/linux.bin bs=512 count=1
dove /tmp è una cartella che dovrà essere accessibile anche a Windows, nell'esempio è il mount point di /dev/sda7 ma potrebbe essere un qualunque dispositivo rimovibile formattato con FAT.

Aquesto punto possiamo passare a Windows, eventualmente installandolo se non lo abbiamo ancora fatto, e comunque ripristinando nel MBR il codice del boot manager di Vista. Tutte le successive operazioni elencate dovranno essere eseguite da una finestra di comandi con i privilegi amministrativi.
Per prima cosa copiare il file linux.bin precedentemente creato nella radice della partizione attiva; solitamente è il disco C: ma se non si è sicuri utilizzare il comando diskmgmt.msc per verificarlo.
Usare il comando bcdedit.exe per aggiungere la "entry" di GRUB nel boot manager di Vista con la seguente sintassi
bcdedit /create /d "GRUB" /application BOOTSECTOR
questo comando ritornerà un id del tipo {25ac1879-54cf-04bd-dfc73e60be72} che di seguito chiamerò esclusivamente {ID}. Si dovrà quindi specificare quale device contiene la copia del boot sector ed in quale file con i comandi:
bcdedit /set {ID} device boot
bcdedit /set {ID} PATH \linux.bin
Alla fine dobbiamo dire al boot manager in quale ordine proporci le scelte e per quanto tempo con i comandi
bcdedit /displayorder {ID} /addlast
bcdedit /timeout 10
Al reboot successivvo apparirà la schermata del Windows Boot Manager dando la scelta se avviare Windows o GRUB (dal quale sarà poi possibile avviare Linux)

P.S.
Avendone la possibilità è tuttavia più indicato e più semplice installare EasyBCD che permette di configurare il boot manager di Vista in maniera più semplice e intuitiva

martedì 3 novembre 2009

Il comando qlist di Gentoo

Il comando qlist delle distribuzioni Linux Gentoo di base permette di visualizzare i files appartenenti ad un determinato package, tuttavia ha motenzialità molto maggiori. Per utilizzare qlist è necessario installare il package app-portage/portage-utils.
Come accennato l'uso più banale di qlist è ottenere la lista dei files presenti in un package, ad esempio con il comando:
qlist app-portage/portage-utils 
o semplicemente
qlist portage-utils

Per conoscere tutti i packages installati nella categoria app-admin si può dare il comando:
qlist -I app-admin/*

Se invece voglio sapere tutti i pacchetti installati che hanno a che fare con il gcc si può dare il comando
qlist -I gcc

La lista dei pacchetti ottenuta da qlist può essere utilizzata come input di altri comandi; ad esempio volendo effettuare il re-emerge di tutti i pacchetti della categoria media-video posso usare il comando:
emerge -va `qlist -C -I media-video/*`


 

venerdì 30 ottobre 2009

(MOVED) Partizioni più grandi di 2TB, MBR, GPT e parted

Si illustra come effettuare una partizione più grande di 2GB su sistemi linux, fornendo anche una panoramica più generale delle problematiche associate

Questo post è stato spostato su:

http://freeehowto.wordpress.com/2010/05/19/partizioni-piu-grandi-di-2tb-mbr-gpt-e-parted/

giovedì 29 ottobre 2009

Gestione dei profili in Gentoo Linux

Il sistema portage (il package manager di Gentoo Linux) prevede la possibilità per alcuni package di avere diverse versioni installate; le configurazioni standard però prevedono l'uso di una ed una sola delle versioni disponibili di un determinato package. La scelta di quale versione di questi package deve essere utilizzato a livello di sistema può essere effettuata mediante il comando eselect. Tale comando deve essere installato mediante il package app-admin/eselect.
I moduli gestibili da eselect si possono vedere eseguendo il comando stesso senza ulteriori parametri; un help di ogni singolo modulo è ottenibile dando eselect . Tipicamente tutti i moduli contengono gli extra comandi
  • list: per vedere i possibili profili
  • show: per vedere il contenuto dei profili correnti
  • set : per impostare il profilo specifico, dove è il numero del profilo voluto ottenibile dal comando list
I moduli di eselect più importanti sono sicuramnte:
  • profile: permette di impostare il profilo generale del sistema, ovvero tutto l'insieme dei files di configurazione di base della distribuzione. I files dei profili sono in /usr/portage/profiles
  • kernel: Permette di impostare la versione dei sorgenti del kernel da utilizzare
  • python: permette di selezionare la versione di python di default; bisogna infatti ricordare che il linguaggio di script python è una componente fondamentale della distribuzione
Un modulo anch'esso molto importante, anche se un po' particolare, è il modulo rc. Questo permette la gestione dei runlevel, permette di visualizzare gli script di init presenti sul sistema, vedere i runlevel esistenti, i processi dei singoli runlevel ed il loro stato 

Altro modulo di sicura importanza è il modulo news che permette la lettura delle news di gentoo che vengono tipicamente inserite durante gli aggiornamenti dei pacchetti con il portage.


Una nota particolare merita la gestione dei profili del gcc. Questa non avviene (alla data di questo post) mediante il comando eselect, ma attraverso l'apposito comando gcc-config

mercoledì 28 ottobre 2009

(MOVED) Valorizzazioni di errno

Vengono elencate e sinteticamente descritte le valorizzazioni di "errno" in un sistema Linux e con linguaggio di sviluppo C/C++

Questo post è stato spostato su:

http://freeehowto.wordpress.com/2010/05/31/valorizzazioni-di-errno-in-cc/


Uso del comando ulimit in Linux

Il comando ulimit è un comando interno della shell Bash che permette di controllare e limitare l'accesso a risorse globali di sistema da parte della shell nella quale lo si esegue e da parte dei processi derivati.
Per vedere tutti i limiti impostati si può utilizzare il comando

ulimit -a

I limiti impostabili in Linux (kernel 2.6.30) sono i seguenti:
  • ulimit -c -> core file size in blocchi: limite massimo delle dimensioni del file di core (file generato dal sistema al crash di un eseguibile). Solitamente posto a 0 (nessun file di core può essere generato) può essere utile impostarlo a unlimited per in caso si voglia effettuare un debug postmortem di un'applicazione. Utile soprattutto durante la fase di sviluppo
  • ulimit -d -> data segment size in kB: dimensione del segmento dati. Generalmente posto a unlimited; può essere utile ridurlo durante la fase di sviluppo per simulare il funzionamento di un applicazione in un ambiente con poca memoria
  • ulimit -e -> scheduling priority: la priorità di base del processo (sostanzialmente il nice)
  • ulimit -f -> max file size in blocchi: massima dimensione dei file scrivibili dal processo. Solitamente posto a unlimited. Se il processo tenta di scrivere un file di dimensione maggiore di quelle permesse viene terminato con un segnale del tipo SIGXFSZ.
  • ulimit -i -> max pending signals: numero massimo di segnali in coda per il processo. Solitamente posto ad un valore di circa 30000 (2^15 - qualcosa). 
  • ulimit -l -> max locked memory in kB: Generalmente impostato a qulche decina (tra 32 e 64) imposta la dimensione massima della memoria che può essere bloccata in ram (non paginabile su disco). Aumentare questo valore può rendere inefficiente la gestione della memoria da parte del S.O. tuttavia può essere necessario in particolari applicazioni real-time dove l'accesso al disco può risultare incompatibile con le necessità del real-time.
  • ulimit -m -> max memory size in kB: quantità massima di memoria fisica utilizzabile da un processo. Generalmente impostata a unlimited può essere utilile limitarla per alcuni processi che devono funzionare in modo non assistito (batch) e che debbono avere ridotti impatti sul sistema complessivo.
  • ulimit -n -> max open file: numero massimo di file aperti contemporaneamente.
  • ulimit -p -> pipe size in unità di 512 byte: dimensione della pipe.
  • ulimit -q -> max POSIX message queue size in byte: dimensione massima della ram utilizzata dalle message queue POSIX. Generalmente impostata a 800 kB può essere necessario aumentarla per processi che impiegano massicciamente questi elementi del sistema. Se si eccede il limite la richiesta di creazione della coda mq_open fallisce con errore ENOMEM
  • ulimit -r -> real-time priority
  • ulimit -s -> max stack size in kB: dimensione massima dello stack. Generalmente impostata a 8MB
  • ulimit -t -> max cpu time in secondi: massimo tempo di cpu utilizzabile dal processo, utilizzato il quale il processo viene terminato con un segnale del tipo SIGXCPU. Generalmente impostato a unlimited può essere ridotto se si vuole che un processo possa utilizzare la cpu per un periodo massimo di tempo
  • ulimit -u -> max user process: numero massiomo di processi che un singolo utente può avere attivi contemporaneamente. Contrariamente agli altri valori gestibili con ulimit questo limite non agisce a livello di permesso ma di utente. Una chiamata a fork dopo aver raggiunto questo limite genera un errore del tipo EAGAIN
  • ulimit -v -> max virtual memory in kB: quantità massima di memoria virtuale utilizzabile dal processo. Generalmente posta a unlimited. Se si eccede il limite un'uteriore richiesta di allocazione di memoria fallisce con ENOMEM
  • ulimit -x -> max file locks
Sono impostabili due tipi di limiti:
  • I limiti Hard sono impostabili esclusivamente da un utente con i privilegi di root e si impostano aggiungendo il flag -H alla linea di comando (e.g. ulimit -Hl per impostare la massima quantità di memoria bloccabile in ram; ulimit -Ha per visualizzarli tutti)
  • I limiti Soft, impostabili con i comandi visti sopra possono esere modificati da qualsiasi utente per i propri processi nei limiti imposti dai parametri Hard.

giovedì 22 ottobre 2009

Posix Message Queue Vs. IPC SYSV messages

Esistono tre modi principali in Linux per scambiare dei messaggi tra due distinti processi.
  1. Usare dei socket IP, ma non è argomento di questo post
  2. Le POSIX message queues 
  3. Le Message queues System V interproces comunication system 
Entrambi i sistemi presi in considerazione da questo post permettono lo scambio di messaggi tra diversi processi attraverso strutture implementate a livello di kernel (per le MQ POSIX a aprtire dalla versione 2.6.6), ma presentano anche sostanziali differenze.
Le MQ POSIX nascono in tempi più recenti, sono considerate più attuali, sono meglio mantenute dagli sviluppatori del kernel, offrono maggiore portabilità verso altri sistemi Unix e non. Al contrario le SYSV IPC sono più datate, poco o niente mantenute (alcuni dicono a rischio scomparsa) e di difficile o nulla portabilità.
Le MQ POSIX presentano un ottima integrazione nei file system linux. Vengono identificate attraverso un nomefile (qualche cosa del tipo /nomecoda); possono essere visualizzate e manipolate attraverso un file system standar (previamente montato con il comando mount -t mqueue none /nome_nelladirectory); possono essere configurate attraverso il file system standard di linux /proc/sys/fs/mqueue. Inoltre sotto Linux un message queue descriptor è a tutti gli effetti un file descriptor e dunque monitorabile con funzioni quali select o poll. Le MQ SYSV seguono regole poco conformi agli standard Linux. Vengono identificate attraverso un id numerico; vengono visualizzate e manipolate attraverso specifici comandi (ipcs, ipcrm); il descriptor ottenuto non è un file descriptor e dunque va manipolato con le funzioni specifice; alcuni parametri di configurazione possono essere manipolati dal file system /proc/sys/kernel.
A livello prestazionale POSIX e SYSV sembrano equivalersi, è oportuno tenere presente che sempre più le API SYSV sono e saranno implementate come layer aggiuntivo sulle API POSIX e dunque con prestazioni certamente non migliori di queste ultime. Le MQ POSIX nascono pensando al real-time e sono quindi meglio strutturate per compiti di questo tipo.
Per contro essendo ancora relativamente recenti le MQ POSIX non godono ancora della diffusione della quale godono le SYSV IPC, ad esmpio le POSIX MQ non sono ancora gesstite da linguaggi quali il php

martedì 6 ottobre 2009

Il costrutto "union" in C#

Il linguaggio C ci fornisce il comodo costrutto union utile per esempio per convertire variabili o strutture di tipo diverso ma di eguale dimensione.
In C# il costrutto union non esiste, esistono al suo posto le classi StructLayoutAttribute e FieldOffsetAttribute entrambe appartenneti al namespace System.Runtime.InteropServices. La StructLayoutAttribute può essere applicata a dei costrutti di tipo class o struct mentre la FieldOffsetAttribute viene applicata ai membri della classe o struttura.
Supponendo di voler convertire un Int16 (intero a 16 bit) in due byte (8 bit) e viceversa possiamo utilizzare il seguente costrutto:

    [StructLayout(LayoutKind.Explicit, Size = 2)]
    struct U16B
    {
        [FieldOffset(0)]
        public byte B1;
        [FieldOffset(1)]
        public byte B2;
        [FieldOffset(0)]
        public Int16 I16;
    }

Questo crea una struttura con i cambi I16 e B1, B2 che condividono gli stessi 2 byte di memoria in maniera del tutto analoga alle union del C.
Anche l'uso è del tutto analogo.
Per convertire l'intero nei due byte che lo compongono si usa il seguente codice:

Int16 a = 12345;
byte[] b = new byte[2];
U16B u = new U16B();

u.I16 = a;
b[1] = u.B2;
b[0] = u.B1;

La documentazione di riferimento si può trovare qui:

Scrivere file binari e di testo in c#

Per scrivere un file binario seguire il seguente esempio:

FileStream fs = File.Create("C:\\Users\\pippo\\test.dat");
    BinaryWriter bw = new BinaryWriter(fs);
        bw.Write(variabileDaScrivere);
    bw.Close();
fs.Close();

Pe scrivere un file di testo seguire il seguente esempio:

TextWriter tw = new StreamWriter("C:\\Users\\pippo\\test.txt");
    tw.WriteLine("Testo da scrivere...");
tw.Close();

Qui si può trovare la documentazione di riferimento:

(MOVED) Impostazione di un controllo di una finestra da un thread separato in C#

Si descrive come agire su un controllo del .NET Framework da un thread diverso da quello del controllo stesso utilizzando il linguaggio C#

Questo post è stato spostato all'URL

http://freeehowto.wordpress.com/2010/07/13/impostazione-di-un-controllo-di-una-finestra-da-un-thread-separato-in-c/

lunedì 5 ottobre 2009

(MOVED) Creazione di thread in C#

Si illustra come creare un thread in C#

Questo post è stato spostato su:


http://freeehowto.wordpress.com/2010/07/13/creazione-di-thread-in-c/

Trovare l'handle della finestra in applicazioni WPF

Con l'introduzione del .net framework 3.5 e delle applicazioni basate su WPF (Windows Presentation Foundation Classes) Microsoft ha rivoluzionato massicciamente il concetto di finestra. Uno dei parametri che ne ha fatto le spese è il concetto di handle della finestra.
Nelle applicazioni di tipo "Windows Form" (.NET 2.0) ottenere il valore dell'handle di una finestra era alquanto semplice in quanto era sufficente leggere la proprietà hWnd della nostra finestra:


Int i = Window1.hWnd;


Più difficile recuperare il valore in una applicazione WPF dove la proprietà .hWnd non esiste più.
Ci viene in aiuto la classe WindowInteropHelper appartenente al namespace System.Windows.Interop. Adeguata documentazione si può reperire all'URL

http://msdn.microsoft.com/it-it/library/system.windows.interop.windowinterophelper.aspx 

L'uso è molto semplice. E' sufficente creare un'istanza della classe passando come parametro del costruttore la finestra di nostro interesse (oggetto di tipo System.Windows.Window). L'handle che ci interessa è una proprietà dell'oggetto così ottenuto.



WindowInteropHelper wih = new WindowInteropHelper(Application.Current.MainWindow);
Int hWnd = wih.Handle;