mardi 31 juillet 2012

Mettre à jour des propriétaires de fichier sous Unix (niveau avancé)

Il arrive parfois, des malheurs. Dernièrement, il m'ai arrivé, au travail, sous Linux en root de faire un rm -rf /*.
Ceux connaissant bien Unix comprenne l'étendu de la catastrophe !
Heureusement, seuls les répertoires "sbin", bin et etc on été supprimés.

Fort chanceusement, les postes sont tous des clones.
J'ai donc recopié les répertoires en question.

Oui mais voilà, le répertoire etc contient le fichier passwd et group qui associe UID et nom d'utilisateur.
De ce fait, je me retrouve avec des noms d'utilisateur inversé...

J'aurais pu m'arranger avec ces fichiers, mais les risques d'erreurs étaient trop nombreux.
Mieux vaut utiliser chmod.

D'accord, mais comment savoir les fichiers concernés et comment modifier juste l'utilisateur si c'est l'utilisateur qui est mauvais, ou simplement le groupe ?
Nous allons partir du principe que l'utilisateur toto doit devenir l'utilisateur emeric.

Avant d'écrire un script, il est bon d'essayer de le faire à la main pour comprendre ce qui va se passer.

La commande ls -l permet de lister les fichiers et répertoires avec leurs informations. Le premier problème vient du fait que si c'est un répertoire, le contenu est listé.
La parade ? ls -l -d, -d pour afficher un répertoire comme s'il s'agissait d'un fichier.
$> ls -l
 drwxr-xr-x   2 root  wheel      512 Aug 13  2008 altroot/
 drwxr-xr-x   2 root  wheel     1024 Aug 13  2008 bin/
 -rw-r--r--   1 root  wheel    43348 Feb 20 01:52 boot
 -rw-r--r--   1 root  wheel  6861562 Aug 13  2008 bsd
 -rw-r--r--   1 root  wheel  5534077 Aug 13  2008 bsd.rd
 drwxr-xr-x   3 root  wheel    20992 Apr  3 08:29 dev/
 drwxr-xr-x  19 root  wheel     2560 Apr  3 08:29 etc/
$>
On a donc comme information le user, le group et le nom du fichier.
La difficulté vient du fait que les champs sont séparés avec un ou plusieurs espaces.

Le contournement va faire appel à une astuce du BASH, les tableaux et IFS (internal field separator).

