Archivi categoria: Nerdaccia

tux-jail-banner

Rompere una jailroot

A volte capita che su appliance o semplicemente su sistemi con sicurezza molto elevata il nostro utente sia collocato in una jailroot, ossia in un ambiente isolato dal root filesystem e con un ristretto numero di comandi disponibili.

Ovviamente stiamo parlando di una situazione in ambiente Linux (ovvero un qualsiasi sistema basato su un kernel linux, ed in particolare superiore o equivalente alla version 2.4).

Ebbene non essendo possibile mantenere questo isolamento  (per varie ragioni, ma essenzialmente per la necessaria gestione dei processi) per quanto riguarda il filesystem virtuale /proc, questo ci consente di rompere parzialmente l’isolamento della jailroot e conoscere molto del sistema reale che l’isolamento presunto ci voleva nascondere.

Essenzialmente la rimozione di molti comandi amministrativi (e molte utilità) vorrebbero impedire la lettura di quelle configurazioni che di norma potrebbero essere lette (ma non manipolate) da un utente normale; altre configurazioni non sono accessibili per la sicurezza intrinseca del filesystem. Ma stiamo parlando delle configurazioni statiche. La configurazione in essere (running) risiede (per molte componenti del sistema essenzialmente) nel kernel, ed il kernel è accessibile tramite il filesystem virtuale /proc, in moltissime sue parti anche da utenti non privilegiati.

Mediante questo assunto possiamo portare quindi due esempi su come accedere a informazioni quali tabella di routing (in assenza del comando route) oppure alla lista dei processi (in assenza del comando ps) facendo uso solo del filesystem virtuale /proc e di soli comandi interni ad una bash.

Tabella di routing

Se non ci hanno voluto fornire il comando route, possiamo ovviare mediante:

while read IFA DST GW FL REF USE MET MSK MTU WIN IRTT do
if [ $IFA != "Iface" ]; then
echo -ne "$IFA\t ${DST:4:2}${DST:6:2}${DST:2:2}${DST:0:2}"
echo -e "\t${GW:4:2}${GW:6:2}${GW:2:2}${GW:0:2}"
fi
done < /proc/net/route

Unico neo di questo approccio è il non poter contare su un comando tipo ipcalc per tradurre da formato esadecimale a dotted-quad. Però questo può essere fatto in un secondo momento: quello che conta è che il dato è perfettamente accessibile.

Lista processi

Se non ci hanno voluto fornire il comando ps,  possiamo ovviare con:

 for pid in /proc/[0-9]* do
[ -f $pid/cmdline ] && read CMD < $pid/cmdline while read TAG VALUE REST; do
[ "$TAG" = "Pid:" ] && echo -ne $VALUE"\t"
[ "$TAG" = "PPid:" ] && echo -ne $VALUE"\t"
[ "$TAG" = "Name:" ] && echo -ne $VALUE"\t"
[ "$TAG" = "State:" ] && echo -ne $VALUE $REST"\t"
[ "$TAG" = "Uid:" ] && echo -ne $VALUE"\t"
done < $pid/status
[ -n "$CMD" ] && echo -n $CMD
echo done

Potremmo continuare a ricercare e decodificare informazioni da /proc.

Ma è sufficiente per indicare il senso di questo approccio.

Firebase

Architetture web two-tier

Esiste un approccio standard per realizzare applicazioni web,  che tutti noi, nerd programmatori, abbiamo imparato ad utilizzare negli anni senza discutere. Si tratta dell’architettura three-tier, che consiste in: una parte di presentazione, che gira sul client ed è solitamente realizzata in html/css con qualche spruzzata di javascript; una parte di business logic, che gira sul server e viene realizzata nella gran parte dei casi in Java EE, ma anche in Python, Node.js e, perché no, il caro vecchio PHP; una parte di storage, ovvero un database relazionale MySQL, Oracle (se il cliente ha soldi da spendere), Postgres, fino ai più recenti database NoSQL (Not only SQL).

La tecnologia avanza, le mode cambiano ma, spesso, a cambiare sono soltanto i linguaggi o i prodotti utilizzati in ognuna delle tre parti dell’applicazione. Suddividere logicamente un’applicazione in livelli distinti, anche più di 3 livelli, è qualcosa di naturale e utile. Suddividere fisicamente un’applicazione in 3 componenti sviluppate separatamente con linguaggi e tecnologie diverse… dipende !

È possibile fare a meno di tutta questa complessità e realizzare un’applicazione web a singolo strato ? La risposta, ovviamente, si chiama html, css, javascript e Web Storage oppure Indexed DB. Le ultime due tecnologie servono a colmare il gap, sempre esistito, tra applicazione desktop e applicazione web, permettendo il salvataggio di dati su un’area di storage privata del proprio browser. L’applicazione, così, non ha proprio bisogno di server, ovvero, potrebbe essere distribuita attraverso un web server che si occupa di fornire i soli asset statici, ma il server non conterrebbe alcuna logica applicativa. Altro metodo di distribuzione di applicazioni web singolo strato è l’app mobile: sono sempre più diffuse le app Android che constano solamente di una WebView che visualizza il contenuto html5 fornito in bundle con l’app.

