[ precedente ] [ Contenuti ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ 13 ] [ 14 ] [ 15 ] [ A ] [ successivo ]

La guida Debian
Capitolo 13 - Programmazione


Non usate "test" come nome di un file eseguibile di prova. test è un comando interno di shell.


13.1 Dove iniziare

Riferimenti:

Molti documenti info più lunghi possono essere ottenuti rilegati da GNU.

Le quattro sezioni a seguire contengono dei semplici scripts, in linguaggi differenti, per creare un file di testo contenente le informazioni di account, da aggiungere a /etc/passwd, utilizzando un "batch processor" come il programma newusers. Ogni script richiede come input un file con le righe sotto forma di nome cognome password. (Le directory home reali di ciascun utente non vengono create con questi script.)


13.2 Shell

Leggere gli shell script è il miglior modo per comprendere il funzionamento di un sistema tipo Unix. Qui fornisco alcuni indirizzi per la programmazione nella shell.


13.2.1 Bash – la shell interattiva standard GNU

Riferimenti per Bash:

Esempio di programma breve (crea delle voci di account per newusers a partire da un input standard):

     #!/bin/bash
     # (C) Osmu Aoki Sun Aug 26 16:53:55 UTC 2001 Public Domain
     pid=1000;
     while read n1 n2 n3 ; do
     if [ ${n1:0:1} != "#" ]; then
     let pid=$pid+1
     echo ${n1}_${n2}:password:${pid}:${pid}:,,,/home/${n1}_${n2}:/bin/bash
     fi
     done

13.2.2 Le shell POSIX

Parecchi pacchetti forniscono una shell POSIX shell in Debian:

Se scrivete uno script che sia portabile, è meglio scriverlo come script POSIX. Usate /bin/sh collegato a ash o (dash) per testarne la complianza con POSIX. Evitate di scrivere gli script con dei bashismi.


13.2.3 Parametri della shell

Ecco parecchi parametri speciali da ricordare:

     $0      = nome della shell o dello script
     $1      = primo(1) argomento della shell
      ...
     $9      = nono(9) argomento della shell
     $#      = numero dei parametri posizionali
     "$*"    = "$1 $2 $3 $4 ... $n"
     "$@"    = "$1" "$2" "$3" "$4" ... "$n"
     $?      = stato di uscita del comando più recente
     $$      = PID di questo script
     $!      = PID del processo più recente lanciato in background

Espansioni dei parametri basilari da ricordare:

         Forma       Se var è impostata(*)    Se var non è impostata(*)
     ${var:-stringa}  $var                stringa
     ${var:+stringa}  stringa              null
     ${var:=stringa}  $var                stringa 
                                         (e lancia var=stringa)
     ${var:?stringa}  $var                (echo stringa ed esce)