BASH ne connait que les chaînes de caractères. Pour lui, un tableau est simplement une chaîne avec des séparateurs.
Pour créer un tableau, il suffit de déclarer :
monTableau=( 1 2 3 )
Nous allons redéfinir l'IFS car par défaut, il n'est pas initialisé comme on le souhaite, et des effets de bord risque d'apparaître.
On le définit comme un espace :
IFS=' '
Si nous prenons une ligne pour faire un test à la main, voici ce qu'on peut faire :
$> IFS=' '
$> TAB=( $(echo ' -rw-r--r--   1 root  wheel    43348 Feb 20 01:52 boot') ) 
$> echo ${#TAB[*]} / ${TAB[*]}
9/-rw-r--r-- 1 root wheel 43348 Feb 20 01:52 boot
On voit donc que les multiples espaces ne sont pas pris en compte. En effet, BASH initialise une "case" de tableau que s'il y a une valeur.

Il sera donc nécessaire de faire le ls -l -d sur chaque fichier unitairement. Pour cela, find sera utilisé. On utilisera la capacité de find pour exécuter le ls sur les fichiers trouvés va l'option -exec.

Les éléments sont suffisants pour créer déjà ce premier script
#!/bin/sh

# Sauvegarde l'ancien field separator
OLDIFS="$IFS";

# Saut de ligne est le separateur
IFS_NL=$'\n'
IFS_SPACE=' '

IFS="$IFS_NL"

# Recherche des fichiers uniquement
for fichier in $(find $1 -exec ls -l -d {} \;)
do
    # Definit le fiel separator en tant qu'espace
    IFS="$IFS_SPACE" ;

    fichier_propriete=( $(echo $fichier) )

    username=${fichier_propriete[2]}
    groupname=${fichier_propriete[3]}
    filename=${fichier_propriete[8]}

    echo ------------
    echo $username
    echo $groupname
    echo $filename
    echo -----------

    IFS="$IFS_NL"
done

IFS="$OLDIFS"
A présent, il ne reste plus qu'à détecter les fichiers concernés et faire la modification nécessaire (user ou group ou user/group). U simple grep sur la ligne retournée par find sera suffisant.
Enfin, pas tout à fait. Une fois que la ligne est identifiée comme devant être modifiée, il faudra de nouveau utiliser grep.

Voici enfin le rendu final :
#!/bin/sh

PATTERN_USER=toto
REPLACE_USER=emeric

# Sauvegarde l'ancien field separator
OLDIFS="$IFS";

# Saut de ligne est le separateur
IFS_NL=$'\n'
IFS_SPACE=' '

IFS="$IFS_NL"

# Recherche des fichiers uniquement
for fichier in $(find $1 -exec ls -l -d {} \;)
do
    user_detect=$(echo $fichier | grep $PATTERN_USER)

    if [ -n "$user_detect" ] ;
    then
        # Definit le fiel separator en tant qu'espace
        IFS="$IFS_SPACE" ;

        fichier_propriete=( $(echo $fichier) )

        username=${fichier_propriete[2]}
        groupname=${fichier_propriete[3]}
        filename=${fichier_propriete[8]}

        echo "Proceed file "$filename

        if [ -n $(echo "$username" | grep "$PATTERN_USER") ] ;
        then
            echo "  > Change user name"
            username="$REPLACE_USER"
        fi

        if [ -n $(echo "$groupname" | grep "$PATTERN_USER") ] ;
        then
            echo "  > Change groupe name"
            groupname="$REPLACE_USER"
        fi

        chown "$username":"$groupname" "$filename"

        IFS="$IFS_NL"
    fi
done

IFS="$OLDIFS" 
Attention toutefois, si le nom de fichier contient un espace, l'utilisation de fichier_propriete[8] posera un problème car il n'y aura que la première partie du nom.

Comment résoudre ce problème ? En utilisant le nom de fichier récupéré par find plutôt que celui de ls.
Pour cela, il faudra modifier le début du script :
# Recherche des fichiers uniquement
for fichier in $(find $1)
do
    ligne=$(ls -l -d $fichier)
    user_detect=$(echo $ligne | grep $PATTERN_USER)

    if [ -n "$user_detect" ] ;
    then
        # Definit le fiel separator en tant qu'espace
        IFS="$IFS_SPACE" ;

        fichier_propriete=( $(echo $ligne) )

        username=${fichier_propriete[2]}
        groupname=${fichier_propriete[3]}
        filename="$fichier"

dimanche 29 juillet 2012

Struts et la balise option/select

Struts met à disposition un moyen de générer un dropbox (liste déroulante) en HTML.
Son utilisation est assez simple finalement.
Voici un exemple d'utilisation.

Dans votre JSP, ajouté :
<%@taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

<html:select property="proprietaire" >
  <html:optionsCollection name="InputForm"
    property="booleanList"
    label="label"
    value="value" />
</html:select>
Dans votre formulaire ajoutez :
import org.apache.struts.util.LabelValueBean;

public class InputForm extends ActionForm
{
    private String proprietaire ;

    private List<LabelValueBean> booleanList = new ArrayList<LabelValueBean>() ;
    
    public InputForm() 
    {
        booleanList.add(new LabelValueBean("OUI", "true")) ;
        booleanList.add(new LabelValueBean("NON", "false")) ;
    }

    public void setBooleanList(List<LabelValueBean> booleanList)
    {
        this.booleanList = booleanList;
    }

    public List<LabelValueBean> getBooleanList()
    {
        return booleanList;
    }

    public void setProprietaire(String proprietaire)
    {
        this.proprietaire = proprietaire;
    }

    public String getProprietaire()
    {
        return proprietaire;
    }
}
Le principe de fonctionnement est le suivant :
  • Struts génère la liste avec le contenu de l'attibut booleanList (property="booleanList") du formulaire InputForm (name="InputForm")
  • Ensuite, il prend la valeur de l'attribut proprietaire (property="proprietaire") pour sélectionner la bonne option.
  • A la validation du formulaire, il valorise l'attribut proprietaire.
Comment fait-il pour savoir ce qu'il faut afficher dans la liste et la valeur a transmettre ?
C'est l'attribut label="label" et value="value" qui indique quelle propriété de l'objet se trouvant dans la liste, prendre.
En effet, la classe LabelValueBean contient :
public class LabelValueBean implements Serializable
{
    private String label;
    private String value;
}
Cela veut donc dire qu'on peut utiliser nos propre objet et simplement indiquer les attributs à prendre.

Pour ceux qui ne souhaite pas utiliser de liste dynamique, il est possible d'utiliser directement :
<html:option value="0">Select Langue</html:option>
<html:option value="1">France</html:option>
<html:option value="2">English</html:option>
dans le html:select

vendredi 27 juillet 2012

Créer un nouveau user Oracle (schema)

Export du SID

A chaque connection, il faut exporter le SID
export ORACLE_SID=TITI

sqlplus /nolog
Cela permet de ne pas enregistrer les informations de connexion (user pwd) dans l'historique des commandes de l'OS.
SQL> connect / as sysdba
Visualiser l'ensemble des user Oracle (schema)

select username from dba_users;
Création du nouvel utilisateur

create user TOTO
identified by TOTO
default tablespace "USERSTOTO"
TEMPORARY TABLESPACE "TEMP01";

GRANT UNLIMITED TABLESPACE TO TOTO;
Cela permet de donner l'accès illimité à tous les tablespaces (!) à un utilisateur, ici TOTO.
GRANT CONNECT, RESOURCE TO TOTO;
Cela permet d'autoriser l'accès à distance (via port 1521) à ce schéma.

Si l'import ne s'est pas passé correctement, utiliser la commande suivante afin de tout purger :
DROP USER TOTO CASCADE;
Visualiser les rôles d'un utilisateur

En se connectant avec le user “system” (mot de passe habituel), exécuter une requête du type :
select * from dba_role_privs
WHERE GRANTEE LIKE 'TOTO%';

mardi 24 juillet 2012

Une recherche de balise par ID multi navigateur

Il arrive parfois d'utiliser la recherche d'un tag par getElementById. Toutefois, il m'est arrivé de constater que ça ne fonctionne pas.

Pourquoi ? Et bien, il faut savoir que cette méthode n'est pas supportée par tous les navigateurs (les anciens par exemple) mais aussi que cette méthode ne fonctionne simplement pas dans certain cas.

Après de nombreuse recherche sur internet, j'ai cumuler les astuces pour que cela fonctionne dans tout les cas.
Le résultat ? Une simple fonction JavaScript.
// Recherche un element par son ID suivant le navigateur
function getElement(id) {
    if (document.getElementById) {
        return document.getElementById(id) ;
    } else if (document.all) {
 
        return window.document.all[id] ;
    } else if (document.layers) {
 
        return window.document.layers[id] ;
    }
 
    return null ;
}

lundi 23 juillet 2012

Pourquoi mes expressions <%= variable %> ne fonctionne pas dans mon taglib ?

Récemment, je devais utiliser un taglib développé en interne de type :

<t:bouton onClick="verifierFormulaire(<%= index%>)" texte="Valider" />

Ce bouton est intégré à un iterator.
Je souhaitais donc passer à une fonction JavaScript l'index de l'itérateur.

Seulement voila, ça ne fonctionnait pas.

J'ai donc vérifier les paramètres du taglib :
<tag>
    <name>bouton</name>
    <tagclass>xxxxxxxxxxxxxx.taglib.BoutonTag</tagclass>
    <bodycontent>empty</bodycontent>

    <attribute>
        <name>onClick</name>
        <required>false</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
</tag>
J'avais bien le paramètre RtExprValue à true qui indique que l'attribut peut résulter d'une expression JSP.

Ce n'est malheureusement pas là le problème.

En effet, le problème vient du fait qu'il faut que tout le contenu de onClick doit être valorisé :
<t:bouton onClick="<%= "verifierFormulaire(" + index + ");" + %>" texte="Valider" />

Voilà donc le problème réglé.

Si ce n'est pas votre problème peut-être que ce blog peut y répondre : http://blog.lecacheur.com/2006/04/27/des-attributs-dynamiques-dans-les-taglibs/

Pourquoi un blog ?

Après 10 ans de carrière dans l'informatique (5 dans le réseau, 5 dans le développement), à noter dans un coin les solutions trouvées aux problèmes rencontrés, j'ai décider de créer un blog pour partager mes connaissances ou mes déboires.