Il problema è che questo tipo di approccio non consente di realizzare applicazioni web che possano essere universalmente ritenute tali. Si tratta, più che altro, di un ottimo metodo per realizzare applicazioni cross-platform, spesso mobile, con delle tecnologie standard. In applicazioni del genere, la condivisione delle informazioni con il resto del mondo (comprese postazioni di lavoro diverse dello stesso utente) è quasi impossibile. Ma se sostituissimo il Web Storage, o l’Indexed DB con uno storage esterno ?

Dopo mille parole di premessa, arrivo al punto: Firebase, uno strumento (gratuito, per piccole applicazioni) che nasce come servizio utile a semplificare di almeno 10 volte lo sviluppo di applicazioni web. Ed è davvero così !

Si tratta di nient’altro che un database cloud NoSQL utilizzabile da molti linguaggi diversi, compreso, ovviamente javascript. Sul sito ufficiale parlano di Node.js ma, utilizzandolo così, torniamo all’architettura a 3 strati classica. Dopo la procedura di registrazione e la creazione di un database privato sul sito di Firebase, l’integrazione prevede qualche semplice passaggio.

Importare lo script di integrazione al servizio:

<script src="https://cdn.firebase.com/js/client/1.0.6/firebase.js"></script>

A questo punto, basta creare un oggetto che consenta il collegamento al servizio remoto di Firebase.


var firebaseStorage = new Firebase('https://il-mio-db.firebaseio.com/');

Il database è un tipico NoSQL document oriented, senza schemi, né vincoli, che può essere utilizzato con oggetti JSON come file di interscambio. Le funzioni per operazioni CRUD sui dati sono molto semplici da imparare, una volta capita la struttura.


// Modificare un documento esistente (creandolo, se non esiste)
firebaseStorage.child("percorso/al/documento").set({name: "Ciccio", type="Human"});

// Inserimento di un documento con un id creato da Firebase
var obj = {text: "Hello world"};
var location = firebaseStorage.child("home/documents");
var id = location.push().name();
obj.id = id; // salvo l'id all'interno del contenuto del documento stesso (tipico in contesti NoSQL)
location.child(id).set(obj); // Inserisco

// Cancellazione di un documento
firebaseStorage.child("home/documents/ilmioiddeldocumento123").remove();

// Recupero di un documento (sempre asincrono)
firebaseStorage.child("home/documents/doc123").once("value", function(documentRef) {
var document = documentRef.val();
alert(document);
});

// Recupero di un insieme di documenti (sempre asincrono)
firebaseStorage.child("home/documents").once("value", function(documentsRef) {
documents = documentsRef.val();
});
// Ovvero uguale a prima, ma nella posizione home/documents ci sono più figli

// Ricevere (in real time) una notifica quando qualche altro utente modifica un dato
firebaseStorage.child("home/documents/xxx123").on("value", function(documentChangedRef) {
//...
});
// Ovviamente, si spegne con off(...)

// Query .. si può ..

Il numero di funzioni è sufficiente per sostituire in toto un server di backend di tipo CRUD e non solo. Firebase supporta anche, come visto, la comunicazione real-time dei cambiamenti sui dati ai browser collegati e le transazioni (al contrario di molti altri prodotti NoSQL).

Veniamo al nodo cruciale: sicurezza. Dovendo semplificare al massimo lo sviluppo dell’applicazione web, firebase ha al suo interno dei moduli di sicurezza oAuth configurabili (es. Facebook login, twitter) e supporta anche la registrazione mediante username e password con verifica tramite email. Una volta configurato un sistema di autenticazione, e integrato questo all’interno dell’applicazione web, si possono impostare dei criteri di sicurezza per l’accesso ai dati, direttamente nella console di amministrazione.

{
"rules": {
"home": {
"$user": {
".read": "$user == auth.uid",
".write": "$user == auth.uid"
}
}
}
}