I due punti, qui, `:' in tutti questi operatori sono opzionali.

Sostituzioni dei parametri basilari da ricordare:

         Forma       Risultato
     ${var%suffisso}   Rimuove il più piccolo pattern suffisso
     ${var%%suffisso}  Rimuove il più largo pattern suffisso
     ${var#prefisso}   Rimuove il più piccolo pattern prefisso
     ${var##prefisso}  Rimuove il più largo pattern prefisso

13.2.4 Redirezione

Redirezione basilare da ricordare (dove [n] è un numero opzionale):

     [n]> file     Redireziona l'output standard (o n) a file.
     [n]>> file    Aggiunge l'output standard (o n) a file.
     [n]< file     Redireziona l'input standard (o n) da file.
     [n1]>&n2      Redireziona l'output standard (o n1) a n2.
     > file >&2    Redireziona l'output standard e di errore a file.
     | comando     Con una pipe invia l'output standard (o n) a comando.
     >&2 | comando Coun una pipe invia l'output standard e di errore a comando.

13.2.5 Condizionali

Ciascun comando ritorna uno stato di uscita che può essere utilizzato per le espressioni condizionali:

Notate che l'utilizzo del valore 0 per "vero" differisce dalle convenzioni usuali in altre aree di programmazione. In aggiunta, `[' è l'equivalente del comando test, che valuta i suoi argomenti fino a `]' come espressione condizionale.

Idiomi condizionali basilari da ricordare sono:

     comando && se_successo_lancia_anche_questo_comando
     comando || se_non_ha_successo_lancia_anche_questo_comando
     
     if [ espressione_condizionale ]; then  
      se_ha_successo_lancia_anche_questo_comando
     else
      se_non_ha_successo_lancia_anche_questo_comando
     fi

Gli operatori per la comparazione dei file nelle espressioni condizionali sono:

     -e file         Vero se file esiste.
     -d file         Vero se file esiste ed è una directory.
     -f file         Vero se file esiste ed è un file regolare.
     -w file         Vero se file esiste ed è scrivibile.
     -x file         Vero se file esiste ed è eseguibile.
     file1 -nt file2 Vero se file1 è più recente di file2. (modificato)
     file1 -ot file2 Vero se file1 è più vecchio di file2. (modificato)
     file1 -ef file2 Vero se se sono gli stessi numeri di inode e device.

Gli operatori di comparazione delle stringhe nelle espressioni condizionali sono:

          -z str    Vero se la lunghezza di str è zero.
          -n str    Vero se la lunghezza di str è non-zero.
     str1 == str2   Vero se str sono uguali.
     str1 = str2    Vero se str sono uguali.
                    ( = può essere usato al posto di == )
     str1 != str2   Vero se str non sono uguali.
     str1 <  str2   Vero se str1 viene prima di str2 (dipende da locale).
     str1 >  str2   Vero se str1 viene dopo str2 (dipende da locale).

Gli operatori aritmetici di comparazione degli interi nelle espressioni condizionali sono -eq, -ne, -lt, -le, -gt, o -ge.


13.2.6 Processamento delle righe di comando

La shell processa uno script come segue:

Le virgolette semplici all'interno delle doppie non hanno effetto.


13.3 Awk

Referimenti per Awk:

Esempio di programma breve (crea delle voci di account per newusers):

     #!/usr/bin/awk -f
     # Script per creare un file utilizzabile con il comando 'newusers',
     # a partire da un file che contiene user IDs e passwords sotto forma di:
     # Nome Cognome password
     # Copyright (c) KMSelf Sat Aug 25 20:47:38 PDT 2001
     # Distributed under GNU GPL v 2, or at your option, any later version.
     # This program is distributed WITHOUT ANY WARRANTY.
     
     BEGIN {
         # Assign starting UID, GID
         if ( ARGC > 2 ) {
             startuid = ARGV[1]
             delete ARGV[1]
         }
         else {
             printf( "Usage:  newusers startUID file\n" \
               "...where startUID is the starting userid " \
               "to add, and file is \n" \
               "an input file in form firstname last name password\n" \
             )
             exit
         }
     
         infile = ARGV[1]
         printf( "Starting UID: %s\n\n", startuid )
     }
     
     /^#/ { next }
     
     {
         ++record
         first = $1
         last = $2
         passwd = $3
         user= substr( tolower( first ), 1, 1 ) tolower( last )
         uid = startuid + record - 1
         gid = uid
         printf( "%s:%s:%d:%d:%s %s,,/home/%s:/bin/bash\n",  \
             user, passwd, uid, gid, first, last, user \
             )
     }

Due sono i pacchetti che forniscono il POSIX awk in Debian:


13.4 Perl

Questo è l' interprete su un sistema simil-Unix.

Riferimenti per Perl:

Esempio di programma breve (crea delle voci di account per newusers):

     #!/usr/bin/perl
     # (C) Osamu Aoki Sun Aug 26 16:53:55 UTC 2001 Public Domain
     $pid=1000;
     while (<STDIN>) {
             if (/^#/) { next;}
             chop;
             $pid++;
             ($n1, $n2, $n3) = split / /;
             print $n1,"_",$n2,":", $n3, ":",$pid,
                       ":",$pid,",,,/home/",$n1,"_",$n2,":/bin/bash\n"
     }

Installate Perl module <module name>:

     # perl -MCPAN -e 'install <module name>'

13.5 Python

E' un valido interprete object-oriented.

Riferimenti per Python:

Esempio di programma breve (crea delle voci di account per newusers):

     #! /usr/bin/env python
     import sys, string
     
     # (C) Osamu Aoki Sun Aug 26 16:53:55 UTC 2001 Public Domain
     # Ported from awk script by KMSelf Sat Aug 25 20:47:38 PDT 2001
     # This program is distributed WITHOUT ANY WARRANTY.
     
     def usages():
         print \
     "Usage:  ", sys.argv[0], " start_UID [filename]\n" \
     "\tstartUID is the starting userid to add.\n" \
     "\tfilename is input file name. If not specified, standard input.\n\n" \
     "Input file format:\n"\
     "\tfirstname lastname password\n"
                     return 1
     
     def parsefile(startuid):
         #
         # main filtering
         #
         uid = startuid
         while 1:
             line = infile.readline()
             if not line:
                 break
             if line[0] == '#':
                 continue
             (first, last, passwd) = string.split(string.lower(line))
             # above crash with wrong # of parameters :-)
             user = first[0] + last
             gid = uid
             lineout = "%s:%s:%d:%d:%s %s,,/home/%s:/bin/bash\n" %  \
                 (user, passwd, uid, gid, first, last, user)
             sys.stdout.write(lineout)
             +uid
     
     if __name__ == '__main__':
         if len(sys.argv) == 1:
             usages()
         else:
             uid = int(sys.argv[1])
             #print "# UID start from: %d\n" % uid
             if len(sys.argv) > 1:
                 infilename   = string.join(sys.argv[2:])
                 infile = open(infilename, 'r')
                 #print "# Read file from: %s\n\n" % infilename
             else:
                 infile = sys.stdin
             parsefile(uid)

13.6 Make

Riferimenti per Make:

Semplici variabili automatiche:

Regole di sintassi:

     Obiettivo: [ Prerequisito ... ]
      [TAB] command1
      [TAB] -command2 # ignora gli errori
      [TAB] @command3 # sopprime l'echoing

Qui [TAB] è un codice TAB. Ogni riga viene interpretata dalla shell dopo la sostituzione della variabile da parte di make. Usate \ alla fine della riga per continuare a capo lo script. Usate $$ per $ per le variabili d'ambiente dello shell script.

Regola delle equivalenze implicite:

     .c:   header.h == %  : %.c header.h
     .o.c: header.h == %.c: %.o header.h

Variabili automatiche per le summenzionate regole:

     foo.o: new1.c new2.c.c old1.c new3.c
     $@ == foo.o                         (obiettivo)
     $< == new1.c                        (il primo)
     $? == new1.c new2.c new3.c          (i più recenti)
     $^ == new1.c new2.c.c old1.c new3.c (tutti)
     $* == `%' motivo corrispondente al motivo obiettivo.

Riferimenti delle variabili:

     foo1 := bar    # Espansione unica
     foo2  = bar    # Espansione ricorsiva
     foo3 += bar    # Appendi
     SRCS := $(wildcard *.c)
     OBJS := $(foo:c=o)
     OBJS := $(foo:%.c=%.o) 
     OBJS := $(patsubst %.c,%.o,$(foo)) 
     DIRS  = $(dir directory/filename.ext) # Estrae la "directory"
     $(notdir NAMES...), $(basename NAMES...), $(suffix NAMES...) ...

Per vedere le regole interne automatiche, lanciate make -p -f/dev/null.


13.7 C

Preparazione:

     # apt-get install glibc-doc manpages-dev libc6-dev gcc

Riferimenti per C:


13.7.1 Un semplice programma in C (gcc)

Un semplice esempio di compilazione di example.c, con una libreria libm in un eseguibile run_example:

     $ cat > example.c << EOF 
     #include <stdio.h>
     #include <math.h>
     #include <string.h>
     
     int main(int argc, char **argv, char **envp){
             double x;
             char y[11];
             x=sqrt(argc+7.5);
             strncpy(y, argv[0], 10); /* prevent buffer overflow */
             y[10] = '\0'; /* fill to make sure string ends with '\0' */
             printf("%5i, %5.3f, %10s, %10s\n", argc, x, y, argv[1]);
             return 0;
     }
     EOF
     $ gcc -Wall -g -o run_example example.c -lm
     $ ./run_example
         1, 2.915, ./run_exam,     (null)
     $ ./run_example 1234567890qwerty
         2, 3.082, ./run_exam, 1234567890qwerty

Qui, -lm è necessario per il link della libreria libm per sqrt(). La libreria vera è in /lib con il nome libm.so.6, link simbolico a libm-2.1.3.so.

Guardate l'ultimo parametro nel testo risultante. Ci sono più di 10 caratteri, anche se viene specificato %10s.

L'uso di puntatori di funzioni che richiedano operazioni in memoria senza controlli sui loro "confini", tipo sprintf e strcpy, non è considerato sufficiente a prevenire gli effetti di exploit tipo buffer overflow, che annullano gli effetti di overrun. Utilizzate, invece, snprintf e strncpy.


13.7.2 Debugging


13.7.2.1 Debugging con gdb

Preparazione:

     # apt-get install gdb

Riferimenti per gdb:

Per il debugging di un programma compilato con l'opzione -g, usate gdb. Molti comandi possono essere abbreviati. L'espansione del comando mediante tab funziona come per la shell.

     $ gdb program
     (gdb) b 1                # imposta il punto di interruzione alla riga 1
     (gdb) run arg1 arg2 arg3 # lancia il programma
     (gdb) next               # riga successiva
     ...
     (gdb) step               # un passo avanti
     ...
     (gdb) p parm             # stampa parm 
     ...
     (gdb) p parm=12          # imposta il valore di parm a 12

Anche i seguenti comandi possono essere utili.

Per il debugging da emacs, fate riferimento a Riassunto dei comandi per emacs e vim, Sezione 11.3.4.


13.7.2.2 Controllo delle dipendenze dalle librerie

Usate ldd per scoprire da quali librerie dipende un programma:

     $ ldd /bin/ls
             librt.so.1 => /lib/librt.so.1 (0x4001e000)
             libc.so.6 => /lib/libc.so.6 (0x40030000)
             libpthread.so.0 => /lib/libpthread.so.0 (0x40153000)
             /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

Affinchè ls funzioni in un ambiente chrootato le librerie di cui sopra devono essere disponibili all'interno dell'ambiente chrootato.

Utili anche i seguenti comandi:


13.7.2.3 Debugging con gli strumenti per scoprire i memory leak

Parecchi sono gli strumenti per il riconoscimento dei memory leak in Debian.

Vedere anche Debugging Tools for Dynamic Storage Allocation and Memory Management.


13.7.3 Flex – una miglior... Lex

flex è un veloce generatore ed analizzatore lessicale.

Riferimenti per flex:

Al vostro programma dovete fornire una propria main() e yywrap(), altrimenti program.l apparirà come nell'esempio qui sotto, tentando la compilazione senza librerie (yywrap è una macro; %option main diventa implicitamente %option noyywrap):

     %option main
     %%
     .|\n    ECHO ;
     %%

In alternativa, potete compilarlo con l'opzione -lfl al termine della riga di comando cc (tipo ATT-Lex con -ll). In questo caso nessuna %option è richiesta.


13.7.4 Bison – un Yacc migliore

Alcuni pacchetti forniscono un LALR parser generator Yacc-compatible in Debian:

Riferimenti per bison:

Dovete fornire la vostra main() e yyerror(). main() chiama yyparse() che chiama yylex(), normalmente creata con FleX.

     %%
     
     %%

13.7.5 Autoconf

autoconf è uno strumento per produrre degli shell script in grado di configurare automaticamente il codice sorgente dei programmi usando l'intero sistema di compilazione GNU, adattandoli a molti tipi di sistema simil-Unix.

autoconf produce lo script di configurazione configure. configure crea automaticamente un Makefile personalizzato e Makefile.am.


13.7.5.1 Compilare ed installare un programma

Debian non tocca i file in /usr/local (vedere Supportare le differenze, Sezione 2.5). Quindi, se compilate un programma dai sorgenti, installatelo in /usr/local, così non interferirà con Debian.

     $ cd src
     $ ./configure --prefix=/usr/local
     $ make
     $ make install # questo comando mette i file nel sistema

13.7.5.2 Disinstallare un programma

Se avete ancora il sorgente e Se utilizza autoconf/automake e se ricordate come l'avete configurato:

     $ ./configure tutte-le-opzioni-che-avevate-dato
     # make uninstall

In alternativa, se siete assolutamente sicuri che il processo di installazione pone i file solo sotto /usr/local e che non c'è nulla di importante lì, potete cancellarne utto il contenuto con:

     # find /usr/local -type f -print0 | xargs -0 rm -f

Se non siete sicuri di dove i file siano installati, dovreste prendere in considerazione l'uso di checkinstall, che fornisce un percorso pulito per la disinstallazione.


13.8 Preparazione di documenti


13.8.1 roff

Tradizionalmente, roff è il principale sistema di scrittura testo in Unix.

Vedere roff(7), groff(7), groff(1), grotty(1), troff(1), groff_mdoc(7), groff_man(7), groff_ms(7), groff_me(7), groff_mm(7), ed "info groff".

Esiste un buon tutorial sulle macro -me. Se avete groff (1.18 o più recente), trovate /usr/share/doc/groff/meintro.me.gz e fate quanto segue:

     $ zcat /usr/share/doc/groff/meintro.me.gz | \
          groff -Tascii -me - | less -R

Quanto segue profurrà un file totalmente in formato testo:

     $ zcat /usr/share/doc/groff/meintro.me.gz | \
         GROFF_NO_SGR=1 groff -Tascii -me - | col -b -x > meintro.txt

Per la stampa, usate l'output PostScript.

     $ groff -Tps meintro.txt | lpr
     $ groff -Tps meintro.txt | mpage -2 | lpr

13.9 SGML

Preparazione:

     # apt-get install debiandoc-sgml debiandoc-sgml-doc

Riferimenti per debiandoc-sgml:

SGML permette la gestione dei formati multipli dei documenti. Un sistema SGML semplice è Debiandoc, utilizzato qui. Richiede delle comversioni minori dai files di testo originali per i seguenti caratteri:

     <   &lt;
     >   &gt;
     " " "&nbsp;"  (spazio non divisibile)
     &   &amp;
     % &percnt; © &copy; – &ndash; —
     &mdash;

Per marcare una sezione come commento non stampabile, date:

     <!-- Il commento va qui ... -->

Per marcare una sezione con un commento modificabile, date:

     <![ %FIXME [ Il commento va qui ... ]]>

In SGML, la prima definizione di un'entità vince. Per esempio:

     <!entity % qref "INCLUDE"> <![ %qref [ <!entity
     param "Data 1"> ]]> <!entity param "Data 2"> &param;

Questa termina come "Data 1". Se la prima riga è, invece, "IGNORE", questa terminerà come "Data 2" (La seconda riga è un'affermazione condizionale). Anche le frasi ripetute possono essere definite a priori, separatamente dal contesto.

     <!entity dichièquesto "mio">
     Ciao amico &dichièquesto;.
     Questo è il &dichièquesto; libro.

Che dà ciò come risultato:

     Ciao amico mio.
     Questo è il mio libro.

Vedere il breve esempio in SGML sample.sgml in esempi.

Quando i documenti SGML diventano voluminosi, talvolta TeX può dare degli errori. Dovete, in tal caso, aumentare le dimensioni del pool in /etc/texmf/texmf.cnf (o, più appropriatamente modificate /etc/texmf/texmf.d/95NonPath e lanciate update-texmf) per risolvere questo problema.


13.10 Creare pacchetti debian

Preparazione:

     # apt-get install debian-policy developers-reference \
             maint-guide dh-make debhelper
     # apt-get install packaging-manual # se su Potato

Riferimenti per il packaging:


13.10.1 Impacchettare un singolo binario

Metodo spiccio per impacchettare un singolo binario, da Joey Hess.

     # mkdir -p mypkg/usr/bin mypkg/DEBIAN
     # cp binary mypkg/usr/bin
     # cat > mypkg/DEBIAN/control
     Package: miopacchetto
     Version: 1
     Architecture: i386
     Maintainer: Joey Hess <joeyh@debian.org>
     Description: il mio piccolo pacchetto
     Non vi aspettate granchè.
     ^D
     # dpkg-deb -b mypkg

13.10.2 Impacchettare con gli strumenti

Usate dh_make dal pacchetto dh-make per creare un pacchetto base. Poi, procedete secondo le istruzioni contenute in dh-make(1). Queste usano debhelper in debian/rules.

Un approccio più datato è quello di usare deb-make dal pacchetto debmake. Non usa nessuno script debhelper e dipende esclusivamente dalla shell.

Per degli esempi di pacchetti con sorgenti multipli vedete "mc" (dpkg-source -x mc_4.5.54.dsc), che usa "sys-build.mk" di Adam Heath (doogie@debian.org) e "glibc" (dpkg-source -x glibc_2.2.4-1.dsc), che usa un altro sistema di Joel Klecker (espy@debian.org).


[ precedente ] [ Contenuti ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ 13 ] [ 14 ] [ 15 ] [ A ] [ successivo ]

La guida Debian

1.07-1, dom mar 7 15:48:58 UTC 2004

Osamu Aoki osamu@debian.org
Editor: David Sewell dsewell@virginia.edu
Traduzione italiana: Davide Di Lazzaro mc0315@mclink.it
Autori, Sezione A.1