Con la configurazione precedente, ho indicato che solo l’utente con un un certo UID (unique identifier, fornito dal sistema di autenticazione di firebase, può accedere al percorso “home/{uid-utente}” in lettura o scrittura. Ho creato così, una cartella privata. Al momento della creazione, il database viene configurato perché chiunque possa scrivere e leggere i dati in qualsiasi posizione, anche gli utenti senza autenticazione.

Si può configurare il servizio in modo da creare delle posizioni condivise tra utenti specifici. La configurazione non è complessa ma richiede un po’ di lavoro aggiuntivo.

Conclusioni

Creare un’architettura web a due strati, eliminando completamente il livello di logica applicativa lato server è possibile e, per alcune tipologie di applicazioni, anche auspicabile.

Spesso realizziamo diversi moduli Java EJB, con livelli di persistenza per il mapping ORM, con una serie infinita di classi e interfacce per… fare semplici operazioni CRUD sui dati. In queste occasioni, un pensiero alla possibilità di eliminare completamente il server è d’obbligo.

In particolare, per quel tipo di applicazioni di tipo SaaS, in cui l’utente ottiene un servizio dall’applicazione e, per nessun motivo al mondo, cercherebbe di fare un “tamper” dell’applicazione al fine di corrompere i dati, va assolutamente bene.

Se, invece, l’integrità dei dati è fondamentale per l’applicazione, un approccio del genere sarebbe sicuramente dannoso per la buona riuscita del progetto.

EALogoBlack

Archeologia informatica: Interchange File Format

In questo mondo moderno in cui il numero dei formati file proprietari si moltiplica, fa tenerezza pensare ad un lontano passato (era il 1985) quando un colosso dell’informatica ludica (Electronic Arts) definiva uno standard per un formato file universale, tentando così di frenare quello che già all’epoca era una continua corsa alla Babele dei formati.

L’IFFInterchange File Format

L’intento era quello di definire un modello di file capace di contenere diverse componenti multimediali per i suoi software: immagini, suono, animazioni, test, ecc.

Questo standard non è stato più mantenuto e portato avanti, ma molte sono state le influenze e le similitudini che da questo sono state derivate; infatti pur non avendo avuto un futuro autonomo, lo standard è ancora enormemente diffuso (nei suoi eredi e direttamente).

Strutturalmente il file è costruito sul concetto di chunk, ossia un corpo dati identificato da un tipo (una parola a 32 bit di caratteri alfanumerici) e una dimensione (una seconda parola a 32 bit). Se la prima parola è da coniderarsi come sequenza di 4 caratteri alfanumerici interpretabili umanamente con un simbolo, la seconda parola sono un valore a 32 bit in formato big-endian.

Nel mondo Macintosh quei quattro caratteri sono noti come OSType, una parola a 32 bit che ricorre in molte strutture del sistema operativo e in qualche modo ispirate agli stessi principi del’IFF (difficile dire chi ha ispirato chi, data la quasi contemporaneità della nascita del Macintosh con IFF); nel mondo Windows gli sviluppatori chiamano FourCC questi stessi caratteri alfanumerici distintivi di una informazione.

L’uso dell’ordinamento di bit big-endian deriva dalla costruzione di questo standard su architetture Motorola 68000, il cuore dei sistemi Commodore Amiga e Apple Macintosh per i quali Electonics Arts stava sviluppando diverso software di successo (oltre a giochi, programmi di grafica come Deluxe Paint, e di musica come Deluxe Music Construction Set, ecc).

DMCS fu il primo programma capace di sfruttare la capacità di playback a 4 voci con campionamento 8-bit 22Khz dei sistemi Amiga, portando la tecnologia dei campionamenti alla portata di tutti in un epoca in cui una tecnologia analoga era appannaggio di un dispositivo professionale da circa $1700 (vedi Ensoniq Mirage).

La logica di costruzione del formato assomiglia alla codifica TLV (Type/Lenght/Value) dei protocolli di comunicazione:

  • semplici funzioni di analisi per ricercare componenti
  • elementi facilmente trascurabili durante la lettura
  • ordine di apparizione degli elementi nel file non importante
  • formato binario delle informazioni

La definizione del formato ha una certa ricorsività basata su tre strutture basilari: il ‘FORM’, il ‘LIST’ e il ‘CAT ‘. Tre identificatori di altrettanti chunk contenitori che rappresentano un formato specifico (identificato a sua volta da un altra parola 32-bit sempre simbolica), una lista di formati coordinati e un gruppo di formati non meglio correlati.

Lo standard prevedeva in qualche modo un pubblico registro degli identificatori dei chunk dati al fine di evitare collisioni (Commodore ne tenne uno di tutti i formati introdotti da software per le sue macchine); il registro doveva tener conto anche delle specifiche sul dato, al fine di rendere effettiva l’interoperabilità dei sistemi che adottassero il formato.
I vari chunk “registrati” in realtà spesso incorporavano dati destinati ad architetture specifiche e/o comunque molto legati a software o a sistemi operativi (è il caso di immagini HAM – Hold & Modify, una specifica tecnologia per schede grafiche Amiga): questo è certamente contradditorio rispetto alla possibilità di interscambio, ma di contro la definizione pubblica dei chunk poteva comunque consentire l’implementazione di una qualche forma di traduzione.

In ogni caso interpretare un formato file non significa poter gestire i dati: questo è vero anche nel caso dell’XML, pertanto IFF non si trova da solo in questo !

Una particolare implementazione di IFF che è sopravvissuta al tempo è il formato AIFF (Audio Interchange File Format) di Apple.
Un altro erede diretto del IFF è certamente il RIFF (Resource Interchange File Format) di Microsoft e IBM: RIFF è esattamente un IFF  che usa una endianess little-endian (per processori Intel). E’ il formato dei file AVI e WAV.

Tra le similitudini possiamo invece annoverare:

  • il resource fork dei sistemi Macintosh Classic ha una analoga struttura a chunk e identificazione tramite ID alfanumerici a 32 bit (ma anche alcune differenze)
  • il formato SMF (Standard Midi File, definito dalla MIDI Manufacturers Association) è un IFF mancato; quello che manca è il container FORM. Per il resto rispetta esattamente la stessa filosofia, tant’é che Microsoft ha introdotto il chunk RMID per incapsulare un SMF in un formato RIFF.

Molte idee dell’IFF rimangono ancora oggi in formati come XML (ad esempio la possibilità di saltare intere componenti di informazioni quando non se ne conosce il significato o non si ha modo di interpretarli), così come l’idea di marcare sezioni di informazioni con identificatori di 4 caratteri alfanumerici e lunghezza (vedi estensione ID3v2 al formato MP3).

Benché la sua definizione legata ad architetture a 32 bit ne impedisca l’utilizzo per dimensioni di dati/file superiori ai circa 4GB, la sua meccanica di funzionamento lo colloca ancora ai primi posti nella semplicità d’uso e implementazione.
Il concorrente diretto per gli stesi scopi è certamente l’XML (almeno questa è la vulgata): questo ha il vantaggio della portabilità (come IFF), ma l’implementazione di un buon parser XML non è meno onerosa (anzi!) di un semplice e completo parser IFF. E IFF è più rapidamente interpretabile e compatto nelle dimensioni.

Mi domando perché le buone idee spesso vengono abbandonate a favore di presunte novità, mode, interessi diversi ! Strane domande mi faccio !

articolo_itunes

Ancora su iTunes e playlist

Con l’ultimo post su iTunes ho potuto riabbracciare la programmazione AppleScript che avevo tralasciato per lunghi anni, da quando lavoravo ancora con un OS Classic 7.5.5 !

Ovviamente ci ho ripreso gusto, pertanto eccomi di nuovo con un altro post che prosegue in qualche modo il precedente.

L’idea di questa nuova estensione alle funzionalità di iTunes mi viene dal passato, ossia da quei lettori di CD Audio che erano parte degli impianti Hi-Fi degli anni 90 e che oggi sono solo appannaggio di impianti detti di “Hi-Fi esoterico“, dove un componente di tal genere può costare anche fino e oltre i 1000€! Oggi che il mondo musicale è sempre più liquido, un lettore CD Audio è qualcosa rara, pertanto per molti sono solo un ricordo.

In ogni caso quei dispositivi avevano una funzione (almeno quelli di una certa fascia) interessante che non si è diffusa nel mondo liquido. La scansione rapida delle tracce.

La scansione prevedeva l’ascolto dei primi 10 secondi di ogni traccia del disco.

Ebbene abbiamo implementato due script per iTunes che mimano questa funzione sulla playlist selezionata.

Il primo è esattamente a scansione dall’inizione di ogni traccia della playlist selezionata; il secondo invece è una variante che mi è utile nella costruzione di playlist per sonorizzazioni: consente l’ascolto degli ultimi 10 secondi di ciascuna traccia della playlist. Questa funzione è molto utile per trovare i migliori collegamenti tra fine e inizio di tracce che devono susseguirsi in un mix continuativo.

Rammentiamo (cosa non fatta nell’altro post) che per integrare i nostri AppleScript in iTunes sarà sufficiente collocarli in /Library/iTunes/Scripts.

Ovviamente anche in questo caso gli script sono un abbozzo funzionante che può essere migliorato a vostro piacere.

--
-- Scan mode 1
--
--	Head of track for 10 seconds
--
property thePlaylist : ""
property scanTime : 10

tell application "iTunes"
	-- Per le sorgentti che non sono una playlist (come Film, ecc)
	try
		set thePlaylist to (view of front window)
	on error number errn
	end try

	if thePlaylist ≠ "" then
		repeat with theTrack in (tracks of thePlaylist)
			play theTrack
			repeat while player position < scanTime
				delay 0.2
			end repeat
		end repeat
	end if
end tell
--
-- Scan mode 2
--
--	Tail of track for 10 seconds
--
property thePlaylist : ""
property scanTime : 10

tell application "iTunes"
	-- Per le sorgentti che non sono una playlist (come Film, ecc)
	try
		set thePlaylist to (view of front window)
	on error number errn
	end try

	if thePlaylist ≠ "" then
		repeat with theTrack in (tracks of thePlaylist)
			play theTrack
			set player position to (duration of theTrack) - scanTime
			repeat while player position < (duration of theTrack) - 1
				delay 0.2
			end repeat
			pause
		end repeat
	end if
end tell
core_midi_devel

Core MIDI e il tempo

Probabilmente Core Midi, parte dell’infrastruttura software Core Audio per OSX e iOS, è il software meno documentato da Apple e dal web in generale.
Volendo costruire un mini player MIDI integrato (all’interno di un programma più complesso) ho dovuto accontentarmi di un paio di esempi nella documentazione ADC (PlaySequence e PlaySoftMIDI) e i references dell’API, quasi tutta basata su strutture opache.

Costruire un modello funzionante non è stato molto difficile seguendo il prototipo PlaySenquence, apportando anche qualche modifica (ad esempio rimuovendo l’utilizzo delle classi C++ PublicUtility incluse nel progetto a favore di un paio di funzioni per la gestione del tempo di sistema).

Il problema è nato nel momento in cui ho voluto porre nell’interfaccia l’informazione del tempo corrente del brano in esecuzione con MusicPlayer (elemento dell’API).

Interrompiamo il racconto per una breve digressione sul tema temporizzazioni in ambito musicale/MIDI.

In musica il tempo si esprime tenendo presenti due parametri: la misura (ingl. bar) e la velocità.
Il tempo della misura (ingl. time signature) è un concetto più notazionale che pratico, ma che in sostanza caratterizza la collocazione reciproca delle note sull’asse tempo (e la loro durata) nel metro di riferimento adottato, ossia la misura): è un riferimento relativo capace di esprimere la struttura metrica del brano. La divisione viene indicata con una frazione che esprime quante note di quarto (ingl. quarter note; è l’unità di misura della divisione) compongono una misura (ingl. measure).

La velocità indica quanto veloci si susseguono le note. Nella notazione classica sono i riferimenti a quel “Piano”, “Pianissimo”, “Vivace”,con brio“, ecc. Con riferimento al metronomo e nella musica digitale si utilizza invece come parametro la velocità con cui si susseguono le note di quarto nel tempo, ossia quante note di quarto sono presenti in un minuto (beat per minute = BPM): è una misura assoluta e determina la velocità di esecuzione di un brano, qualsiasi metro si adotti.

Nel file MIDI (SMF = Standard Midi File) questi concetti sono espressi in vari modi. Il tempo della misura ad esempio è collocato con meta eventi nel flusso dei dati, così come la velocità di esecuzione, mentre posizione e durata delle note è espressa come differenziale tra due momenti espressi di una unità di misura estranea alla notazione tradizionale ma che funziona egregiamente come ponte tra questa e le necessità dell’informatica: lo step (o tick o, come lo definisce Core Midi, subbeat).
Lo step è una suddivisione della nota di quarto espressa a partire dal concetto di risoluzione, un concetto estraneo alla notazione classica, ma necessario a rendere la relazione tra il tempo assoluto (in milli o microsencondi, dipendentemente dal timer adottato dal software) e la nota di quarto; più propriamente uno step è la più piccola unità riconoscibile all’interno di una nota di quarto a partire da una risoluzione. Una risoluzione di 960 (quella adottata per esempio da Garage Band) indica che nella nota di quarto sono riconoscibili 960 frazioni di tempo (480 per la nota di ottavo, 240 per la nota di sedicesimo, ecc).
Quindi la risoluzione caratterizza la precisione con cui un software può esprimere le posizioni e le durate delle note (andando ben oltre la notazione tradizionale e consentendo così di esprimere quei discostamenti dalla divisione che caratterizza l’esecuzione umana di un brano). Vedi concetto di quantizzazione/umanizzazione.

E veniamo al problema in Core Midi.

Il discorso che segue fa riferimento all’API a partire da OSX 10.5 (e quindi anche iOS della stessa epoca).
L’API mette a disposizione (per la lettura di un SMF, ma anche per la generazione ex-novo) una struttura opaca MusicSequence che contiene una lista di strutture opache MusicTrack, più un accessorio di strutture e API di gestione (come il MusicEventIterator), il tutto a favore di un altro elemento opaco (MusicPlayer) capace di eseguire un brano espresso mediante un MusicSequence.
La funzione MusicSequenceFileLoad (MusicSequence References) costruisce una sequenza a partire da un SMF; nella MusicSequence le informazioni di cui abbiamo parlato in precedenza (e di cui certamente il file SMF ne ha una rappresentazione) vengono distribuite in un modo particolare e scarsamente documentato. L’unico modo di accedere alle informazioni dovrebbe essere attraverso l’API associata (strutture opache, ricordate?) ma tutto non è ben cordinato, specialmente nella documentazione.

La velocità di esecuzione del brano (ad esempio) è collocata in un dizionario leggibile mediante la funzione MusicSequenceGetInfoDictionary per la chiave “tempo”; le sue variazioni però devono essere rilevate (lo fa ovviamente anche MusicPlayer quando esegue il brano) nella “traccia tempo“, una traccia speciale in cui sono collocati (che lo siano stai nel file SMF o no) tutti i meta eventi che caratterizzazo il tempo.
La traccia tempo è ottenibile mediante la funzione MusicSequenceGetTempoTrack e iterabile mediante MusicEventIterator per leggerne e decodificarne ogni evento (se ad esempio il nostro software deve mostrare il contenuto di una MusicSequence invece di darla in pasto a MusicPlayer). Volendo usare MusicPlayer non saremo costretti a farlo.

Ma tornando al nostro problema di visualizzazione del tempo durante l’esecuzione con MusicPlayer, quello che dovremmo utilizzare è la funzione:

OSStatus MusicSequenceBeatsToBarBeatTime(
MusicSequence inSequence,
MusicTimeStamp inBeats,
UInt32 inSubbeatDivisor,
CABarBeatTime *outBarBeatTime
);

Questa dovrebbe essere intesa per mostrare il tempo (internamente espresso come numero float di note di quarto) nella canonica forma:

Misura:Battuta:Frammento di tempo

Per quanto riguarda il parametro inBeats, questo è facilmente ottenibile mediante MusicPlayerGetTime().
Per quanto riguarda la struttura CABarBeatTime del parametro di uscita outBarBeatTime non abbiamo documentazione; ma basta cercare in AudioToolbox/CoreAudioClock.h (erroneamente chiamato ancora nella documentazione AudioToolbox/CAClock.h ) per ottenere

struct CABarBeatTime {
SInt32 bar;
UInt16 beat;
UInt16 subbeat;
UInt16 subbeatDivisor;
UInt16 reserved;
};
typedef struct CABarBeatTime CABarBeatTime;

Ma per quanto riguarda il parametro inSubbeatDivisor non esiste documentazione.
Dopo varia sperimentazione intuisco che il parametro è in qualche modo associato al concetto di risoluzione. So che il file SMF pone questo valore nell’ultima parola a 16 bit del chunk THdr; ma non trovo nell’API di MusicSequence nulla che mi possa far accedere a questa informazione.
Solo una ricerca nei file AudioToolbox/CoreAudioClock.h mi conferma che il parametro subbeatDivisor è legato alla risoluzione: questo mi convince a cercare informazioni nell’API con una ricerca brutale del termine “risoluzione”.
Rinvengo una costante kSequenceTrackProperty_TimeResolution legata all’API di MusicTrack, e per la precizione alla funzione MusicTrackGetProperty e vengo a scoprire dalla documentazione che la sola traccia tempo detiene il dato di risoluzione del brano, esattamente quanto riportato in THrd.

Bingo ! Questo è il parametro necessario.

Vista la difficoltà nel reperire una informazione così vitale implemento una estensione all’API di MusicSequence (mi pare più appropriato) con il doppio fine di documentare e di semplificare l’utilizzo di questa informazione.

Ecco l’implementazione:

/**
* MusicSequenceGetResolution
*
* @author Andrea Tassotti
*
*/
OSStatus MusicSequenceGetResolution(MusicSequence inSequence, SInt16 *outResolution)
{
MusicTrack tempoTrack;

OSStatus status = MusicSequenceGetTempoTrack(inSequence, &tempoTrack);
if (status != noErr) return status;

UInt32 ioLength = sizeof(SInt16);
return MusicTrackGetProperty (
tempoTrack,
kSequenceTrackProperty_TimeResolution,
outResolution,
&ioLength
);
}

che sarà semplicemente utilizzabile nel seguente modo:

MusicTimeStamp time;
if ( MusicPlayerGetTime (player, &time) != noErr )
[NSException raise:@"getPrerollTime" format:@"Can't get time for player"];
if (time >= sequenceLength)
time = sequenceLength;

CABarBeatTime outBarBeatTime;
SInt16 resolution;

if ( MusicSequenceGetResolution(sequence, &resolution) != noErr )
resolution = 240;

if ( MusicSequenceBeatsToBarBeatTime(sequence, time, (UInt32)resolution, &outBarBeatTime) == noErr )
{
// Get the string representation of the current time (Garage Band style)
[timeTextField setStringValue: [NSString stringWithFormat:@"%04i.%2i.%2i.%03i",
outBarBeatTime.bar,
outBarBeatTime.beat,
outBarBeatTime.subbeat / (resolution/4) + 1, // 16-th
outBarBeatTime.subbeat ]];
}

Ovviamente in un caso reale (come nel mio software), la risoluzione verrà estratta una sola volta dalla traccia tempo.

Spero anche in questo caso di essere stato utile a qualcuno.

Il vice-versa, ovvero l’impostazione di una risoluzione per un file SMF si ottiene con la funzione che crea il file (questo è documentato):

OSStatus MusicSequenceFileCreate (
MusicSequence inSequence,
CFURLRef inFileRef,
MusicSequenceFileTypeID inFileType,
MusicSequenceFileFlags inFlags,
SInt inResolution);
);

Ma questa è una altra storia.

BROCADE_fnl_TM

FabricOS e configurazioni

Nella gestione di una fabbrica fiber channel realizzata con switch Brocade (o assimilabili) si ha a che fare con il sistema FabricOS (ne abbiamo già parlato in un precedente articolo). Questo ha tutta una serie di comandi per creare e modificare la sua configurazione.

A differenza del Cisco IOS, nel FabricOS la sintassi di configurazione differisce dalla sintassi nella visualizzazione della configurazione stessa. Pertanto chi è abituato a Cisco IOS trova difficoltoso “copiare” una parte della configurazione da uno switch ad un altro osservandone semplicemente la configurazione tramite i comandi alishow, zoneshow e cfgshow.

È la classica situazione in cui si trova il sistemista che deve risolvere il conflitto di due fabbriche segmentate su una connessione ISL. La soluzione passa per la clonazione della configurazione su tutti gli switch interessati.

Il comando configupload, salvando la configurazione dello switch in un formato ASCII su un server FTP o via SCP, potrebbe tornarci utile (come in molti consigliano). Ma l’utilità si ferma al poter individuare  le differenze, e soltanto a patto di riordinare le righe della configurazione prima di eseguire tale ricerca.

Applicare le opportune modifiche non è cosa diretta.

Nel file (pur potendo scegliere tra configurazione intera e riduzione al  solo chassis o al solo switch) sono presenti informazioni non replicabili su tutti gli switch.

La replica della configurazione al fine di sanare una segmentazione deve considerare solo  alias, zone e configurazioni, non parametri dello chassis o dello switch che sono parametri univoci (e devono rimanere tali), come nome, indirizzo, id di dominio, ecc. Pertanto un file generato da uno switch non potrà essere caricato su di un altro, se non al fine di un disaster recovery.

Inoltre una zona (ad esempio) in questi file è espressa con la seguente:

zone.Prod1_C_CXPROD_SPA0:Prod1_Adapter_C;CX4_PROD_SPA0

che è cosa diversa dal comando per istruirla:

zonecreate "Prod1_C_CXPROD_SPA0", "Prod1_Adapter_C;CX4_PROD_SPA0"

La cosa ottimale sarebbe poter avere una traduzione del formato del file di configurazione scaricato dallo switch reputato “modello” e poterla replicare sugli altri dopo averli ripuliti con il comando cfgclear (come molti tutorial insegnano).

Pertanto ci sarà molto utile il seguente script, progettato proprio a questo scopo:

#!/bin/bash
#
# usage: create_FOS_config.sh
#
#
awk -F. '/^alias/{ print "alicreate \""substr($2,1, index($2,":") - 1)"\", \"" substr($2, index($2,":") + 1)"\"" }' $1 | sort -k2
awk -F. '/^zone/ { print "zonecreate \""substr($2,1, index($2,":") - 1)"\", \"" substr($2, index($2,":") + 1)"\"" }' $1 | sort -k2
awk -F. '/^cfg/ { print "cfgcreate \""substr($2,1, index($2,":") - 1)"\", \"" substr($2, index($2,":") + 1)"\"" }' $1

L’ordinamento impostato nell’elenco degli alias e delle zone potrà essere utile per un esame manuale del contenuto di questa parte della configurazione una volta caricata.

Spero possa essere utile.

articolo_itunes

Esportare una playlist iTunes su chiavetta USB

Per tutti coloro che utilizzano al meglio (e felicemente) iTunes e la sua libreria organizzata e consolidata, è difficile pensare ad una organizzazione del materiale audio senza iTunes.

Molti però tendono ancora a gestire i file multimediali in maniera autonoma, specie chi di questa gestione automatizzata, comoda ed integrata non ha mai sentito parlare (non è nel loro DNA, diciamo). Va bé! ci sono forme alternative di pensiero che dicono che noi utenti Apple invero siamo indottrinati; fate come volete. Tant’é. Noi viviamo sereni.

Però il problema nasce quando occorre integrarsi con il mondo a “gestione manuale”.
Se qualcuno ci chiede una copia della nostra playlist (per ascoltare le nostre canzoni autoprodotte rigorosamente con il nostro GarageBand !!! ovviamente !!! ;-), potrebbe essere difficile raccogliere in giro per la cartella “iTunes Music” tutti i file e copiarli diciamo su una chiavetta USB.

Ecco che ci viene incontro un piccolo frammento di codice AppleScript da me creato in pochi minuti (potenza del linguaggio):

tell application "iTunes"
    repeat with aTrack in (tracks of user playlist "Prova")
        set theAlias to (get location of aTrack)
        set theAlbum to (get album of aTrack).
        tell application "Finder"
        try
                duplicate theAlias to folder "Macintosh HD:Users:andrea:Desktop:Prova"
        on error number errn
            if errn = -15267 then
                make new folder at folder "Macintosh HD:Users:andrea:Desktop:Prova" with properties {name:theAlbum}
                duplicate theAlias to folder ("Macintosh HD:Users:andrea:Desktop:Prova:" & theAlbum)
            end if
        end try
        end tell
    end repeat
end tell

Rozzamente (non abbiamo prodotto una interfaccia per richiedere sorgente, ossia playlist, e destinazione, ossia un folder) ma semplicemente questo script cercherà per noi tutti gli originali indicati da una playlist e li copierà in un folder da noi indicato: qualora il file dovesse collidere con uno già presente (ricordiamo che i nomi di file gestiti con libreria organizzata da iTunes sono fatti del numero di traccia e del titolo, quindi possono sussistere casi di omonimia in assenza di album) allora crea un subfolder con il titolo dell’album.

Potrete modificarlo a piacimento, magari creando direttamente la gerarchia di folder che più vi aggrada, introducendo altre meta informazioni, se necessario.

Buon ascolto!

tux+ibm

Linux e appliances

Mi è recentemente capitato di configurare degli switch FC IBM, modello 2498_24.
Nel verificare alcuni parametri di versione per la configurazione che mi accingevo a fare mi è andato l’occhio su un numero alquanto sospetto:

SAN:root> version
Kernel:     2.6.14.2
Fabric OS:  v6.4.2a
Made on:    Mon Jul 18 22:27:42 2011
Flash:        Tue Jan 3 17:18:42 2012
BootProm:   1.0.9

2.6.14 … interessante, mi dico. E mentre la parola Linux mi sovviene alla mente, mi ritornano certe polemiche mosse da certi “guru” sulla presunta pericolosità di adottare sistemi Linux nei comparti del networking e della sicurezza, ed è più sicuro affidarsi ad appliance da migliaia di euro (senza considerare licenze d’uso, upgrade, assistenze, ecc).
Ed eccomene una sotto mano, di queste appliance, e per di più costruita da “mamma IBM”, e chi ti trovo? Un bel sistema Linux con kernel 2.6: certo, customizzato, certo con tantissimi comandi ad hoc (vedi cosiddetto FOS) per il ruolo di questo dispositivo. Ma in finale sempre un kernel Linux.

Pertanto rido di quanti credano che comprare è meglio che realizzare in economia a partire da un semplice Linux box, specialmente per quei servizi che sono già completi e “di serie” quali un netfilter o altri elementi di livello kernel. Il resto sono pezzi di ferro da aggiungere tutto intorno.

Tanto per la cronaca; ecco altre dimostrazioni che un IBM 2498_24 è a tutti gli effetti un Linux box, customizzato e ridotto al minimo necessario.

SAN:root> uname -r
2.6.14.2
SAN:root> uname -a
Linux SAN 2.6.14.2 #1 Sat Jul 16 10:19:20 PDT 2011 ppc unknown
SAN:root> ls -l /
total 96
drwxr-xr-x   2 root     sys          4096 Jan  3  2012 bin/
drwxr-xr-x   2 root     sys          4096 Jan  3  2012 boot/
drwxr-xr-x   2 root     root         4096 Jan  3  2012 config/
drwxrwxrwx  41 root     sys          4096 Jan  3  2012 core_files/
drwxr-xr-x   3 root     sys          4096 Nov 13 12:28 dev/
lrwxrwxrwx   1 root     root           10 Nov 13 12:28 diag -> /proc/diag/
drwxr-xr-x  17 root     sys          4096 Jan 21 13:02 etc/
drwxr-xr-x   2 root     sys          4096 Jul 18  2011 export/
drwxr-xr-x  18 root     sys          4096 Nov 13 12:28 fabos/
drwxr-xr-x   2 root     sys          4096 Jul 18  2011 import/
drwxr-xr-x   2 root     sys          4096 Jul 18  2011 initrd/
drwxr-xr-x   6 root     sys          4096 Jan  3  2012 lib/
lrwxrwxrwx   1 root     sys            11 Jan  3  2012 libexec -> usr/libexec/
drwx------   2 root     root        16384 Jan  3  2012 lost+found/
drwxr-xr-x  24 root     root         4096 Jan  3  2012 mnt/
dr-xr-xr-x 214 root     root            0 Jan  1  1970 proc/
drwxr-x---   4 root     sys          4096 Jan  3  2012 root/
drwxr-xr-x   2 root     sys          4096 Jan  3  2012 sbin/
lrwxrwxrwx   1 root     sys             9 Jan  3  2012 share -> usr/share/
drwxr-xr-x   2 root     root         4096 Jan  3  2012 standby_sbin/
drwxrwxrwx   3 root     sys          4096 Jan  3  2012 support_files/
drwxr-xr-x   2 root     sys          4096 Jul 18  2011 tftpboot/
drwxrwxrwt   5 root     root            0 Jan 23 14:26 tmp/
drwxr-xr-x   2 root     sys          4096 Jul 18  2011 users/
drwxr-xr-x  11 root     sys          4096 Jan  3  2012 usr/
drwxr-xr-x  11 root     sys          4096 Jan  3  2012 var/

E vogliamo parlare di un

tail /var/log/nslog.txt
?

Va bene. Ogni altra considerazione è puramente superflua.

Il seguente articolo è anche disponibile nel seguente Blog

nokia-lumia-800

Windows Phone (7.8): sincronizzare contatti e calendari Google

Se anche voi siete in possesso di uno smartphone con sistema operativo Windows phone ma non riuscite ad importare i contatti e i calendari di google, vuol dire che, come me, avete uno smartphone che non supporta Windows 8, e a cui la Microsoft ha deciso di dare un contentino facendo un aggiornamento a Windows 7.8 (release 7.10.8862.144) che dovrebbe correggere alcuni errori riscontrati da alcuni utenti. Gli smartphone interessati sono i seguenti:

  • Nokia Lumia 900
  • Nokia Lumia 800
  • Nokia Lumia 710
  • Nokia Lumia 610

Il problema è che Google Sync sarà disponibile solo per Windows 8, e chi è in possesso di uno degli smartphone citati precedentemente, in teoria, non potrà importare i contatti e i calendari del proprio account Google.
Cercando sul sito www.windowsphone.com sulle FAQ si ottiene la seguente risposta:

Gli account di Google configurati per la prima volta su telefoni con l’ultima versione del software Windows Phone 7 (aggiornamento 7.10.8862.144) sincronizzano solo le e-mail. I contatti e i calendari non si sincronizzano.

Queste limitazioni ti riguardano se:

  • hai un telefono con l’ultima versione del software Windows Phone 7 e configuri il tuo account di Google per la prima volta;
  • nel tuo telefono c’è l’ultima versione del software e hai reimpostato il telefono o eliminato dal telefono il tuo account di Google e ora vuoi riconfigurare l’account.

MA NON DISPERATE… UN MODO PER SINCRONIZZARLI C’E’ e non c’è bisogno di alcuna app esterna; quella che segue è una semplice guida:

  1. Andate su Impostazioni –> e-mail e account e cliccate su aggiungi un account;
  2. Scegliete Outlook, inserite le vostre credenziali dell’account Google e cliccate su Accedi;
  3. Non vi spaventate se vi da errore, e cliccate nuovamente su Accedi; dopo la seconda volta che vi da errore uscirà una schermata e dovrete cliccare sul pulsante Avanzate, e vi verrà chiesto di inserire il dominio e il server;
  4. Inserire come dominio google e come server m.google.com; se nel nome utente viene eliminata la parte  finale dell’e-mail (@gmail.com) reinseritela e confermate.
  5. A questo punto il vostro account si sincronizzerà e potrete notare con immensa soddisfazione che importerà anche i contatti!

A questo punto il più è fatto… non vi resta che cliccare sull’account appena creato e rinominarlo da Outlook a Gmail (o qualunque altra cosa volete) e andare in rubrica per vedere i contatti.

N.B. Se non vedete i contatti in rubrica andate nelle impostazioni e nella schermata filtra contatti dovete spuntare l’indirizzo e-mail appena creato.

N.B.2 Se vedete i contatti ma non i numeri di telefono corrispondenti, assicuratevi che i vostri Google contacts abbiano una categoria ben definita (es. Cellulare, Casa, ecc.) altrimenti non li vedrete!

 Infine per quanto riguarda i calendari, quello personale lo sincronizza di default, mentre per quelli condivisi ancora non ne sono venuto a capo, ma spero di riuscirci a breve.