diff options
author | Willy Tarreau <w@1wt.eu> | 2006-07-16 14:53:20 +0200 |
---|---|---|
committer | Willy Tarreau <willy@wtap.(none)> | 2006-07-26 11:00:38 +0200 |
commit | 3462eae1e5f60349b089529769a159c4df4375ed (patch) | |
tree | c968456ec80963acfd6e4f13c71c9905dac39d81 | |
parent | [RELEASE] flxutils-0.1.11 (diff) | |
download | flxutils-3462eae1e5f60349b089529769a159c4df4375ed.tar.xz |
[RELEASE] flxutils-0.1.11.1v0.1.11.1
-rw-r--r-- | init/Makefile | 2 | ||||
-rw-r--r-- | init/README.2 | 55 | ||||
-rwxr-xr-x | init/examples/.linuxrc | 82 | ||||
-rwxr-xr-x | init/examples/.preinit | 83 | ||||
-rw-r--r-- | init/init.c | 635 | ||||
-rwxr-xr-x | scripts/pkg | 1833 |
6 files changed, 2073 insertions, 617 deletions
diff --git a/init/Makefile b/init/Makefile index bc1ed4f..8b95b06 100644 --- a/init/Makefile +++ b/init/Makefile @@ -1,3 +1,3 @@ OBJS=init mkdev include ../include/rules.make -CFLAGS+=-fomit-frame-pointer +CFLAGS+=-fomit-frame-pointer -Wl,--gc-sections diff --git a/init/README.2 b/init/README.2 new file mode 100644 index 0000000..f306601 --- /dev/null +++ b/init/README.2 @@ -0,0 +1,55 @@ +Résumé rapide des commandes les plus courantes : + + - { ... } : bloc d'instructions + - &<cmd> : n'exécute CMD que si le retour précédent est OK + - |<cmd> : n'exécute CMD que si le retour précédent est ERR + - !<cmd> : inverse le code de retour de CMD, et peut être + combiné à &,| + + - te VAR=VAL => retourne TRUE si VAR=VAL dans l'env. + - in : spécifie l'init auquel on donne la main + - ec : echo + - rd : passe en mode prompt clavier, en affichant le + message. Ne retourne jamais d'erreur. Le prompt + compte les niveaux pour s'y retrouver avec les {} :-) + - mt : mount ; um : umount + - mv : mount --move ; bi : mount --bind + - ex : exécute dans un sous-process (system()) + - rx xxx yyy : execute yyy dans chroot xxx; + - md : mkdir ; ln : lien + - bl,ch,fi : devices block, char, fifo + - pr xxx yyy : pivot_root : root -> xxx/yyy ; xxx->root + + +C'est une conf opérationnelle de boot avec un linuxrc dans un initrd +et un .preinit sur un CD. +Par défaut, le kernel charge /sbin/init à partir de l'initrd. Ce dernier +est un lien qui pointe vers le script /.linuxrc, référençant lui-même +/linuxrc comme interpréteur. Le résultat est que l'on exécute : + /linuxrc < /sbin/init ce qui revient à /linuxrc < /.linuxrc + +Il est possible de forcer le chemin de linuxrc par 'init=/xxxxx' au boot. + +Ensuite, le script linuxrc monte le CD puis exécute soit /sbin/init, soit +le nom en regard de la ligne 'in xxxx' dans la conf, soit xxxx si +'init2=xxxx' est précisé sur la ligne de commande, soit enfin le paramètre +de 'in' fourni au clavier en mode prompt si "RDSHELL=1" est passé au noyau. + +Le /sbin/init du CD utilise par défaut /.preinit (qu'on aurait pu appeler +en direct par 'init=' venant d'un kernel sans initrd, ou 'init2=' venant +d'un initrd équipé du linuxrc décrit ci-dessus). + +Si le paramètre "RAMCOPY=1" est passé au kernel, alors le script recopie +tout le CD en RAM, puis le démonte. + +Si le paramètre "AUTORUN=1" est passé au kernel, alors il tentera de monter +une disquette en ext2 puis en fat, pour y exécuter /autorun dans un +sous-processus. + +Si le paramètre "INITSHELL=1" est passé au kernel, alors l'utilisateur +récupère un prompt. + +Enfin, le script transfère l'exécution à /sbin/init-sysv, ou au binaire +désigné par 'in' dans le script, ou par celui désigné par le paramètre +"INIT=xxx" passé au kernel. + diff --git a/init/examples/.linuxrc b/init/examples/.linuxrc new file mode 100755 index 0000000..24c7300 --- /dev/null +++ b/init/examples/.linuxrc @@ -0,0 +1,82 @@ +#!/linuxrc < +# mem, kmem, null, zero, random, urandom, tty0, tty, console, ptmx, initctl +# full, fd + +md /var 755 +md /proc 755 +md /cdrom 755 +ln var/tmp /tmp + +mt /proc /proc proc rw +mt /var /var tmpfs rw mode=755 +md /var/tmp 1777 +md /var/run 755 +md /dev/pts 755 + +bl 0600 0 0 3 0 hd[c,ab,64][I,0-16,1] +bl 0600 0 0 22 0 hd[c,cd,64][I,0-16,1] +bl 0600 0 0 33 0 hd[c,ef,64][I,0-16,1] +bl 0600 0 0 8 0 sd[c,a-h,16][I,0-15,1] +md /dev/rd 755 # DAC960 raid disks (majors 48-55) +bl 0600 0 0 48 0 rd/c0d[i,0-31,8] +bl 0600 0 0 48 1 rd/c0d[i,0-31,8]p[i,1-7,1] +md /dev/ida 755 # Compaq raid disks (majors 72-79) +bl 0600 0 0 72 0 ida/c0d[i,0-15,16] +bl 0600 0 0 72 1 ida/c0d[i,0-15,16]p[i,1-15,1] +md /dev/cciss 755 # Compaq CCISS raid disks (major 104) +bl 0600 0 0 104 0 cciss/c0d[i,0-15,16] +bl 0600 0 0 104 1 cciss/c0d[i,0-15,16]p[i,1-15,1] +bl 0600 0 0 11 0 sr[i,0-16,1] +ch 0600 0 0 9 0 st[i,0-15,1] +bl 0600 0 0 9 0 md[i,0-15,1] +bl 0600 0 0 2 0 fd0 +bl 0600 0 0 2 28 fd0u1440 +ch 0600 0 5 2 0 pty[c,p-za-f,16][h,0-f,1] +ch 0600 0 5 3 0 tty[c,p-za-f,16][h,0-f,1] +ch 0600 0 5 4 1 tty[i,1-12,1] +bl 0600 0 0 7 0 loop[i,0-9,1] +bl 0600 0 0 1 0 ram[i,0-9,1] +ch 0600 0 5 4 64 ttyS[i,0-9,1] +ch 0600 0 3 10 1 psaux +bl 0400 0 0 1 250 initrd +md /dev/input 755 +ch 0600 0 0 13 63 input/mice + +ln psaux /dev/mouse + +ec "Looking for a valid CDROM." +ex /sbin/findcdrom +&{ + ec "Found! Mounting the CDROM..." + mt /dev/cdrom /cdrom iso9660 ro + &ec "Done." + |ec "Failed." +} +|{ + ec "No CDROM found. You can try by yourself : 'ex /sbin/findcdrom'." + ec "Then mount it into /cdrom : 'mt /dev/cdrom /cdrom iso9660 ro'." + rd +} + +# we don't need all this anymore. +um /var +um /proc + +# pivot_root only works on mount points, so we'll fake +# /cdrom by remounting /cdrom/root into it +bi /cdrom/root /cdrom +bi /dev /cdrom/dev +pr /cdrom mnt/initrd +|rd "<pr /cdrom mnt/initrd> failed !!! Try by hand..." + +um /mnt/initrd/dev +um /mnt/initrd/cdrom /mnt/cdrom +um /mnt/initrd + +te RDSHELL=1 +&rd "You have requested this prompt by appending RDSHELL=1 to the kernel cmd line." + +in /sbin/init + +# now we're on the root, and /dev will be unmounted on exit + diff --git a/init/examples/.preinit b/init/examples/.preinit new file mode 100755 index 0000000..fead5ba --- /dev/null +++ b/init/examples/.preinit @@ -0,0 +1,83 @@ +#!/sbin/init < +# mem, kmem, null, zero, random, urandom, tty0, tty, console, ptmx, initctl +# full, fd +mt /proc /proc proc rw +mt /var /var tmpfs rw mode=755 +md /var/tmp 1777 +md /var/run 755 +md /dev/pts 755 + +bl 0600 0 0 3 0 hd[c,ab,64][I,0-16,1] +bl 0600 0 0 22 0 hd[c,cd,64][I,0-16,1] +bl 0600 0 0 33 0 hd[c,ef,64][I,0-16,1] +bl 0600 0 0 8 0 sd[c,a-h,16][I,0-15,1] +md /dev/rd 755 # DAC960 raid disks (majors 48-55) +bl 0600 0 0 48 0 rd/c0d[i,0-31,8] +bl 0600 0 0 48 1 rd/c0d[i,0-31,8]p[i,1-7,1] +md /dev/ida 755 # Compaq raid disks (majors 72-79) +bl 0600 0 0 72 0 ida/c0d[i,0-15,16] +bl 0600 0 0 72 1 ida/c0d[i,0-15,16]p[i,1-15,1] +md /dev/cciss 755 # Compaq CCISS raid disks (major 104) +bl 0600 0 0 104 0 cciss/c0d[i,0-15,16] +bl 0600 0 0 104 1 cciss/c0d[i,0-15,16]p[i,1-15,1] +bl 0600 0 0 11 0 sr[i,0-16,1] +ch 0600 0 0 9 0 st[i,0-15,1] +bl 0600 0 0 9 0 md[i,0-15,1] +bl 0600 0 0 2 0 fd0 +bl 0600 0 0 2 28 fd0u1440 +ch 0600 0 5 2 0 pty[c,p-za-f,16][h,0-f,1] +ch 0600 0 5 3 0 tty[c,p-za-f,16][h,0-f,1] +ch 0600 0 5 4 1 tty[i,1-12,1] +bl 0600 0 0 7 0 loop[i,0-9,1] +bl 0600 0 0 1 0 ram[i,0-9,1] +ch 0600 0 5 4 64 ttyS[i,0-9,1] +ch 0600 0 3 10 1 psaux +ch 0600 0 0 10 144 nvram +ch 0600 0 0 10 130 watchdog +bl 0400 0 0 1 250 initrd +ch 0600 0 0 14 0 mixer +ch 0600 0 0 14 3 dsp +md /dev/input 755 +ch 0600 0 0 13 63 input/mice +md /dev/fs 755 + +ln psaux /dev/mouse + +te RAMCOPY=1 +&{ + ec "Copying whole RootFS to RAM (can take a while)..." + mt / /mnt/initrd tmpfs rw size=33554432 + &ex /bin/cp -dRfpx / /mnt/initrd + &{ + bi /proc /mnt/initrd/proc + bi /var /mnt/initrd/var + bi /dev /mnt/initrd/dev + pr /mnt/initrd mnt/initrd # move mnt/initrd to /, and / to the new /mnt/initrd + um /mnt/initrd/dev + um /mnt/initrd/proc + um /mnt/initrd/var + um /mnt/initrd + ec "RootFS now running from RAM." + } + |{ + um /mnt/initrd + ec "Failed to copy the RootFS into RAM." + } +} + +te AUTORUN=1 +&{ + mt /dev/fd0 /mnt/floppy ext2 ro + |mt /dev/fd0 /mnt/floppy vfat ro + &{ + ex /mnt/floppy/autorun + um /mnt/floppy + } + |ec "Could not find an autorun file on the floppy disk." +} + +te INITSHELL=1 +&rd "You have requested this prompt by appending INITSHELL=1 to the kernel cmd line." + +in /sbin/init-sysv + diff --git a/init/init.c b/init/init.c index 4593a40..9204f62 100644 --- a/init/init.c +++ b/init/init.c @@ -158,6 +158,16 @@ wrong for now: #include <sys/stat.h> #include <linux/loop.h> +#ifndef MNT_DETACH +#define MNT_DETACH 2 +#endif + +#ifndef MS_MOVE +#define MS_MOVE 8192 +#endif + +#define STR_SECT ".rodata" + #ifdef DEBUG static void print(char *c) { char *p = c; @@ -174,32 +184,41 @@ static void print(char *c) { typedef unsigned char uchar; -extern char **environ; - -static const char cfg_fname[] = "/.preinit"; /* configuration file */ -static const char tmpfs_fs[] = "tmpfs"; -static const char dev_console[] = "dev/console"; -static const char dev_root[] = "dev/root"; -static const char dev_name[] = "/dev"; -static const char root_dir[] = "/"; -static const char var_dir[] = "/var"; -static const char var_run[] = "/var/run"; -static const char var_tmp[] = "/var/tmp"; -static const char proc_dir[] = "/proc"; -static const char proc_self_fd[] = "/proc/self/fd"; -static const char proc_cmdline[] = "/proc/cmdline"; -static const char sbin_init_sysv[] = "sbin/init-sysv"; -static const char str_rebuild[] = "rebuild"; -static const char dev_options[] = "size=0,nr_inodes=4096,mode=755"; - -#define tmp_name (var_tmp + 4) //static const char tmp_name[] = "/tmp"; -#define proc_fs (proc_dir+1) //static const char proc_fs[] = "proc"; -#define fd_dir (proc_self_fd + 11) //static const char fd_dir[] = "fd"; -#define UID_ROOT 0 -#define GID_ROOT 0 -#define GID_TTY 5 -#define GID_KMEM 9 +/* this ordering is awful but it's the most efficient regarding space wasted in + * long strings alignment with gcc-2.95.3 (gcc 3.2.3 doesn't try to align long + * strings). + */ +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) msg_ent_console[] = "Entering command line mode : enter one command per line, end with '.'\n"; +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) root_dir[] = "/"; +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) cur_dir[] = "."; +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) dev_name[] = "/dev"; +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) var_dir[] = "/var"; +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) cfg_fname[] = "/.preinit"; /* configuration file */ +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) msg_err_console[] = "Command ignored, input alread bound to console !\n"; +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) dev_console[] = "dev/console"; +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) str_rebuild[] = "rebuild"; +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) var_tmp[] = "/var/tmp"; +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) var_run[] = "/var/run"; +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) proc_self_fd[] = "/proc/self/fd"; +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) proc_cmdline[] = "/proc/cmdline"; +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) sbin_init[] = "sbin/init"; +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) sbin_init_sysv[] = "sbin/init-sysv"; +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) cfg_linuxrc[] = "/.linuxrc"; +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) str__linuxrc[] = "/linuxrc"; +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) dev_options[] = "size=0,nr_inodes=4096,mode=755"; +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) proc_dir[] = "/proc"; +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) tmpfs_fs[] = "tmpfs"; +static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) dev_root[] = "dev/root"; + + +#define tmp_name (var_tmp + 4) // static const char tmp_name[] = "/tmp"; +#define proc_fs (proc_dir+1) // static const char proc_fs[] = "proc"; +#define fd_dir (proc_self_fd + 11) // static const char fd_dir[] = "fd"; +#define str_linuxrc (str__linuxrc+1) // "linuxrc" + + +#define CONST_STR(x) ({ static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) ___str___[]=x; (char *)___str___; }) /* used by naming rules */ #define MAX_FIELDS 8 @@ -207,6 +226,7 @@ static const char dev_options[] = "size=0,nr_inodes=4096,mode=755"; #define MAX_CFG_SIZE 4096 #define MAX_CFG_ARGS 16 #define MAX_CMDLINE_LEN 512 +#define MAX_BRACE_LEVEL 10 struct dev_varstr { char type; @@ -226,30 +246,6 @@ struct dev_varstr { uchar scale; }; -static const struct { - char name[8]; - short gid; - char major, minor; - mode_t mode; /* mode + S_IFCHR, S_IFBLK, S_IFIFO */ -} dev_nodes[] = { - /* console must always be at the first location */ - { "console", GID_TTY, 5, 1, 0600 | S_IFCHR }, - { "mem", GID_KMEM, 1, 1, 0640 | S_IFCHR }, - { "kmem", GID_KMEM, 1, 2, 0640 | S_IFCHR }, - { "null", GID_ROOT, 1, 3, 0666 | S_IFCHR }, - { "port", GID_KMEM, 1, 4, 0640 | S_IFCHR }, - { "zero", GID_ROOT, 1, 5, 0666 | S_IFCHR }, - { "full", GID_ROOT, 1, 7, 0666 | S_IFCHR }, - { "random", GID_ROOT, 1, 8, 0644 | S_IFCHR }, - { "urandom", GID_ROOT, 1, 9, 0644 | S_IFCHR }, - { "tty0", GID_TTY, 4, 0, 0600 | S_IFCHR }, - { "tty", GID_TTY, 5, 0, 0666 | S_IFCHR }, - { "ptmx", GID_TTY, 5, 2, 0666 | S_IFCHR }, - { "initctl", GID_ROOT, 0, 0, 0600 | S_IFIFO }, -}; - -#define NB_TOKENS 15 - enum { TOK_LN = 0, /* ln : make a symlink */ TOK_MD, /* md : mkdir */ @@ -262,21 +258,31 @@ enum { TOK_FI, /* fi : make a fifo */ TOK_MA, /* ma : set umask */ TOK_PR, /* pr : pivot root */ - TOK_MV, /* mv : move */ - TOK_UM, /* um : umount */ + TOK_MV, /* mv : move a filesystem */ + TOK_BI, /* bi : bind a directory */ + TOK_UM, /* um : umount a filesystem */ TOK_LO, /* lo : losetup */ TOK_EC, /* ec : echo */ + TOK_TE, /* te : test an environment variable */ + TOK_RD, /* rd : read a command from the console */ + TOK_OB, /* { : begin a command block */ + TOK_CB, /* } : end a command block */ + TOK_DOT, /* . : end of config */ TOK_UNK, /* unknown command */ TOK_EOF, /* end of file */ + TOK_COND_NEG = 0x20, /* negate the result before evaluation */ TOK_COND_OR = 0x40, /* conditionnal OR */ TOK_COND_AND = 0x80, /* conditionnal AND */ - TOK_COND = 0xc0, /* any condition */ + TOK_COND = 0xE0, /* any condition */ }; +/* counts from TOK_LN to TOK_DOT */ +#define NB_TOKENS 21 + /* this contains all two-chars command, 1-char commands, followed by a token * number. */ -static const struct { +static const __attribute__ ((__section__(STR_SECT),__aligned__(1))) struct { char lcmd[2]; /* long form */ char scmd; /* short form */ char minargs; /* min #args */ @@ -293,11 +299,44 @@ static const struct { "ma", 'U', 1, /* TOK_MA */ "pr", 'P', 2, /* TOK_PR */ "mv", 'K', 2, /* TOK_MV */ + "bi", 'K', 2, /* TOK_BI */ "um", 'O', 1, /* TOK_UM */ "lo", 'l', 2, /* TOK_LO */ "ec", 0, 0, /* TOK_EC */ + "te", 0, 1, /* TOK_TE */ + "rd", 0, 0, /* TOK_RD */ + "{", '{', 0, /* TOK_OB */ + "}", '}', 0, /* TOK_CB */ + ".", '.', 0, /* TOK_DOT : put every command before this one */ }; +#define UID_ROOT 0 +#define GID_ROOT 0 +#define GID_TTY 5 +#define GID_KMEM 9 + +static const __attribute__ ((__section__(STR_SECT),__aligned__(1))) struct { + char name[8]; + short gid; + char major, minor; + mode_t mode; /* mode + S_IFCHR, S_IFBLK, S_IFIFO */ +} dev_nodes[] = { + /* console must always be at the first location */ + { "console", GID_TTY, 5, 1, 0600 | S_IFCHR }, + { "mem", GID_KMEM, 1, 1, 0640 | S_IFCHR }, + { "kmem", GID_KMEM, 1, 2, 0640 | S_IFCHR }, + { "null", GID_ROOT, 1, 3, 0666 | S_IFCHR }, + { "port", GID_KMEM, 1, 4, 0640 | S_IFCHR }, + { "zero", GID_ROOT, 1, 5, 0666 | S_IFCHR }, + { "full", GID_ROOT, 1, 7, 0666 | S_IFCHR }, + { "random", GID_ROOT, 1, 8, 0644 | S_IFCHR }, + { "urandom", GID_ROOT, 1, 9, 0644 | S_IFCHR }, + { "tty0", GID_TTY, 4, 0, 0600 | S_IFCHR }, + { "tty", GID_TTY, 5, 0, 0666 | S_IFCHR }, + { "ptmx", GID_TTY, 5, 2, 0666 | S_IFCHR }, + { "initctl", GID_ROOT, 0, 0, 0600 | S_IFIFO }, +} ; + static char cfg_data[MAX_CFG_SIZE]; static char *cfg_args[MAX_CFG_ARGS]; static char *cfg_line; @@ -306,6 +345,11 @@ static char *cst_str[MAX_FIELDS]; static char *var_str[MAX_FIELDS]; static struct dev_varstr var[MAX_FIELDS]; static int error; /* an error has emerged from last operation */ +static int linuxrc; /* non-zero if we were called as 'linuxrc' */ + +/* the two input modes */ +#define INPUT_FILE 0 +#define INPUT_KBD 1 static unsigned long my_atoul(const char *s) { unsigned long res = 0; @@ -450,23 +494,39 @@ static inline int read_cfg(char *cfg_file) { * TOK_EOF if nothing left. All args are copied into <cfg_args> as an array * of pointers. Maximum line length is 256 chars and maximum args number is 15. */ -static int parse_cfg() { +static int parse_cfg(char **cfg_data) { int nbargs; int token; int cond; + char *cfg_line = *cfg_data; memset(cfg_args, 0, sizeof(cfg_args)); while (*cfg_line) { char c, *p = cfg_line; + cond = 0; /* search beginning of line */ - while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') + do { + if (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\r') { + if (*p == '|') { + cond |= TOK_COND_OR; + } else if (*p == '&') { + cond |= TOK_COND_AND; + } else if (*p == '!') { + cond ^= TOK_COND_NEG; + } else { + /* catches any printable char and the final zero */ + break; + } + } p++; + } while (1); /* now search end of line */ cfg_line = p; - while (*cfg_line && *cfg_line != '#' && *cfg_line != '\n' && *cfg_line != '\r') + while (*cfg_line && *cfg_line != '#' && *cfg_line != '\n' && *cfg_line != '\r') { cfg_line++; + } /* terminate the line cleanly to avoid further tests */ while (c = *cfg_line) { @@ -475,37 +535,39 @@ static int parse_cfg() { break; } + /* update the caller's pointer once for all. */ + *cfg_data = cfg_line; + /* skip empty lines */ if (!*p) continue; - - if (*p == '|') { - cond = TOK_COND_OR; - p++; - } - else if (*p == '&') { - cond = TOK_COND_AND; - p++; - } - else - cond = 0; /* fills the cfg_args[] array with the command itself, followed by all - * args. + * args. cfg_args[last+1]=NULL. */ for (nbargs = 0; *p && (nbargs < MAX_CFG_ARGS - 1); nbargs++) { - int backslash = 0; + int backslash = 0, quote = 0; cfg_args[nbargs] = p; do { if (backslash) { backslash = 0; + if (*p == 'n') + *p = '\n'; + else if (*p == 'r') + *p = '\r'; + else if (*p == 't') + *p = '\t'; memmove(p - 1, p, cfg_line - p); - } - else { + } else { backslash = (*p == '\\'); - p++; + if (*p == '"') { + memmove(p, p + 1, cfg_line - p - 1); + quote = !quote; + } + else + p++; } - } while (*p && (backslash || (*p != ' ' && *p != '\t'))); + } while (*p && (backslash || quote || (*p != ' ' && *p != '\t'))); if (*p) { *p = 0; do p++; while (*p == ' ' || *p == '\t'); @@ -527,8 +589,10 @@ static int parse_cfg() { return TOK_EOF; } -/* makes a dev entry */ +/* makes a dev entry. continues on error, but reports them. */ static inline int mknod_chown(mode_t mode, uid_t uid, gid_t gid, uchar major, uchar minor, char *name) { + int error; + if (mknod(name, mode, makedev(major, minor)) == -1) { error = 1; print("init/error : mknod("); print(name); print(") failed\n"); @@ -538,6 +602,8 @@ static inline int mknod_chown(mode_t mode, uid_t uid, gid_t gid, uchar major, uc error = 1; print("init/error : chown("); print(name); print(") failed\n"); } + + return error; } /* breaks a 3-fields, comma-separated string into 3 fields */ @@ -861,16 +927,49 @@ static mode_t a2mode(char *ascii) { return m; } -int main(int argc, char **argv) { +int main(int argc, char **argv, char **envp) { int old_umask; int pid1, err; int cfg_ok; int rebuild; int token; + int cmd_input = INPUT_FILE; + static char cmd_line[256]; /* one line of config from the prompt */ struct stat statf; char *cmdline_arg; char *cfg_file; + int brace_level, kbd_level, run_level; + struct { + int error; + int cond; + } context[MAX_BRACE_LEVEL]; + + /* first, we'll check if we have been called as 'linuxrc', used only in + initrd. In this particular case, we ignore all arguments and use + /.linuxrc as a configuration file. + */ + +#ifdef DEBUG + print("argv[0]: "); print(argv[0]); print("\n"); + sleep(1); +#endif + /* if we are called as "linuxrc" or "/linuxrc", then we work a bit + * differently : /dev is unmounted at the end, and we proceed even if the + * pid is not 1. + * + * Warning: for an unknown reason (isolinux, kernel?) specifying + * 'init=/linuxrc' or 'init=linuxrc' on the command line doesn't work + * because 'init' is set in argv[0] ! But setting it by hand works, + * so does 'init=/.linuxrc'. Rather strange. So the best solution is + * to link /sbin/init to /.linuxrc so that the interpreter's name is + * used even if nothing is specified. + */ + if (!strcmp(argv[0], str_linuxrc) || !strcmp(argv[0], str__linuxrc)) { + linuxrc = 1; + rebuild = 0; + pid1 = 0; + } /* check if a config file name has been given to preinit : init [ \< <cfg_file> ] [ init args ] */ if (argc > 2 && *argv[1] == '<') { cfg_file = argv[2]; @@ -879,28 +978,40 @@ int main(int argc, char **argv) { argc -= 2; } else - cfg_file = (char *)cfg_fname; + cfg_file = linuxrc ? (char *)cfg_linuxrc : (char *)cfg_fname; - /* restore the correct name. Warning: in the case where init is launched - * from userspace, the config file is not read again so only the hardcoded - * name will be used for the executable name. - */ - *argv = &sbin_init_sysv;/*"sbin/init-sysv"*/; - old_umask = umask(0); + if (!linuxrc) { + /*FIXME*/ + /* restore the correct name. Warning: in the case where init is launched + * from userspace, the config file is not read again so only the hardcoded + * name will be used for the executable name. + */ + *argv = (char *)&sbin_init_sysv; /*"sbin/init-sysv"*/; + /* if "rebuild" is passed as the only argument, then we'll try to rebuild a + * full /dev even if not pid==1, but only if it was not already populated + */ + rebuild = (argc == 2 && streq(argv[1], str_rebuild/*"rebuild"*/)); + pid1 = (getpid() == 1); + } + else { + *argv = (char *)&sbin_init; /* "sbin/init" */ + } - /* if "rebuild" is passed as the only argument, then we'll try to rebuild a - * full /dev even if not pid==1, but only if it was not already populated - */ - rebuild = (argc == 2 && streq(argv[1], str_rebuild/*"rebuild"*/)); + if (pid1 || linuxrc) { + setsid(); + } - pid1 = (getpid() == 1) /*|| 1*/; + old_umask = umask(0); cfg_ok = (read_cfg(cfg_file) == 0); chdir(root_dir); /* be sure not to stay under /dev ! */ /* do nothing if we're not called as the first process */ - if (pid1 || rebuild) { - /* check if /dev is already populated : /dev/console should exist */ - if (stat(dev_console, &statf) == -1) { + if (pid1 || linuxrc || rebuild) { + /* check if /dev is already populated : /dev/console should exist. We + * can safely ignore and overwrite /dev in case of linuxrc, reason why + * we don't test the presence of /dev/console. + */ + if (linuxrc || stat(dev_console, &statf) == -1) { print("init/info: /dev/console not found, rebuilding /dev.\n"); if (mount(dev_name, dev_name, tmpfs_fs, MS_MGC_VAL, dev_options) == -1) print("init/err: cannot mount /dev.\n"); @@ -923,13 +1034,13 @@ int main(int argc, char **argv) { */ reopen_console(); } - } - else { - if (!pid1) { - /* we don't want to rebuild anything else if pid is not 1 */ - print("init/info: /dev is OK.\n"); - return 0; - } + } else if (!pid1) { + /* we don't want to rebuild anything else if pid is not 1 */ +#ifdef DEBUG + print("init/info: /dev is OK.\n"); + sleep(10); +#endif + return 0; } /* if /dev/root is non-existent, we'll try to make it now */ @@ -950,13 +1061,70 @@ int main(int argc, char **argv) { /* here, the cwd is still "/" */ if (cfg_ok) { - while ((token = parse_cfg()) != TOK_EOF) { + print("ready to parse file : "); print(cfg_file); print("\n"); + + run_level = brace_level = 0; + context[brace_level].error = 0; + context[brace_level].cond = 0; + + /* main parsing loop */ + while (1) { int cond = 0; - int lasterr = error; + if (cmd_input == INPUT_KBD) { + int len; + char *cmd_ptr = cmd_line; + static char prompt[MAX_BRACE_LEVEL + 4]; + char *p = prompt; + int lev1, lev2; + + p += my_strlcpy(p, error ? CONST_STR("ER\n>") : CONST_STR("OK\n>"), 5); + + lev1 = run_level; + lev2 = brace_level; + while (lev1) { + *p++ = '>'; + lev1--; + lev2--; + } + if (lev2) { + *p++ = '{'; + while (lev2--) + *p++ = '>'; + *p++ = '}'; + } + *p++ = ' '; + write(1, prompt, p-prompt); + + len = read(0, cmd_line, sizeof(cmd_line)-1); + if (len > 0) { + cmd_line[len] = 0; + token = parse_cfg(&cmd_ptr); + if (token == TOK_EOF) /* empty line */ + continue; + } else { + token = TOK_DOT; + } + + if (token == TOK_DOT) { + cmd_input = INPUT_FILE; + brace_level = kbd_level; + /* if it was not right, 'rd' would not have been called : */ + run_level = brace_level; + /* don't report prompt errors to the rest of the config ! */ + error = 0; + } + } + + if (cmd_input == INPUT_FILE) { + token = parse_cfg(&cfg_line); + if (token == TOK_EOF || token == TOK_DOT) + break; + } + if (token == TOK_UNK) { print("unknown command.\n"); - break; + continue; } cond = token & TOK_COND; @@ -964,27 +1132,152 @@ int main(int argc, char **argv) { if (cfg_args[tokens[token].minargs] == NULL) { print("Missing args\n"); - break; + continue; } - /* skip conditionnal executions if unneeded */ - if ((cond & TOK_COND_OR) && (!lasterr) || - (cond & TOK_COND_AND) && (lasterr)) - continue; - /* now we can reset the error */ + context[brace_level].error = error; error = 0; - /* the first command set is always available */ + if (token == TOK_CB) { /* closing brace */ + if (cond & TOK_COND) { + print("Conditions not permitted with a closing brace.\n"); + /* we close the brace anyway, ignoring the condition. */ + } else if (brace_level == 0) { + print("Too many closing braces.\n"); + error = context[brace_level].error; + continue; + } + /* transmit the current error to the upper level, and restore the upper + * condition to know if we had to negate the result or not. + */ + error = context[brace_level--].error; + cond = context[brace_level].cond; + if (run_level > brace_level) + run_level = brace_level; + goto finish_cmd; + } + else if (token == TOK_OB) { /* opening brace */ + if (brace_level == MAX_BRACE_LEVEL - 1) { + print("Too many brace levels.\n"); + error = context[brace_level].error; + break; + } + + /* if this block should not be executed because of a particular + * condition, we'll mark the new level to be skipped, so that + * other braces are correctly counted but not evaluated. + */ + if ((run_level == brace_level) && + (!(cond & TOK_COND_OR) || context[brace_level].error) && + (!(cond & TOK_COND_AND) || !context[brace_level].error)) { + /* save the current condition to properly handle a negation. + * The error code has already been set to 0. + */ + context[brace_level++].cond = cond; + run_level = brace_level; + } + else { + /* the braces will not be evaluated because a & or | prevents + * it to do so. Since we want to be able to chain these + * expressions to do if/then/else with &{}|{}, we'll propagate + * the current error code and void the condition. + */ + error = context[brace_level].error; + context[brace_level++].cond = 0; + } + continue; + } + + //printf("parsing intruction <%s %s...> at level %d (%d)\n", cfg_args[0], cfg_args[1], brace_level, run_level); + /* skip conditionnal executions if they cannot change the error status, + * as well as blocks of code excluded from the evaluation + */ + if ((cond & TOK_COND_OR) && !context[brace_level].error || + (cond & TOK_COND_AND) && context[brace_level].error || + (run_level < brace_level)) { + error = context[brace_level].error; + continue; + } + + + /* + * Now we begin to parse the 'real' commands. The first set is always available + */ + if (token == TOK_IN) { - /* I <path> : specify the path to init */ + /* I | in <path> : specify the path to init. + * Problem: what to do with init args ? + * We could pass ours, but if init is replaced with a + * shell, this one might be called with 'auto'... + * So we flush them all. + */ print("<I>nit : used config name for init\n"); - *argv = cfg_args[1]; + argv[0] = cfg_args[1]; + argv[1] = NULL; + + /* in keyboard mode, specifying init stops any further parsing, + * so that the rest of the config file can be skipped. + */ + if (cmd_input == INPUT_KBD) + break; + else { + /* non sense to switch error status when assigning init */ + error = context[brace_level].error; + continue; + } + //} else if (token == TOK_EC) { + /* ec <string> : echo a string */ + //int l = strlen(cfg_args[1]); + //cfg_args[1][l] = '\n'; + //write(1, cfg_args[1], l + 1); + //goto finish_cmd; + } else if (token == TOK_RD || token == TOK_EC) { + /* ec <string> : echo a string */ + /* rd <string> : display message then read commands from the console instead of the file */ + char *msg; + int len; + + if (cfg_args[1] != NULL) { + len = strlen(cfg_args[1]); + cfg_args[1][len] = '\n'; + write(1, cfg_args[1], len + 1); + } + if (token != TOK_RD) + goto finish_cmd; + + if (cmd_input == INPUT_KBD) { + msg = (char *)msg_err_console; + len = sizeof(msg_err_console) - 1; + } else { + msg = (char *)msg_ent_console; + len = sizeof(msg_ent_console) - 1; + kbd_level = brace_level; + } + error = context[brace_level].error; + write(1, msg, len); + cmd_input = INPUT_KBD; continue; - } + } else if (token == TOK_TE) { + /* te <var=val> : compare an environment variable to a value. + * In fact, look for the exact assignment in the environment. + * The result is OK if found, NOK if not. + */ + char **env = envp; + while (*env) { + //printf("testing <%s> against <%s>\n", cfg_args[1], *env); + if (!strcmp(*env, cfg_args[1])) + break; + env++; + } + error = (*env == NULL); + goto finish_cmd; + } - if (!pid1 && !rebuild) { /* other options are reserved for pid 1 only or rebuild mode */ + /* other options are reserved for pid 1/linuxrc/rebuild and prompt mode */ + if (!pid1 && !linuxrc && !rebuild && cmd_input != INPUT_KBD) { print("Command ignored since pid not 1\n"); + error = context[brace_level].error; continue; } @@ -996,14 +1289,14 @@ int main(int argc, char **argv) { error = 1; print("<D>irectory : mkdir() failed\n"); } - continue; + goto finish_cmd; case TOK_LN: /* L from to : make a symlink */ if (symlink(cfg_args[1], cfg_args[2]) == -1) { error = 1; print("<S>ymlink : symlink() failed\n"); } - continue; + goto finish_cmd; case TOK_BL: /* B <mode> <uid> <gid> <major> <minor> <naming rule> : build a block device */ case TOK_CH: @@ -1011,38 +1304,33 @@ int main(int argc, char **argv) { if (chdir(dev_name) == -1) { print("<B>lock_dev/<C>har_dev : cannot chdir(/dev)\n"); error = 1; - continue; + goto finish_cmd; } multidev(a2mode(cfg_args[1]) | ((token == TOK_BL) ? S_IFBLK : S_IFCHR), (uid_t)ATOL(cfg_args[2]), (gid_t)ATOL(cfg_args[3]), ATOL(cfg_args[4]), ATOL(cfg_args[5]), cfg_args[6]); chdir(root_dir); - continue; + goto finish_cmd; case TOK_FI: /* F <mode> <uid> <gid> <name> : build a fifo */ if (chdir(dev_name) == -1) { - error = 1; print("<F>ifo : cannot chdir(/dev)\n"); + error = 1; + goto finish_cmd; } - mknod_chown(a2mode(cfg_args[1]) | S_IFIFO, - (uid_t)ATOL(cfg_args[2]), (gid_t)ATOL(cfg_args[3]), - 0, 0, cfg_args[4]); - + error = mknod_chown(a2mode(cfg_args[1]) | S_IFIFO, + (uid_t)ATOL(cfg_args[2]), (gid_t)ATOL(cfg_args[3]), + 0, 0, cfg_args[4]); chdir(root_dir); - continue; - case TOK_EC: { - /* ec <string> : echo a string */ - int l = strlen(cfg_args[1]); - cfg_args[1][l] = '\n'; - write(1, cfg_args[1], l + 1); - continue; - } + goto finish_cmd; } /* end of switch() */ - if (!pid1) { /* other options are reserved for pid 1 only */ + /* other options are reserved for pid 1/linuxrc/prompt mode only */ + if (!pid1 && !linuxrc && cmd_input != INPUT_KBD) { print("Command ignored since pid not 1\n"); + error = context[brace_level].error; continue; } @@ -1096,7 +1384,7 @@ int main(int argc, char **argv) { } mntarg = MS_RDONLY; - if (cfg_args[4] != NULL && streq(cfg_args[4], "rw")) { + if (cfg_args[4] != NULL && streq(cfg_args[4], CONST_STR("rw"))) { print("<M>ount : 'rw' flag found, mounting read/write\n"); mntarg &= ~MS_RDONLY; } @@ -1131,7 +1419,7 @@ int main(int argc, char **argv) { res = fork(); if (res == 0) { chroot(exec_dir); - execve(exec_args[0], exec_args, environ); + execve(exec_args[0], exec_args, envp); print("<E>xec(child) : execve() failed\n"); return 1; } @@ -1140,7 +1428,7 @@ int main(int argc, char **argv) { while (wait(&error) != res) print("<E>xec(parent) : signal received\n"); - error = !WIFEXITED(error); + error = (WIFEXITED(error) > 0) ? WEXITSTATUS(error) : 1; print("<E>xec(parent) : child exited\n"); } else { @@ -1160,12 +1448,12 @@ int main(int argc, char **argv) { print("<P>ivot : error during chdir(new root)\n"); } - if (pivot_root(".", cfg_args[2]) == -1) { + if (pivot_root(/*CONST_STR(".")*/cur_dir, cfg_args[2]) == -1) { error = 1; print("<P>ivot : error during pivot_root()\n"); } - chroot("."); + chroot(cur_dir/*CONST_STR(".")*/); if (chdir(root_dir) == -1) { error = 1; print("<P>ivot : error during chdir(/)\n"); @@ -1175,15 +1463,27 @@ int main(int argc, char **argv) { reopen_console(); break; case TOK_MV: - /* K <old_dir> <new_dir> : keep directory <old_dir> after a pivot. */ + /* K | mv <fs_dir> <new_dir> : + * initially used to keep directory <old_dir> after a pivot, now used to + * move a filesystem to another directory. + */ + if (mount(cfg_args[1], cfg_args[2], cfg_args[1], MS_MGC_VAL | MS_MOVE, NULL) == 0) + break; + /* if it doesn't work, we'll try to cheat with BIND/UMOUNT */ + case TOK_BI: + /* bi <old_dir> <new_dir> : bind old_dir to new_dir, which means that directory + * <new_dir> will show the same contents as <old_dir>. + */ if (mount(cfg_args[1], cfg_args[2], cfg_args[1], MS_MGC_VAL | MS_BIND, NULL) == -1) { error = 1; - print("<mv> : error during mount\n"); + print("<bi> : error during mount|bind\n"); } - /* fall through umount */ + if (token == TOK_BI) + break; + /* fall through umount if we were trying a move */ case TOK_UM: /* O <old_dir> : umount <old_dir> after a pivot. */ - if (umount(cfg_args[1]) == -1) { + if (umount2(cfg_args[1], MNT_DETACH) == -1) { error = 1; print("<um> : error during umount\n"); } @@ -1224,9 +1524,13 @@ int main(int argc, char **argv) { print("unknown cmd in /.preinit\n"); break; } - } /* while (token != TOK_EOF) */ - } else if (pid1) { - print("init/info : error while opening configuration file\n"); + finish_cmd: + if (cond & TOK_COND_NEG) + error = !error; + } /* while (1) */ + } else if (pid1 && !linuxrc) { + print("init/info : error while opening configuration file : "); + print(cfg_file); print("\n"); /* /.preinit was not found. In this case, we take default actions : * - mount /proc @@ -1253,22 +1557,57 @@ int main(int argc, char **argv) { } } } + else { + print("init/info : error while opening configuration file : "); + print(cfg_file); print("\n"); + } if (rebuild) { + print("end of rebuild\n"); +#ifdef SLOW_DEBUG + sleep(10); +#endif /* nothing more to do */ return 0; } - /* handle the lilo command line "INIT=prog" */ - if ((cmdline_arg = find_arg("INIT")) != NULL) { - argv[0] = cmdline_arg; - argv[1] = NULL; - } + /* We undo all that we can to restore a clean context. + * In case the init has been specified by the user at the console prompt, + * we don't close 0/1/2 nor dismount /dev, else we wouldn't be able to do + * anything. + */ + if (cmd_input != INPUT_KBD) { + if (linuxrc) { + close(2); close(1); close(0); + umount2(dev_name, MNT_DETACH); + print("exit from linuxrc\n"); +#ifdef SLOW_DEBUG + sleep(10); +#endif + /* handle the lilo command line "init2=prog" */ + cmdline_arg = find_arg(CONST_STR("init2")); + } else { + /* handle the lilo command line "INIT=prog" */ + cmdline_arg = find_arg(CONST_STR("INIT")); + } + + if (cmdline_arg != NULL) { + argv[0] = cmdline_arg; + argv[1] = NULL; + } + } print("init/debug: *argv = "); print (*argv); print("\n"); umask(old_umask); - err = execve(*argv, argv, environ); +#ifdef SLOW_DEBUG + sleep(10); +#endif + err = execve(*argv, argv, envp); print("init/error : last execve() failed\n"); - sleep(200); + + /* we'll get a panic there, so let some time for the user to read messages */ + if (pid1) + sleep(60); + return err; } diff --git a/scripts/pkg b/scripts/pkg index c9f111c..ab88db7 100755 --- a/scripts/pkg +++ b/scripts/pkg @@ -1,563 +1,1460 @@ #!/bin/bash -# -# /usr/sbin/pkg - Formilux source package manager - version 0.2.3 - 2003-03-20 + +# pkg - Formilux package builder - version 0.3.2 - 2003-06-09 # # Copyright (C) 2001-2003 Benoit Dolez & Willy Tarreau # mailto: benoit@ant-computing.com,willy@ant-computing.com # # This program is licenced under GPLv2 ( http://www.gnu.org/licenses/gpl.txt ) -########## WARNING ########## -# this version is not compatible anymore with versions earlier than 0.2.0 -############################# +## WARNING ## +# This version is not compatible with pkg scripts written for pre-0.2.0 versions + + +# Usage: +# pkg <action> [ pkg [ pkg2 ] ] +# +# pkg newpkg [ new_pkg [ old_pkg ] ] +# ex: pkg newpkg openssl-0.9.6g-flx0.1 openssl-0.9.6d-flx0.1 +# pkg newpkg apache apache-1.3 +# pkg newpkg bash +# pkg newpkg gcc gcc-3*flx*.1 +# +# pkg setpkg [ new_pkg ] +# ex: pkg setpkg openssl-0.9.6g-flx0.1 +# +# pkg { info | cat | edit } [ pkg ] +# ex: pkg info +# pkg info bash +# pkg edit modutils-2.4 +# pkg cat gzip-1.3 +# +# pkg { compile,build,prepack,strip,pack,unpack,delpack,release,clean }* +# +# pkg { patch | unpatch } [ patch_name ] +# +# pkg { any_command } [ any_args ] +# + +# don't return stupid names, and we also want dotfiles and use extended globbing +shopt -s nullglob +shopt -s dotglob +shopt -s extglob + +# disable pathnames expansion +set -o noglob + +# change the default mask to avoid common security problems +umask og-w + +# set some constants +KERNDIR=${KERNDIR:-/usr/src/linux} +FLXARCH=${FLXARCH:-$(uname -m)} +DEVROOT=${DEVROOT:-/var/flx-dev} +PKGROOT=${PKGROOT:-/var/flx-pkg} +# use -p1 by default to apply a patch +PATCH_LEVEL=${PATCH_LEVEL:-1} +# the suffix that we use to name different builds. It also matches build +# versions with this name followed by a number (BUILDVER) +BUILDSFX=${BUILDSFX:-flx} +BUILDVER=${BUILDVER:-0} + +PKGSUFF="tgz" +CFGSUFF="cfg" +INSTNAME=".flxdisk" +LINKNAME=".flxpkg" -# patch -p1 by default -PATCH_LEVEL=1 +FILE_LIST= -function logit { - echo "$*" - $* - return $? +###### +###### here are some functions for manipulating package names +###### + +# returns the radix from a package name. Eg: 'pkg-1.2.3a-flx0.12' returns 'pkg' +function get_pkg_radix { + echo ${1%%[-_][0-9]*} } -function do_compile_only { - $FLXMAKE - return $? +# returns the version from a package name. Eg: 'pkg-1.2.3a-flx0.12' returns '1.2.3a' +function get_pkg_ver { + local ver=${1#${1%%[_-][0-9]*}[._-]} + ver=${ver%-${BUILDSFX}*} + [ "$ver" = "$1" ] || echo $ver } -function pre_prepack { - if [ "$UID" != "0" -a "$force" != "1" ]; then - echo "You must specify '--force' to install as non-root" - exit 1 - fi - if [ -d `pwd`/.flxdisk ] ; then rm -rf `pwd`/.flxdisk ; fi +# returns the build number from a package name when appropriate, or empty when +# there's nothing. Eg: 'pkg-1.2.3a-flx0.12-pkg' returns 'flx0.12' +function get_build_num { + local build=${1##${1%%-${BUILDSFX}*([0-9]).+([0-9])*}} # -flx0.12-pkg + build=${build%%${build##-${BUILDSFX}*([0-9]).+([0-9])}} # -flx0.12 + build=${build#-} # flx0.12 + [ "$build" != "$1" ] && echo $build } -function post_prepack { - if [ -d $ROOTDIR/opt ] ; then - (cd $ROOTDIR/opt ; mkdir bin sbin lib ) - (cd $ROOTDIR/opt ; find */bin -type f -perm +111 -exec ln -s ../{} bin \; -printf "ln -s ../%p $ROOTDIR/opt/bin\n" ) - (cd $ROOTDIR/opt ; find */sbin -type f -perm +111 -exec ln -s ../{} sbin \; -printf "ln -s ../%p $ROOTDIR/opt/sbin\n" ) - (cd $ROOTDIR/opt ; find */lib -type f -perm +111 -exec ln -s ../{} lib \; -printf "ln -s ../%p $ROOTDIR/opt/lib\n" ) - fi +# returns the build number following a known build. Eg: 'flx0.12' returns 'flx0.13' +function get_next_build { + local prefix=${1%%.*} + local suffix=${1##*.} + echo $prefix.$[$suffix + 1] } -function do_compile { - do_config_only && do_compile_only +# This function accepts a list of versionned names, and returns them sorted by +# version number. The names must NOT contain any '|' or '~' character, or they +# will be discarded. Names that don't have any version are also discarded. +function sortnames { + local IFS FIELD NUMERIC_VERSION ALPHA_VERSION VERSION + local base version rest filename i t file flist + local -a list + + # a numeric versions consists in a series of numbers delimited by dots, and + # optionnally ending with one or several dots, so that strange namings are + # correctly processed. An alphanumeric version consists in everything that + # cannot match a numeric version, optionnaly ending with one or more dots. + IFS=$'\n' + FIELD='\([^|]*\)' + NUMERIC_VERSION='\([0-9]\+\(\.[0-9]\+[.]*\)*\)' + ALPHA_VERSION='\([^0-9~|.]\+[.]*\)' + VERSION="\($NUMERIC_VERSION\|$ALPHA_VERSION\)" + + # make the list appear in the form 'package|version|rest|full_name' + list=($(echo "$*" | grep -v "|~" | sed -e "s/$VERSION/\1|/" \ + -e "s/^$FIELD|$VERSION/\1|\2|/" \ + -e "s/^$FIELD|$FIELD|$FIELD$/\1|\2|\3~\1\2\3/" \ + -e "s/^[^|]*|[^|]*$//")) + + # there's a risk that it doesn't complete for all the list, and that some + # elements keep a "rest". But what can we do about it ? + + # we loop on the list if there's at least one element + # this will build alternating series of numeric-only and non-numeric + # substrings, packed by six. + while [ "${list[0]}" ] ; do + # now we add sub-version delimiters ',' + list=( $(for file in ${list[*]} ; do + IFS="|~" ; set -- $file + base=$1 ; version=$2 ; rest=$3 ; filename=$4 + if [ -z "$rest" ] ; then + IFS="." ; set -- $version + # we append a dot to the version for sed below. + echo "$base,$1,$2,$3,$4,$5,$6|.~$filename" + continue + fi + IFS="." ; set -- $version + echo "$base,$1,$2,$3,$4,$5,$6|$rest~$filename" + done | sed -e "s/^$FIELD|\($VERSION\|\.\)/\1|\2|/")) + IFS=$'\n' + # and we stop once everyone has "|\.|~" (no rest) + if echo "${list[*]}" | grep -vq "|\.|~" ; then : ; else break ; fi + done + + # now construct a field separator list for 'sort'. Since it's full of bugs, + # the only way for it to work is -k1,1 -k2,2n -k3,3n ... + # To match most cases, we'll assume that most of our packages will be + # numbered NNNNNNAAAAAANNN... (6 numbers, 6 alpha, repeating). + IFS=',' ; i=1 ; flist= + for t in ${list[0]%%|*} ; do + if [ $i -eq 1 -o $[(($i-2)/6)&1] -eq 1 ]; then + flist="$flist${flist:+ }-k$i,$i" + else + flist="$flist${flist:+ }-k$i,$i"n + fi + i=$[$i+1]; + done + + IFS=$'\n'$'\t'' ' + # Do not use '-u' since sort is stupid enough to remove nearly identical + # lines ! + #echo "${list[*]}" | sort -t , -u $flist | cut -f2 -d~ + echo "${list[*]}" | sort -t , $flist | cut -f2 -d~ } +###### +###### here are "exported" functions, which can be used and redefined by build.cfg +###### + +# builds everything from a clean start function do_build { - for i in clean compile prepack strip pack ; do - if declare -f pre_$i > /dev/null ; then ( pre_$i ) ; fi - if [ $? != 0 ] ; then break ; fi - if declare -f do_$i > /dev/null ; then ( do_$i ) ; fi - if [ $? != 0 ] ; then break ; fi - if declare -f post_$i > /dev/null ; then ( post_$i ) ; fi - if [ $? != 0 ] ; then break ; fi - done + local ACTION + # ACTION will be inherited by other functions + for ACTION in clean compile prepack strip pack ; do + declare -f pre_$ACTION > /dev/null && { ( pre_$ACTION $* ) || return $?; } + declare -f do_$ACTION > /dev/null && { ( do_$ACTION $* ) || return $?; } + declare -f post_$ACTION > /dev/null && { ( post_$ACTION $* ) || return $?; } + done } -function do_delpack { - if [ -d `pwd`/.flxdisk ] ; then rm -rf `pwd`/.flxdisk ; fi +# this function returns one exact package name from a list of potentially +# interesting ones, classed from higher preference to lower. They are all +# passed as strings, constituting packages names, or some of the following +# special names : +# %P => use current directory as the source for the name +# %L => use the package pointed to by the ${LINKNAME} link +# %D => use the default package +# If several packages match a given pattern, the user is asked to select the +# desired one. +# The result is returned in REPLY. +function get_name { + local pattern pkg_name + local radix ver build + local -a rel_list dev_list sort_list + local i + + REPLY= + for pattern in $*; do + if [ "$pattern" = "%P" ]; then + pattern=$(basename $(pwd)) + elif [ "$pattern" = "%L" ]; then + if [ -L ${LINKNAME} -a -d ${LINKNAME}/. ]; then + # the link is always an EXACT name, so we return it as-is. + pattern=$(readlink ${LINKNAME}) + REPLY=$(basename $pattern) + return + else + continue + fi + elif [ "$pattern" = "%D" ]; then + pattern=default + fi + radix=$(get_pkg_radix $pattern) + ver=$(get_pkg_ver $pattern) + build=$(get_build_num $pattern) + pkg_name=${radix:-*}-${ver:-*}-${build:-*} + + REPLY= + # we loop until pkg_name is empty, which allows recursive choices. + while [ "$pkg_name" ]; do + # now we'll try to build a list of potentially matching packages for + # each pattern. We'll reduce the original name until either we have + # a non-empty list or the package name is void. + rel_list=( ); dev_list=( ) + while [ "$pkg_name" -a -z "$rel_list" -a -z "$dev_list" ]; do + rel_list=( $(find $PKGROOT/ -maxdepth 1 -type d -name ${pkg_name} -printf "%f\n" 2>/dev/null) ) + if [ "$release_only" != "1" ]; then + dev_list=( $(find $DEVROOT/ -maxdepth 1 -type d -name ${pkg_name} -printf "%f\n" 2>/dev/null) ) + fi + + if [ -z "${rel_list[*]}" -a -z "${dev_list[*]}" ]; then + radix=$(get_pkg_radix $pkg_name) + ver=$(get_pkg_ver $pkg_name) + build=$(get_build_num $pkg_name) + + if [ "$ver" -a "$ver" != "*" -a "$radix" != "$pkg_name" ]; then + if [ "$build" -a "$build" != "*" ]; then + pkg_name=${radix}-${ver}-* + elif [ "${ver%.*}" != "$ver" ]; then + # let's reduce the version precision + pkg_name=${radix}-${ver%.*}-* + else + pkg_name=${radix}-* + fi + else + break + fi + else + break + fi + done + + # we're prepared to break the big loop, unless someone sets pkg_name again. + pkg_name= + sort_list=( $(sortnames ${dev_list[*]} ${rel_list[*]}) ) + + # if we matched nothing, we jump to the next pattern, and if we matched + # exactly one result, we return it immediately. + if [ ${#sort_list[*]} -eq 0 ]; then + continue + elif [ ${#sort_list[*]} -eq 1 ]; then + REPLY=${sort_list[0]} + return + fi + + # now, we'll present the possible names to the user. + i=0 + printf " %5d : - None of the following packages -\n" 0 + while [ $i -lt ${#sort_list[*]} ]; do + # we'll display an 'R' in front of released names, or a 'D' for dev. + if [ "${rel_list[*]/${sort_list[$i]}/}" != "${rel_list[*]}" ]; then + printf " %5d : [R] %s\n" $[$i+1] ${sort_list[$i]} + else + printf " %5d : [D] %s\n" $[$i+1] ${sort_list[$i]} + fi + i=$[$i+1] + done + echo + + while : ; do + echo -n "Choice [${sort_list[${#sort_list[*]}-1]}]: "; read i + if [ -z "$i" ]; then + # empty string, we use the last choice which is the preferred one. + i=${#sort_list[*]} + REPLY=${sort_list[$[$i-1]]} + return + elif [ "${i//[0-9]/}" ]; then + # not a plain integer, we'll allow to recursively re-select + #pattern=${pattern}*${i} + pattern=${i} + radix=$(get_pkg_radix $pattern) + ver=$(get_pkg_ver $pattern) + build=$(get_build_num $pattern) + pkg_name=${radix:-*}-${ver:-*}-${build:-*} + break; + elif [ $i -le 0 ]; then + # if the user explicitly replied "0", then he wants other choices. + break; + elif [ $i -le ${#sort_list[*]} ]; then + REPLY=${sort_list[$[$i-1]]} + return + fi + done + # we get here only either if someone tries to refine the package name or + # if he refuses these ones. + done + done } -function do_clean { - make distclean || make mrproper || make clean - ( do_delpack ) +# choose a package and make ${LINKNAME} point to it +function do_setpkg { + rm -f ${LINKNAME} + ln -s $PKGDIR ${LINKNAME} } + +# look for existing packages, and propose a new version for the current one +function do_newpkg { + local -a rel_list dev_list sort_list + local pkg_name new_name + local radix ver build + + set -o noglob + if [ -e ${LINKNAME} ]; then + if [ -L ${LINKNAME} ]; then + if [ -d ${LINKNAME}/. ]; then + echo "Error! the link '${LINKNAME}' already exists. Please remove it by manually." + exit 1 + else + rm -f ${LINKNAME} + fi + else + echo "Error! '${LINKNAME}' already exists and is not a link. Please remove it by manually." + exit 1 + fi + fi + + if [ $# -gt 0 ]; then + # the user has specified an explicit version string + new_name=$1 + if [ $# -gt 1 ]; then + pkg_name=$2 + fi + else + # the user has not specified any version string, we'll use the directory + # name. + new_name=$(basename $(pwd)) + fi + + rel_list=( ); dev_list=( ) + + # now we'll have to guess the new package name. + # The build rev part (flx*.*) will be ignored. + # We'll look for existing packages with the exact + # name+version, and if found, use this + the first unused build number. + # If not found, a new package is created with the exact name and flx0.1 + + radix=$(get_pkg_radix $new_name) + ver=$(get_pkg_ver $new_name) + build=$(get_build_num $new_name) + new_name=${radix:-*}-${ver:-*} + + rel_list=( $(find $PKGROOT/ -maxdepth 1 -type d -name ${new_name}\* -printf "%f\n" 2>/dev/null) ) + dev_list=( $(find $DEVROOT/ -maxdepth 1 -type d -name ${new_name}\* -printf "%f\n" 2>/dev/null) ) + sort_list=(${rel_list[*]} ${dev_list[*]}) + + if [ "${sort_list[*]}" ]; then + sort_list=($(IFS=$'\n'; echo "${sort_list[*]%-${BUILDSFX}*([0-9]).+([0-9])*}" | sort -u) ) + sort_list=( $(sortnames ${sort_list[*]}) ) + if [ "${radix/*\\**/}" -a "${ver/*\\**/}" ] && \ + ! (IFS=$'\n';echo "${sort_list[*]}"|grep -q "^$new_name\$"); then + # if the package was properly named, and not already listed, let's + # propose it on last position. + sort_list=( ${sort_list[*]} $new_name ) + fi + # echo "package_list : ${sort_list[*]}" + + # now, we'll present the possible names to the user + if [ ${#sort_list[*]} -gt 1 ]; then + local i=0 + echo; echo ">>> Please select the name of the package to create :";echo + while [ $i -lt ${#sort_list[*]} ]; do + # we'll display an 'R' in front of released names, or a 'D' for dev. + if [ "${rel_list[*]/${sort_list[$i]}/}" != "${rel_list[*]}" ]; then + printf " %5d : [R] %s\n" $[$i+1] ${sort_list[$i]} + else + printf " %5d : [D] %s\n" $[$i+1] ${sort_list[$i]} + fi + i=$[$i+1] + done + + echo + while : ; do + echo -n "Choice [${sort_list[${#sort_list[*]}-1]}]: "; read i + if [ -z "$i" ]; then + new_name=${sort_list[${#sort_list[*]}-1]} + break + elif [ "${i//[0-9]/}" ]; then + # not a plain integer, we'll take it for the new name + new_name=$i + break; + elif [ $i -ge 1 -a $i -le ${#sort_list[*]} ]; then + new_name=${sort_list[$[$i-1]]} + break; + fi + done + else + new_name=${sort_list[0]} + fi + # we'll search for all packages starting with the same name and version + # in both release and dev dirs. Then we'll be able to deduce the latest + # build number used. +# sort_list=( $(find $PKGROOT/ $DEVROOT/ -maxdepth 1 -type d -name ${new_name}-${BUILDSFX}*.\* -printf "%f\n" 2>/dev/null|sort -u) ) + sort_list=( $(find $PKGROOT/ $DEVROOT/ -maxdepth 1 -type d -name ${new_name}-${BUILDSFX}${BUILDVER}.\* -printf "%f\n" 2>/dev/null|sort -u) ) + if [ ${#sort_list[*]} -eq 0 ]; then + # this can happen with new BUILDSFX/BUILDVER + new_name=${new_name}-${BUILDSFX}${BUILDVER}.1 + else + sort_list=( $(sortnames ${sort_list[*]} )) + new_name=${new_name}-$(get_next_build $(get_build_num ${sort_list[${#sort_list[*]}-1]})) + fi + else + if [ -z "${radix/*\\**/}" -o -z "${ver/*\\**/}" ]; then + echo "Error: no existing package matches $new_name, and wildcards" + echo "or incomplete names cannot be part of a real name." + exit 1 + fi + # we keep new_name since it's syntactically correct + new_name=${new_name}-${BUILDSFX}${BUILDVER}.1 + fi + + #echo "new_name: $new_name" + + # if pkg_name is unspecified, we'll use the current directory name to guess + # the source package, else we'll use the explicit name + echo; echo ">>> Please select the package to use as a reference :"; echo + + get_name $pkg_name $new_name %P %D + + if [ -z "$REPLY" ]; then + echo "No reference package found (even default). Please specify one." + exit 1 + fi + + echo "Using '$REPLY'." + + if [ -e "$PKGROOT/$REPLY/build.cfg" ]; then + pkg_name=$PKGROOT/$REPLY + else + pkg_name=$DEVROOT/$REPLY + fi + + # new_name is always relative to DEVROOT + #echo "new_name: $new_name ; old_name: $(basename $pkg_name)" + + # we should verify that new_name/released doesn't exist before extracting + # anything into it, or even that new_name doesn't exist at all. + new_name=$DEVROOT/$new_name + if [ -e $new_name ]; then + echo "Error! new directory $new_name already exists. Refusing to overwrite." + exit 1 + fi + + rm -f ${LINKNAME} && mkdir -p $new_name && ln -s $new_name ${LINKNAME} && \ + tar -C $pkg_name --exclude='compiled/*' --exclude='released.*' -cplf - . | tar -C $new_name -xf - || \ + (rmdir $new_name ; rm -f ${LINKNAME}) + echo "A new package '$(basename $new_name)' has been created as '$new_name', based on '$(basename $pkg_name)'." + echo "The link '${LINKNAME}' now points to it." + echo + if [ $(find $new_name/patches -type f |wc -l) -gt 0 ]; then + echo "*** Warning: there are patches to be applied, use >>>pkg info<<< ***" + echo + fi + set +o noglob + return 0 +} + + function do_edit { - echo "Editing $CFGFILE..." - vi $CFGFILE + echo "Editing $CFGFILE..." + vi $CFGFILE } function do_cat { - cat $CFGFILE + cat $CFGFILE } -function do_patch { - find . -name '*.rej' -o -name '*~' | xargs rm -f +function pre_info { + echo "Information for package '$EXACTPKG' :" + + echo " Package version : $PKGVER (\$PKGVER)" + echo " Distrib version : $DISTVER (\$DISTVER)" + echo -n " Config. file : " + if [ -e $CFGFILE ]; then + echo "$CFGFILE" + else + echo "none found." + fi + echo " Package file : $PKGDIR/compiled/$EXACTPKG-$FLXARCH.$PKGSUFF" + echo -n " Package size : " + if [ -e $PKGDIR/compiled/$EXACTPKG-$FLXARCH.$PKGSUFF ]; then + echo "$(du -b $PKGDIR/compiled/$EXACTPKG-$FLXARCH.$PKGSUFF |cut -f1) bytes." + else + echo "does not exist yet." + fi + [ "$PATCH_LIST" ] && echo " Patches list : $PATCH_LIST" + return 0 +} + +# does only compile, not changing the current config +function do_compile_only { + $FLXMAKE + return $? +} + +# new simplified name for 'config_only', which is deprecated, not changing current scripts. +function do_config { + if declare -f do_config_only >/dev/null 2>&1; then + do_config_only + return $? + else + return 0 + fi +} + +# configures and compiles +function do_compile { + do_config && do_compile_only +} + +# preparatory work for prepack() +function pre_prepack { + if [ "$UID" != "0" -a "$force" != "1" ]; then + echo "You must specify '--force' to install as non-root" + exit 1 + fi + # WARNING! here, we don't use $ROOTDIR because we don't want to risk + # erasing a wrong directory as root ! + [ -d $(pwd)/${INSTNAME} ] && rm -rf $(pwd)/${INSTNAME} + return 0 +} - for i in $PATCH_LIST; do - patch -Np$PATCH_LEVEL < $CFGROOT/$CFGDIR/patches/$i +# some cleanup of an eventual opt directory after prepack() +function post_prepack { + local dir + if [ -d $ROOTDIR/opt ] ; then ( + cd $ROOTDIR/opt + for dir in bin sbin lib ; do + mkdir $dir + find */$dir -type f -perm +111 -exec ln -s ../{} $dir \; -printf "ln -s ../%p $ROOTDIR/opt/$dir\n" done + ) fi + return 0 +} - if [ -z "`find . -name '*.rej'`" ]; then - find . -name '*~' | xargs rm -f - fi +# deletes the current prepack directory. +function do_delpack { + # WARNING! here, we don't use $ROOTDIR because we don't want to risk + # erasing a wrong directory as root ! + [ -d $(pwd)/${INSTNAME} ] && rm -rf $(pwd)/${INSTNAME} + return 0 +} + +# does a full clean +function do_clean { + make distclean || make mrproper || make clean + ( do_delpack ) + return 0 +} + +# applies all the patches to the current sources +# files which match *.rej and *~ will be deleted +function do_patch { + local i + find . -name '*.rej' -o -name '*~' | xargs rm -f + + for i in $PATCH_LIST; do + patch -Np$PATCH_LEVEL < $PKGDIR/patches/$i + done + + if [ -z "$(find . -name '*.rej')" ]; then + find . -name '*~' | xargs rm -f + fi + return 0 } +# reverts all the patches from the current sources +# files which match *.rej and *~ will be deleted function do_unpatch { - UNPATCH_LIST="" + local i + local UNPATCH_LIST="" - find . -name '*.rej' -o -name '*~' | xargs rm -f + find . -name '*.rej' -o -name '*~' | xargs rm -f - for i in $PATCH_LIST; do - UNPATCH_LIST="$i $UNPATCH_LIST" - done + for i in $PATCH_LIST; do + UNPATCH_LIST="$i $UNPATCH_LIST" + done - for i in $UNPATCH_LIST; do - patch -RNp$PATCH_LEVEL < $CFGROOT/$CFGDIR/patches/$i - done + for i in $UNPATCH_LIST; do + patch -RNp$PATCH_LEVEL < $PKGDIR/patches/$i + done - if [ -z "`find . -name '*.rej'`" ]; then - find . -name '*~' | xargs rm -f - fi + if [ -z "$(find . -name '*.rej')" ]; then + find . -name '*~' | xargs rm -f + fi + return 0 +} + +# extracts a binary package into $ROOTDIR, to reflect the state prior to pack(). +function do_unpack { + local FILE=$PKGDIR/compiled/$EXACTPKG-$FLXARCH.$PKGSUFF + mkdir -p $ROOTDIR + cd $ROOTDIR + + echo -n "Extracting $FILE into $ROOTDIR ... " + tar zUxpf $FILE >/dev/null 2>&1 + echo "done." + return 0 +} + +# strips symbols from executables before building the package. +# Abort if ROOTDIR doesn't exist (thus needing prepack() first). +function do_strip { + if [ ! -d $ROOTDIR ] ; then + echo "Error: directory $ROOTDIR doesn't exist. Make sure you dir 'prepack'." + exit 1 + fi + #find $ROOTDIR/. -type f | xargs file | grep ":.*executable.*not stripped" | cut -f1 -d: | xargs strip -x --strip-unneeded -R .note -R .comment > /dev/null 2>&1 + # allow executable and shared (.so), but not relocatable (.o), both stripped or not stripped + find $ROOTDIR/. -type f | xargs file | grep ":.*ELF.*\(executable\|\shared\).*stripped" | cut -f1 -d: | xargs strip -x --strip-unneeded -R .note -R .comment > /dev/null 2>&1 + return 0 +} + +# forces pack() to strip before starting, even if do_pack() is redefined by the user. +function pre_pack { + ( do_strip ) + return 0 } +# this function finds perl dependencies for a given file. +# It's only called from do_pack_files() and do_pack() function get_perl_depend { - filename=$1 - DEP=`grep "^\(.*['{\"]\)*[ ]*\(require\|use\) \+['\"]*[a-zA-Z][a-z:/A-Z0-9-_]*[; '\"]" $filename | \ + local filename=$1 + local dep DEP + local DEP_FILE=$PKGDIR/compiled/$EXACTPKG-$FLXARCH.dep + + DEP=$(grep "^\(.*['{\"]\)*[ ]*\(require\|use\) \+['\"]*[a-zA-Z][a-z:/A-Z0-9-_]*[; '\"]" $filename | \ sed -e 's/.*\(require\|use\) \+["'\'']\?\([^'\''" };]\+\)["'\'']\?/§§\2§§/g' \ -e 's/§§\([^§]\+\)§§[^§]*/ \1/g' | \ - sed 's@::@/@g'` - if [ "x$DEP" != "x" ] ; then - echo -n "$filename" >> $F - for dep in $DEP ; do - if [ "x${dep/*.*}" != "x" ] ; then - echo -n " $dep.pm" >> $F - else - echo -n " $dep" >> $F + sed 's@::@/@g') + if [ "x$DEP" != "x" ] ; then + echo -n "$filename" >> $DEP_FILE + for dep in $DEP ; do + if [ "x${dep/*.*}" != "x" ] ; then + echo -n " $dep.pm" >> $DEP_FILE + else + echo -n " $dep" >> $DEP_FILE fi - done - echo >> $F - fi + done + echo >> $DEP_FILE + fi } -function do_pack { +# same as pack, except that it uses files in the current directory as the root +# entries, and that no strip, link nor compression is performed. +# Only entries listed in the file pointed to by variable FILE_LIST find their +# way to the archive. +# This function relies on get_perl_depend(). +function do_pack_files { + local DEP_FILE FPNAME + + find . -not -type l | xargs touch -m + + # full path name of different files + FPNAME=$PKGDIR/compiled/$EXACTPKG-$FLXARCH + DEP_FILE=$FPNAME.dep + + # FIXME: absurde ? : rm puis cat ! + rm -rf $DEP_FILE + if [ -e $DEP_FILE.diff ] ; then cat $DEP_FILE.diff $DEP_FILE ; fi + + echo -n "Creating $DEP_FILE ... " + touch $DEP_FILE + find . -type f -o -type l | while read ; do + case $REPLY in + *.pm|*.pl|*.ph) + get_perl_depend $REPLY + ;; + */man/man*/*.[0-9n]) + echo "$REPLY \$MAN" >> $DEP_FILE + ;; + */info/*.info|*/info/*.info-[0-9]*) + echo "$REPLY \$INFO" >> $DEP_FILE + ;; + */sbin/*|*/bin/*|*/lib/*|*/libexec/*) + flr="$(file $REPLY)" + case "$flr" in + *\ shell\ *) + echo "$REPLY $(head -1 $REPLY| sed -e 's/^#\! *\([^ ]\+\).*/\1/') \$SHELL">>$DEP_FILE + ;; + *perl\ commands*) + echo "$REPLY $(head -1 $REPLY| sed -e 's/^#\! *\([^ ]\+\).*/\1/') ">>$DEP_FILE + get_perl_depend $REPLY + ;; + *:\ symbolic\ link*) + echo "$REPLY $(echo $flr | cut -f5 -d' ')" >> $DEP_FILE + ;; + *\ ELF\ 32-bit\ LSB*dynamically\ linked*) + echo "$REPLY $(ldd $REPLY 2>/dev/null | grep -v 'statically linked' | awk '{print $1}' | tr '\012' ' ')" >> $DEP_FILE + ;; + *\ ELF\ 32-bit\ LSB*shared\ object*) + echo "$REPLY $(ldd $REPLY 2>/dev/null | grep -v 'statically linked' | awk '{print $1}' | tr '\012' ' ')" >> $DEP_FILE + ;; + esac + ;; + esac + done + echo "done." + + echo -n "Creating $FPNAME.lst ... " + # we try the special case of the '.' entry which is needed to set the root permissions. + # this entry must be set as "." in FILE_LIST. + if grep -q '^.[ ]' $FILE_LIST; then + set -- $(grep '^.[ ]' $FILE_LIST) + owner=${2%%:*} + group=${2##*:} + echo "d $3 $owner $group 0 -------------------------------- 0 ." + fi > $FPNAME.lst + (flx sign --no-depth --ignore-dot $(cut -f1 -d' ' $FILE_LIST|sed -e 's,/$,,') >> $FPNAME.lst) > /dev/null 2>&1 + echo "done." + + echo -n "Creating $FPNAME.$PKGSUFF ... " + + # we want everything, including directories. + cut -f1 -d' ' $FILE_LIST|sed -e 's,/$,,' | tar -T - --no-recursion -cf - | gzip -9 >$FPNAME.$PKGSUFF 2>/dev/null + echo "done." + return 0 +} + + +# packs the prepacked files into a new file located in $DEVROOT. +# any eventual old package is removed. +# this function relies on do_pack_files(), get_perl_depend(), +function do_pack { + local DEP_FILE FPNAME + # use the file list when available if [ "$FILE_LIST" ]; then - do_pack_files - return $? + do_pack_files + return $? fi - if [ ! -d $ROOTDIR ] ; then export ROOTDIR=`pwd` ; fi - cd $ROOTDIR + # FIXME: is this normal ??? + if [ ! -d $ROOTDIR ] ; then export ROOTDIR=$(pwd) ; fi + cd $ROOTDIR ## ( find lib -type l -name "lib*.so*" | xargs rm -f ; \ ## find usr/lib -type l -name "lib*.so*" | xargs rm -f ; \ ## ldconfig -nr . ) > /dev/null 2>&1 - ldconfig -nr . lib usr/lib > /dev/null 2>&1 - find . ! -type l | xargs touch -m - - F=$PKGROOT/$packver.dep - - rm -rf $F - if [ -e $F.diff ] ; then cat $F.diff $F ; fi - - echo -n "Creating $F ... " - touch $F - find . -type f -o -type l | while read ; do - case $REPLY in - *.pm|*.pl|*.ph) - get_perl_depend $REPLY - ;; - */man/man*/*.[0-9n]) - if [ "${REPLY/*gz}" ] ; then - if [ -L $REPLY ] ; then - LINK=`readlink $REPLY` - rm $REPLY - ln -s $LINK.gz $REPLY.gz - else - gzip -f -9 $REPLY - chmod 644 $REPLY.gz - fi - fi - echo "$REPLY \$MAN" >> $F - ;; - */info/*.info|*/info/*.info-[0-9]*) - if [ "${REPLY/*gz}" ] ; then - gzip -f -9 $REPLY - chmod 644 $REPLY.gz - fi - echo "$REPLY \$INFO" >> $F - ;; - */sbin/*|*/bin/*|*/lib/*|*/libexec/*) - flr="`file $REPLY`" - case "$flr" in - *\ shell\ *) - echo "$REPLY `head -1 $REPLY| sed -e 's/^#\! *\([^ ]\+\).*/\1/'` \$SHELL">>$F - ;; - *perl\ commands*) - echo "$REPLY `head -1 $REPLY| sed -e 's/^#\! *\([^ ]\+\).*/\1/'` ">>$F - get_perl_depend $REPLY - ;; - *:\ symbolic\ link*) - echo "$REPLY `echo $flr | cut -f5 -d' '`" >> $F - ;; - *\ ELF\ 32-bit\ LSB*dynamically\ linked*) - echo "$REPLY `ldd $REPLY 2>/dev/null | grep -v 'statically linked' | awk '{print $1}' | tr '\012' ' '`" >> $F - ;; - *\ ELF\ 32-bit\ LSB*shared\ object*) - echo "$REPLY `ldd $REPLY 2>/dev/null | grep -v 'statically linked' | awk '{print $1}' | tr '\012' ' '`" >> $F - ;; - esac - ;; - esac - done - echo "done." - - echo -n "Creating $PKGROOT/$packver.lst ... " - (find . ! -type d -o -empty | cut -c3-| xargs flx sign --ignore-dot --no-depth > $PKGROOT/$packver.lst) > /dev/null 2>&1 - echo "done." - - F=$PKGROOT/$packver.$PKGSUFF - echo -n "Creating $F ... " - # we want everything, and directories only if they're empty. All this without './' - # we shouldn't get an empty line since . should contain at least what we want to tar ! - find . ! -type d -o -empty | cut -c3- | tar -T - -cf - | gzip -9 >$F 2>/dev/null - echo "done." - - if [ -n "$CFGFILE" ]; then - F=$CFGROOT/$CFGDIR/$pack.$CFGSUFF - echo -n "Creating $F ... " - if [ "$F" != "$CFGFILE" ]; then cp -f "$CFGFILE" "$F"; echo "done." ; else echo "up to date."; fi - fi - + ldconfig -nr . lib usr/lib > /dev/null 2>&1 + find . ! -type l | xargs touch -m + + # full path name of different files + FPNAME=$PKGDIR/compiled/$EXACTPKG-$FLXARCH + DEP_FILE=$FPNAME.dep + + # FIXME: absurde ? : rm puis cat ! + rm -rf $DEP_FILE + if [ -e $DEP_FILE.diff ] ; then cat $DEP_FILE.diff $DEP_FILE ; fi + + echo -n "Creating $DEP_FILE ... " + touch $DEP_FILE + find . -type f -o -type l | while read ; do + case $REPLY in + *.pm|*.pl|*.ph) + get_perl_depend $REPLY + ;; + */man/man*/*.[0-9n]) + if [ "${REPLY/*gz}" ] ; then + if [ -L $REPLY ] ; then + LINK=$(readlink $REPLY) + rm $REPLY + ln -s $LINK.gz $REPLY.gz + else + gzip -f -9 $REPLY + chmod 644 $REPLY.gz + fi + fi + echo "$REPLY \$MAN" >> $DEP_FILE + ;; + */info/*.info|*/info/*.info-[0-9]*) + if [ "${REPLY/*gz}" ] ; then + gzip -f -9 $REPLY + chmod 644 $REPLY.gz + fi + echo "$REPLY \$INFO" >> $DEP_FILE + ;; + */sbin/*|*/bin/*|*/lib/*|*/libexec/*) + flr="$(file $REPLY)" + case "$flr" in + *\ shell\ *) + echo "$REPLY $(head -1 $REPLY| sed -e 's/^#\! *\([^ ]\+\).*/\1/') \$SHELL">>$DEP_FILE + ;; + *perl\ commands*) + echo "$REPLY $(head -1 $REPLY| sed -e 's/^#\! *\([^ ]\+\).*/\1/') ">>$DEP_FILE + get_perl_depend $REPLY + ;; + *:\ symbolic\ link*) + echo "$REPLY $(echo $flr | cut -f5 -d' ')" >> $DEP_FILE + ;; + *\ ELF\ 32-bit\ LSB*dynamically\ linked*) + echo "$REPLY $(ldd $REPLY 2>/dev/null | grep -v 'statically linked' | awk '{print $1}' | tr '\012' ' ')" >> $DEP_FILE + ;; + *\ ELF\ 32-bit\ LSB*shared\ object*) + echo "$REPLY $(ldd $REPLY 2>/dev/null | grep -v 'statically linked' | awk '{print $1}' | tr '\012' ' ')" >> $DEP_FILE + ;; + esac + ;; + esac + done + echo "done." + + echo -n "Creating $FPNAME.lst ... " + (find . ! -type d -o -empty | cut -c3-| xargs flx sign --ignore-dot --no-depth > $FPNAME.lst) > /dev/null 2>&1 + echo "done." + + echo -n "Creating $FPNAME.$PKGSUFF ... " + # we want everything, and directories only if they're empty. All this without './' + # we shouldn't get an empty line since . should contain at least what we want to tar ! + find . ! -type d -o -empty | cut -c3- | tar -T - -cf - | gzip -9 >$FPNAME.$PKGSUFF 2>/dev/null + echo "done." + return 0 } -function do_unpack { - mkdir -p $ROOTDIR - cd $ROOTDIR +function usage { + echo "Usage:" + echo " pkg [-options]* <action> [ pkg [ pkg2 ] ]" + echo + echo " pkg newpkg [ new_pkg [ old_pkg ] ]" + echo " ex: pkg newpkg openssl-0.9.6g-${BUILDSFX}${BUILDVER}.1 openssl-0.9.6d-${BUILDSFX}${BUILDVER}.1" + echo " pkg newpkg apache apache-1.3" + echo " pkg newpkg bash" + echo " pkg newpkg gcc gcc-3*${BUILDSFX}*.1" + echo + echo " pkg setpkg [ new_pkg ]" + echo " ex: pkg setpkg openssl-0.9.6g-${BUILDSFX}${BUILDVER}.1" + echo + echo " pkg { info | cat | edit } [ pkg ]" + echo " ex: pkg info" + echo " pkg info bash" + echo " pkg edit modutils-2.4" + echo " pkg cat gzip-1.3" + echo + echo " pkg { compile | config | compile_only | build | prepack }*" + echo " pkg { strip | pack | unpack | delpack | release | clean }*" + echo + echo " pkg { patch | unpatch } [ patch_name ]" + echo + echo " pkg { any_command } [ any_args ]" + echo + echo "User variables are :" + echo "PKGROOT : directory containing released packages <$PKGROOT>" + echo "DEVROOT : directory containing unreleased packages <$DEVROOT>" + echo "ROOTDIR : base directory for package installation (not source), <$ROOTDIR>" + echo "FLXARCH : architecture to use for the package, <$FLXARCH>" + echo "KERNDIR : kernel sources location, if needed, <$KERNDIR>" +# Those two are not user-settable anymore +# echo "CFGFILE : force to use of a .pkg, <$CFGFILE>" +# echo "DISTVER : build version (${BUILDSFX}${BUILDVER}.1)" + exit 1 +} - F=$PKGROOT/$packver.$PKGSUFF - echo -n "Extracting $F into $ROOTDIR ... " - tar zUxpf $F >/dev/null 2>&1 - echo "done." +# displays usage +function do_help { + usage + return 0 } -# same as pack, except that it uses files in the current directory as the root -# entries, and that no strip, link nor compression is performed. -# Only entries listed in the file pointed to by variable FILE_LIST find their -# way to the archive. -function do_pack_files { -## ( find lib -type l -name "lib*.so*" | xargs rm -f ; \ -## find usr/lib -type l -name "lib*.so*" | xargs rm -f ; \ -## ldconfig -nr . ) > /dev/null 2>&1 - find . ! -type l | xargs touch -m - - F=$PKGROOT/$packver.dep - - # absurde ? : rm puis cat ! - rm -rf $F - if [ -e $F.diff ] ; then cat $F.diff $F ; fi - - echo -n "Creating $F ... " - touch $F - find . -type f -o -type l | while read ; do - case $REPLY in - *.pm|*.pl|*.ph) - get_perl_depend $REPLY - ;; - */man/man*/*.[0-9n]) - echo "$REPLY \$MAN" >> $F - ;; - */info/*.info|*/info/*.info-[0-9]*) - echo "$REPLY \$INFO" >> $F - ;; - */sbin/*|*/bin/*|*/lib/*|*/libexec/*) - flr="`file $REPLY`" - case "$flr" in - *\ shell\ *) - echo "$REPLY `head -1 $REPLY| sed -e 's/^#\! *\([^ ]\+\).*/\1/'` \$SHELL">>$F - ;; - *perl\ commands*) - echo "$REPLY `head -1 $REPLY| sed -e 's/^#\! *\([^ ]\+\).*/\1/'` ">>$F - get_perl_depend $REPLY - ;; - *:\ symbolic\ link*) - echo "$REPLY `echo $flr | cut -f5 -d' '`" >> $F - ;; - *\ ELF\ 32-bit\ LSB*dynamically\ linked*) - echo "$REPLY `ldd $REPLY 2>/dev/null | grep -v 'statically linked' | awk '{print $1}' | tr '\012' ' '`" >> $F - ;; - *\ ELF\ 32-bit\ LSB*shared\ object*) - echo "$REPLY `ldd $REPLY 2>/dev/null | grep -v 'statically linked' | awk '{print $1}' | tr '\012' ' '`" >> $F - ;; - esac - ;; - esac - done - echo "done." - - echo -n "Creating $PKGROOT/$packver.lst ... " - # we try the special case of the '.' entry which is needed to set the root permissions. - # this entry must be set as "." in FILE_LIST. - if grep -q '^.[ ]' $FILE_LIST; then - set -- $(grep '^.[ ]' $FILE_LIST) - owner=${2%%:*} - group=${2##*:} - echo "d $3 $owner $group 0 -------------------------------- 0 ." - fi > $PKGROOT/$packver.lst - (flx sign --no-depth --ignore-dot `cut -f1 -d' ' $FILE_LIST|sed -e 's,/$,,'` >> $PKGROOT/$packver.lst) > /dev/null 2>&1 - echo "done." - - F=$PKGROOT/$packver.$PKGSUFF - echo -n "Creating $F ... " - - # we want everything, and directories only if they're empty. All this without './' - # we shouldn't get an empty line since . should contain at least what we want to tar ! - cut -f1 -d' ' $FILE_LIST|sed -e 's,/$,,' | tar -T - --no-recursion -cf - | gzip -9 >$F 2>/dev/null - echo "done." - - if [ -n "$CFGFILE" ]; then - F=$CFGROOT/$CFGDIR/$pack.$CFGSUFF - echo -n "Creating $F ... " - if [ "$F" != "$CFGFILE" ]; then cp -f "$CFGFILE" "$F"; echo "done." ; else echo "up to date."; fi - fi - +function do_release { + echo "#####################################################" + echo "# Release command not implemented yet ! Aborting... #" + echo "#####################################################" + exit 1 + return 0 } -function do_strip { - if [ ! -d $ROOTDIR ] ; then export ROOTDIR=`pwd` ; fi - #find $ROOTDIR/. -type f | xargs file | grep ":.*executable.*not stripped" | cut -f1 -d: | xargs strip -x --strip-unneeded -R .note -R .comment > /dev/null 2>&1 - # allow executable and shared (.so), but not relocatable (.o), both stripped or not stripped - find $ROOTDIR/. -type f | xargs file | grep ":.*ELF.*\(executable\|\shared\).*stripped" | cut -f1 -d: | xargs strip -x --strip-unneeded -R .note -R .comment > /dev/null 2>&1 - return 0 -} +###### +###### here are some functions used only from main +###### -function pre_pack { - ( do_strip ) +function known_cmd { + declare -f pre_$ACTION > /dev/null && { ( pre_$ACTION $* ) || return $?; } + declare -f do_$ACTION > /dev/null && { ( do_$ACTION $* ) || return $?; } + declare -f post_$ACTION > /dev/null && { ( post_$ACTION $* ) || return $?; } } + +###### +###### here is the main entry point +###### + +# scan the command line + +release_only=0 +force=0 +PRINTUSAGE=0 +ARGLIST=( ) +ACTION= +CHAINCMD=1 + +[ $# -eq 0 ] && PRINTUSAGE=1 + +while [ $# -gt 0 ] ; do + case "$1" in + --force ) + force=1 + ;; + --help|-h) + PRINTUSAGE=1 + ;; + --rel|-r*) + release_only=1 + ;; + --) + shift + ARGLIST=(${ARGLIST[*]} $*) + break + ;; + -* ) + PRINTUSAGE=1 + ;; + *) + ARGLIST=(${ARGLIST[*]} "$1") + ;; + esac + shift +done + + +#echo "arglist=${ARGLIST[*]}" + +[ $PRINTUSAGE -gt 0 ] && usage +[ ${#ARGLIST[*]} -lt 1 ] && usage + +# Some actions can be chained, others not. we'll get the longest +# possible chain, and stop once we encounter a non-chainable action + +while [ $CHAINCMD -gt 0 ]; do + set -o noglob + ACTION=${ARGLIST[0]} + + # unset ARGLIST[0] ### doesn't work in scripts with this shitty bash !!! + ARGLIST[0]= ; ARGLIST=( ${ARGLIST[*]} ) # gets expanded with shitty bash ! + + case "$ACTION" in + newpkg) + CHAINCMD=0 + KNOWNCMD=1 + # newpkg is the only command which doesn't start by a package lookup. + ;; + setpkg) + CHAINCMD=0 + KNOWNCMD=1 + get_name $1 %P default + ;; + info|edit|cat) + CHAINCMD=0 + KNOWNCMD=1 + get_name ${ARGLIST[0]} %L %P %D + ;; + patch|unpatch) + CHAINCMD=0 + KNOWNCMD=1 + REPLY=$(basename $(readlink ${LINKNAME}) 2>/dev/null) + # get_name %L + ;; + compile_only|config|config_only|compile|build|prepack|strip|pack|unpack|delpack|release|clean) + KNOWNCMD=1 + REPLY=$(basename $(readlink ${LINKNAME}) 2>/dev/null) + # get_name %L + ;; + *) + CHAINCMD=0 + KNOWNCMD=0 + REPLY=$(basename $(readlink ${LINKNAME}) 2>/dev/null) + # get_name %L + ;; + esac + + set +o noglob + if [ "$ACTION" != "newpkg" ]; then + if [ -z "$REPLY" ]; then + echo "Error: package name not found." + exit 1 + fi + EXACTPKG=$REPLY + + if [ -e "$PKGROOT/$EXACTPKG/build.cfg" ]; then + PKGDIR=$PKGROOT/$EXACTPKG + else + PKGDIR=$DEVROOT/$EXACTPKG + fi + CFGFILE=$PKGDIR/build.cfg + PKGRADIX=$(get_pkg_radix $EXACTPKG) + PKGVER=$(get_pkg_ver $EXACTPKG) + DISTVER=$(get_build_num $EXACTPKG) + ROOTDIR=${ROOTDIR:-$(pwd)/${INSTNAME}} + + # for compatibility with old functions. Not used anywhere outside this script. + packver=$EXACTPKG + pack=$PKGRADIX + + . $CFGFILE + fi + + case "$FLXARCH" in + i686) arch=i686 cpu=i686 basearch=i386 ;; + i486) arch=i486 cpu=i486 basearch=i386 ;; + i386) arch=i386 cpu=i386 basearch=i386 ;; + *) arch=i586 cpu=i686 basearch=i386 ;; + esac + + if [ -z "$FLXMAKE" ]; then + FLXMAKE=make + fi + + export DISTVER PKGRADIX PKGVER FLXMAKE PATCH_LIST FILE_LIST + +# echo "ACTION=$ACTION, KNOWNCMD=$KNOWNCMD, CHAINCMD=$CHAINCMD" +# echo "ARGLIST=${ARGLIST[*]}" + + if [ $KNOWNCMD -gt 0 ]; then + known_cmd ${ARGLIST[*]} || exit 1 + else + if declare -f do_$ACTION >/dev/null; then + ( do_$ACTION ${ARGLIST[*]} ) || exit 1 + fi + fi + + # now, we'll loop only if we were in a chainable action +done + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +exit 99 + +############################################################################################################### +############################################################################################################### +############################################################################################################### +############################################################################################################### + + +DEAD CODE BELOW !!! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + function usage { - echo "Usage: pkg <action>" - echo " action is one of :" - echo " help : display this help." - echo " info : get information on current package." - echo " newpkg : build a more recent .pkg script from an old one." - echo " cat : display last .pkg file." - echo " edit : edit last .pkg file." - echo " patch : apply a list of patches to the directory prior to compile." - echo " unpatch : revert a list of patches to the directory." - echo " compile : do_compile=do_config_only+do_compile_only in .pkg script ($CFGROOT/$CFGDIR)" - echo " prepack : execute do_prepack in .pkg script ($CFGROOT/$CFGDIR)" - echo " strip : strip binaries in temporary directory" - echo " pack : strip binaries, then package into $PKGROOT" - echo " delpack : remove temporary directory" - echo " clean : execute 'make clean' and remove temporary directory." - echo " build : execute clean compile prepack pack." - echo " unpack : extract package into temporary directory" - echo "Variables are :" - echo "CFGROOT : directory for .pkg and patches, <$CFGROOT>" - echo "CFGFILE : force to use of a .pkg, <$CFGFILE>" - echo "PKGROOT : directory for .lst, .tgz and .dep, <$PKGROOT>" - echo "ROOTDIR : base directory for package (not source), <$ROOTDIR>" - echo "FLXARCH : architecture for package name, <$FLXARCH>" - echo "KERNDIR : base directory for package (not source), <$KERNDIR>" - echo "DISTVER : build version (flx.1)" - exit 1 + echo "Usage: pkg <action> [new_pkg [old_pkg]]" + echo " action is one of :" + echo " help : display this help." + echo " info : get information on current package." + echo " newpkg : build a more recent .pkg script from an old one." + echo " cat : display last .pkg file." + echo " edit : edit last .pkg file." + echo " patch : apply a list of patches to the directory prior to compile." + echo " unpatch : revert a list of patches to the directory." + echo " compile : do_compile=do_config_only+do_compile_only in .pkg script ($CFGROOT/$CFGDIR)" + echo " prepack : execute do_prepack in .pkg script ($CFGROOT/$CFGDIR)" + echo " strip : strip binaries in temporary directory" + echo " pack : strip binaries, then package into $PKGROOT" + echo " delpack : remove temporary directory" + echo " clean : execute 'make clean' and remove temporary directory." + echo " build : execute clean compile prepack pack." + echo " unpack : extract package into temporary directory" + echo "Variables are :" + echo "CFGROOT : directory for .pkg and patches, <$CFGROOT>" + echo "CFGFILE : force to use of a .pkg, <$CFGFILE>" + echo "PKGROOT : directory for .lst, .tgz and .dep, <$PKGROOT>" + echo "ROOTDIR : base directory for package (not source), <$ROOTDIR>" + echo "FLXARCH : architecture for package name, <$FLXARCH>" + echo "KERNDIR : base directory for package (not source), <$KERNDIR>" + echo "DISTVER : build version (flx.1)" + exit 1 } -function do_help { - usage -} -function pre_info { - echo "Information for package $pack: " - - echo " Package version : $PKGVER (\$PKGVER)" - echo " Distrib version : $DISTVER (\$DISTVER)" - echo -n " Config. file : " - if [ -e $CFGFILE ]; then - echo "$CFGFILE" - else - echo "none found." - fi - echo " Package file : $PKGROOT/$packver.$PKGSUFF" - echo -n " Package size : " - if [ -e $PKGROOT/$packver.$PKGSUFF ]; then - echo "`du -b $PKGROOT/$packver.$PKGSUFF|cut -f1` bytes." - else - echo "does not exist yet." - fi - if [ "$PATCH_LIST" ]; then - echo " Patches list : $PATCH_LIST" - fi -} -function do_newpkg { - echo "WARNING!!! the 'newpkg' feature is in beta stage !!!" - if [ -n "$CFGFILE" ]; then - F=$CFGROOT/$PKGRADIX-$PKGVER-$DISTVER-pkg/$pack.$CFGSUFF - echo -n "Creating $F ... " - if [ "$F" != "$CFGFILE" ]; then - mkdir -p $CFGROOT/$PKGRADIX-$PKGVER-$DISTVER-pkg && cp -f "$CFGFILE" "$F" && - cp -af $CFGROOT/$CFGDIR/patches $CFGROOT/$PKGRADIX-$PKGVER-$DISTVER-pkg/ >/dev/null 2>&1 - echo "done." - else - echo "up to date." - fi - fi -} -# setting fixed vars -if [ -z "$KERNDIR" ] ; then KERNDIR="/usr/src/linux" ; fi -if [ -z "$CFGROOT" ] ; then CFGROOT="/var/flx-src" ; fi -if [ -z "$PKGROOT" ] ; then PKGROOT="/var/flx-pkg" ; fi -#if [ -z "$DISTVER" ] ; then DISTVER="flx.1" ; fi -if [ "$FLXARCH" = "" ]; then FLXARCH=`uname -m` ; fi -PKGSUFF="tgz" -CFGSUFF="pkg" -exe=`basename $0` -# check for action type -echo $exe | grep -q "^pkg" -if [ $? = 0 -a "$exe" != "pkg" ] ; then - type=`echo $exe | cut -c4-` -else - type=$1 + + + +for ACTION in ${ARGLIST[*]}; do + +# now we will try to identify two packages names : +# - the EXACT one, deduced from command line, then version symlink, then the +# directory name ; this one doesn't have to exist to be correct. +# - the NEAREST one, deduced from the same criterions, with and without +# versions, and based on EXISTING files only. +# The NEAREST one will be used as a source, while the EXACT one will be used as +# a target. When the EXACT one exists, the NEAREST one must obviously be the +# same. + +# EXACTPKG can be specified as an environment variable if needed +[ $NEAREST_IS_SRC -eq 0 ] && [ -z "$EXACTPKG" -a ${#ARGLIST[*]} -gt 0 ] && EXACTPKG=$(basename ${ARGLIST[0]}) +[ -z "$EXACTPKG" -a -L .flxver ] && EXACTPKG=$(readlink .flxver) +[ -z "$EXACTPKG" ] && EXACTPKG=$(basename $(pwd)) + +if [ -z "$(get_pkg_ver $EXACTPKG)" ]; then + TEMP=$(sortnames $CFGROOT/$EXACTPKG-[0-9]* | tail -1) + TEMP=${TEMP:-$(sortnames $CFGROOT/$EXACTPKG.* | tail -1)} + TEMP=${TEMP:-$(sortnames $CFGROOT/$EXACTPKG-* | tail -1)} + TEMP=${TEMP:-$(sortnames $CFGROOT/$EXACTPKG* | tail -1)} +# if [ -z "$TEMP" ]; then +# echo "Cannot find a suitable package for the current directory. Please specify" +# echo "a correct name on the command line." +# usage +# exit 1 +# fi + [ "$TEMP" ] && EXACTPKG=$(basename $TEMP) + [ -z "$(get_pkg_ver $EXACTPKG)" ] && EXACTPKG=$EXACTPKG-0 fi -# look for parameters -if [ "$type" = "$1" -a "${type##-*}" ] ; then shift ; fi -case $1 in - --force ) force=1; shift ;; - --help ) usage ;; - --source) type=source_only ;; - -* ) shift ;; -esac - -if [ "$type" = "" ] ; then - usage ; +if [ -z "$(get_build_num $EXACTPKG)" ]; then + RADIX=$(get_pkg_radix $EXACTPKG) + TEMP=$(sortnames $CFGROOT/$EXACTPKG-* $CFGROOT/$EXACTPKG $CFGROOT/$RADIX | tail -1) + + VER=$(get_pkg_ver $TEMP) + BUILD=$(get_build_num $TEMP) + EXACTPKG=${RADIX}-${VER:-0}-${BUILD:-flx.1} fi -# execute action -if [ "$type" = "find" ] ; then - for i in * ; do - pkgf=`grep "/$i\$" $CFGROOT/$CFGDIR/*.$CFGSUFF | cut -f1 -d: | tr '\012' ' '` - echo "$i: $pkgf" - done -elif [ "$type" != "source_only" ] ; then - ARGV=$* - - # look for package name from directory name - pack=`pwd` - pack=`basename $pack | sed -e 's/[-_][0-9].*$//'` - - # for package - if [ -n "$pack" ] ; then - - packver=`pwd` - packver=`basename $packver` - - if [ -z "$DISTVER" ]; then - if echo $packver | grep -q -- "-flx\." ; then - DISTVER=`echo $packver|sed 's/\(.*-\)\(flx.[0-9]\+\)\(.*\)/\2/'` - fi +NEWPKGRADIX=$(get_pkg_radix $EXACTPKG) +NEWPKGVER=$(get_pkg_ver $EXACTPKG) +NEWDISTVER=$(get_build_num $EXACTPKG) +NEWDISTVER=${NEWDISTVER:-flx.1} +EXACTPKG=$NEWPKGRADIX-$NEWPKGVER-$NEWDISTVER + +trylist=( ) +[ -d "$CFGROOT/$EXACTPKG" -o -f "$CFGROOT/$EXACTPKG.$PKGSUFF" ] && trylist=( ${trylist[*]} $EXACTPKG) +[ ${#ARGLIST[*]} -gt 0 ] && trylist=( ${trylist[*]} $(basename ${ARGLIST[0]})) +[ -L .flxver ] && trylist=( ${trylist[*]} $(readlink .flxver)) +trylist=( ${trylist[*]} $NEWPKGRADIX-$NEWPKGVER ) +trylist=( ${trylist[*]} $NEWPKGRADIX ) +trylist=( ${trylist[*]} $(basename $(pwd))) +trylist=( ${trylist[*]} "default") + +echo trylist=${trylist[*]} + +for NEARESTPKG in ${trylist[*]}; do + if [ -z "$(get_pkg_ver $NEARESTPKG)" ]; then + TEMP=$(sortnames $CFGROOT/$NEARESTPKG-[0-9]* | tail -1) + TEMP=${TEMP:-$(sortnames $CFGROOT/$NEARESTPKG.* | tail -1)} + TEMP=${TEMP:-$(sortnames $CFGROOT/$NEARESTPKG-* | tail -1)} + #TEMP=${TEMP:-$(sortnames $CFGROOT/$NEARESTPKG | tail -1)} + [ "$TEMP" ] && NEARESTPKG=$(basename $TEMP) || continue fi - # source configuration - if [ -z "$ROOTDIR" ] ; then ROOTDIR=`pwd`/.flxdisk ; fi - if [ -n "$CFGFILE" ]; then - CFGDIR=`dirname $CFGFILE` - CFGROOT=`dirname $CFGDIR` - CFGDIR=`basename $CFGDIR` - . $CFGFILE - else - #CFGFILE=`find $CFGROOT/ -name "$pack[-_]*-${DISTVER:-*}-$FLXARCH.$CFGSUFF"|sed -e "s/\.$CFGSUFF\$//"|sort|tail -1` - #CFGFILE=${CFGFILE:-`find $CFGROOT/ -name "$pack[-_]*-${DISTVER:-*}-*.$CFGSUFF"|sed -e "s/\.$CFGSUFF\$//"|sort|tail -1`} - #CFGFILE=${CFGFILE:-`find $CFGROOT/ -name "$pack[-_]*.$CFGSUFF"|sed -e "s/\.$CFGSUFF\$//"|sort|tail -1`} - #CFGFILE=${CFGFILE:-`find $CFGROOT/ -name "$pack.$CFGSUFF"|sed -e "s/\.$CFGSUFF\$//"|sort|tail -1`} - CFGFILE=`find $CFGROOT/ -maxdepth 1 -type d -name "$pack[-_]*-${DISTVER:-*}-pkg"|sed -e "s/-pkg\$//"|sort|tail -1` - CFGFILE=${CFGFILE:-`find $CFGROOT/ -maxdepth 1 -type d -name "$pack[-_]*-pkg"|sed -e "s/-pkg\$//"|sort|tail -1`} - CFGFILE=${CFGFILE:-`find $CFGROOT/ -maxdepth 1 -type f -name "$pack[-_]*-${DISTVER:-*}-pkg.$PKGSUFF"|sed -e "s/-pkg\.$PKGSUFF\$//"|sort|tail -1`} - CFGFILE=${CFGFILE:-`find $CFGROOT/ -maxdepth 1 -type f -name "$pack[-_]*-pkg.$PKGSUFF"|sed -e "s/-pkg\.$PKGSUFF\$//"|sort|tail -1`} - - # to be completed - - if [ -z "$CFGFILE" ]; then - echo "CFGFILE not found. Cannot continue." >&2 - exit 1 - fi - - if [ -d $CFGFILE ]; then - CFGROOT=`dirname $CFGFILE` - CFGDIR=`basename $CFGFILE`-pkg - CFGFILE=$CFGROOT/$CFGDIR/$pack.$CFGSUFF - else - CFGROOT=`dirname $CFGFILE` - CFGDIR=`basename $CFGFILE`-pkg - CFGFILE=$CFGROOT/$CFGDIR/$pack.$CFGSUFF - if [ ! -e $CFGROOT/$CFGDIR ]; then - echo "Opening package $CFGROOT/$CFGDIR.$PKGSUFF into $CFGROOT/$CFGDIR..." - mkdir -p $CFGROOT/$CFGDIR && tar -C $CFGROOT/$CFGDIR -Uxpf $CFGROOT/$CFGDIR.$PKGSUFF - if [ $? != 0 ]; then - echo "There was an error during this operation. You may have to manually clean $CFGROOT/$CFGDIR. Cannot continue !" - exit 1 - else - echo "Done !" - fi - fi - fi - - if [ -e "$CFGFILE" ]; then - . $CFGFILE - else - echo "CFGFILE ($CFGFILE) not found. Cannot continue." >&2 - exit 1 - fi - fi + RADIX=$(get_pkg_radix $NEARESTPKG) + VER=$(get_pkg_ver $NEARESTPKG) + BUILD=$(get_build_num $NEARESTPKG) + NEARESTPKG=${RADIX}${VER:+-$VER}${BUILD:+-$BUILD} + + #### [ "$(get_build_num $NEARESTPKG)" ] && + + [ -d "$CFGROOT/$NEARESTPKG" -o -f "$CFGROOT/$NEARESTPKG.$PKGSUFF" ] && break +echo NEARESTPKG=$NEARESTPKG + + ###TEMP=$(sortnames $CFGROOT/$NEARESTPKG-* | tail -1) + ###[ "$(get_build_num $TEMP)" ] && NEARESTPKG=$(basename $TEMP) && break +done + +RADIX=$(get_pkg_radix $NEARESTPKG) +VER=$(get_pkg_ver $NEARESTPKG) +BUILD=$(get_build_num $NEARESTPKG) +NEARESTPKG=${RADIX}${VER:+-$VER}${BUILD:+-$BUILD} + +echo "EXACTPKG=$EXACTPKG" +echo "NEARESTPKG=$NEARESTPKG" + +# to be removed ## look if there was an argument, in which case we would treat it as a package +# to be removed ## name (either source or destination, depending on the action). These variables +# to be removed ## are set : +# to be removed ## - ARGPKGFULL : full package name with version +# to be removed ## - ARGPKGRADIX : package radix name (without version) +# to be removed ## - ARGPKGVER : package version without -flx* +# to be removed ## - ARGDISTVER : package build version (flx*) +# to be removed # +# to be removed #if [ ${#ARGLIST[*]} -gt 0 ]; then +# to be removed # ARGPKGFULL=$(basename ${ARGLIST[0]}) +# to be removed # ARGPKGRADIX=$(get_pkg_radix $ARGPKGFULL) +# to be removed # ARGPKGVER=$(get_pkg_ver $ARGPKGFULL) +# to be removed # if echo $ARGPKGFULL | grep -q -- "-flx\." ; then +# to be removed # ARGDISTVER=$(get_build_num $ARGPKGFULL) +# to be removed # fi +# to be removed # ARGBASECFG=${ARGBASECFG:-$(sortnames $CFGROOT/$ARGPKGFULL* |tail -1)} +# to be removed # ARGBASECFG=${ARGBASECFG:-$(sortnames $CFGROOT/$ARGPKGRADIX-$ARGPKGVER-* |tail -1)} +# to be removed # ARGBASECFG=${ARGBASECFG:-$(sortnames $CFGROOT/$ARGPKGRADIX-$ARGPKGVER* |tail -1)} +# to be removed # ARGBASECFG=${ARGBASECFG:-$(sortnames $CFGROOT/$ARGPKGRADIX-* |tail -1)} +# to be removed #fi +# to be removed # +# to be removed ## look for package name from the '.flxver' link in current dir, then dir name +# to be removed # +# to be removed #if [ -L .flxver ]; then +# to be removed # PKGFULL=$(readlink .flxver) +# to be removed #else +# to be removed # PKGFULL=$(basename $(pwd)) +# to be removed #fi +# to be removed # +# to be removed #PKGRADIX=$(get_pkg_radix $PKGFULL) +# to be removed #PKGVER=$(get_pkg_ver $PKGFULL) +# to be removed # +# to be removed #if [ -z "$DISTVER" ] && echo $PKGFULL | grep -q -- "-flx\." ; then +# to be removed # DISTVER=$(get_build_num $PKGFULL) +# to be removed #fi +# to be removed # +# to be removed #BASECFG=${BASECFG:-$(sortnames $CFGROOT/$PKGFULL* |tail -1)} +# to be removed #BASECFG=${BASECFG:-$(sortnames $CFGROOT/$PKGRADIX-$PKGVER-* |tail -1)} +# to be removed #BASECFG=${BASECFG:-$(sortnames $CFGROOT/$PKGRADIX-$PKGVER* |tail -1)} +# to be removed #BASECFG=${BASECFG:-$(sortnames $CFGROOT/$PKGRADIX-* |tail -1)} +# to be removed # +# to be removed # +# to be removed # +# to be removed ## now process the destination parameters +# to be removed # +# to be removed #if [ -L .flxver ]; then +# to be removed # NEWPKGFULL=$(readlink .flxver) +# to be removed #else +# to be removed # NEWPKGFULL=$(basename $(pwd)) +# to be removed #fi +# to be removed # +# to be removed #NEWPKGRADIX=$(get_pkg_radix $NEWPKGFULL) +# to be removed #NEWPKGVER=$(get_pkg_ver $NEWPKGFULL) +# to be removed #NEWPKGVER=${NEWPKGVER:-$PKGVER} +# to be removed # +# to be removed #if [ -z "$NEWDISTVER" ] && echo $NEWPKGFULL | grep -q -- "-flx\." ; then +# to be removed # NEWDISTVER=$(get_build_num $NEWPKGFULL) +# to be removed #fi +# to be removed #NEWDISTVER=${NEWDISTVER:-$DISTVER} +# to be removed # +# to be removed ## recompute the new package version +# to be removed #NEWBASECFG=${NEWBASECFG:-$NEWPKGRADIX-$NEWPKGVER-$NEWDISTVER} +# to be removed # + + +# now this is rather simple : for nearly all actions, NEWPKGFULL is used as the +# directory name for the new package. If it cannot be found, all actions except +# info and newpkg will fail. So we have to do a newpkg before using a new dir. + +if [ ! -d "$CFGROOT/$NEARESTPKG" -a ! -f "$CFGROOT/$NEARESTPKG.$PKGSUFF" ]; then + echo "Config directory <$NEARESTPKG> (NEARESTPKG) does not exist, use 'newpkg' first." + exit 1 +fi + +# source configuration +ROOTDIR=${ROOTDIR:-$(pwd)/${INSTNAME}} + + +CURPKG=$NEARESTPKG +PKGRADIX=$(get_pkg_radix $NEARESTPKG) +PKGVER=$(get_pkg_ver $NEARESTPKG) +if echo $NEARESTPKG | grep -q -- "-flx\." ; then + DISTVER=$(get_build_num $NEARESTPKG) + NEARESTPKG=$PKGRADIX-$PKGVER-$DISTVER +else + DISTVER= + NEARESTPKG=$PKGRADIX-$PKGVER +fi + +CFGDIR=$CFGROOT/$CURPKG +CFGFILE=$CFGDIR/$PKGRADIX.$CFGSUFF + +echo "CFGFILE=$CFGFILE, PKGVER=$PKGVER, CFGDIR=$CFGDIR" + +exit 0 + - if [ -z "$DISTVER" ]; then - if echo $CFGFILE | grep -q -- "-flx\." ; then - DISTVER=`echo $CFGFILE|sed 's/\(.*-\)\(flx.[0-9]\+\)\(.*\)/\2/'` - else - DISTVER='flx.1' + +if [ -n "$CFGFILE" ]; then + CFGDIR=$NEWCFGROOT/$NEWBASECFG + . $CFGFILE +else + #CFGFILE=`find $CFGROOT/ -name "$pack[-_]*-${DISTVER:-*}-$FLXARCH.$CFGSUFF"|sed -e "s/\.$CFGSUFF\$//"|sort|tail -1` + #CFGFILE=${CFGFILE:-`find $CFGROOT/ -name "$pack[-_]*-${DISTVER:-*}-*.$CFGSUFF"|sed -e "s/\.$CFGSUFF\$//"|sort|tail -1`} + #CFGFILE=${CFGFILE:-`find $CFGROOT/ -name "$pack[-_]*.$CFGSUFF"|sed -e "s/\.$CFGSUFF\$//"|sort|tail -1`} + #CFGFILE=${CFGFILE:-`find $CFGROOT/ -name "$pack.$CFGSUFF"|sed -e "s/\.$CFGSUFF\$//"|sort|tail -1`} + CFGFILE=`find $CFGROOT/ -maxdepth 1 -type d -name "$pack[-_]*-${DISTVER:-*}-pkg"|sed -e "s/-pkg\$//"|sort|tail -1` + CFGFILE=${CFGFILE:-`find $CFGROOT/ -maxdepth 1 -type d -name "$pack[-_]*-pkg"|sed -e "s/-pkg\$//"|sort|tail -1`} + CFGFILE=${CFGFILE:-`find $CFGROOT/ -maxdepth 1 -type f -name "$pack[-_]*-${DISTVER:-*}-pkg.$PKGSUFF"|sed -e "s/-pkg\.$PKGSUFF\$//"|sort|tail -1`} + CFGFILE=${CFGFILE:-`find $CFGROOT/ -maxdepth 1 -type f -name "$pack[-_]*-pkg.$PKGSUFF"|sed -e "s/-pkg\.$PKGSUFF\$//"|sort|tail -1`} + + # to be completed + + if [ -z "$CFGFILE" ]; then + echo "CFGFILE not found. Cannot continue." >&2 + exit 1 + fi + + if [ -d $CFGFILE ]; then + CFGROOT=`dirname $CFGFILE` + CFGDIR=`basename $CFGFILE`-pkg + CFGFILE=$CFGROOT/$CFGDIR/$pack.$CFGSUFF + else + CFGROOT=`dirname $CFGFILE` + CFGDIR=`basename $CFGFILE`-pkg + CFGFILE=$CFGROOT/$CFGDIR/$pack.$CFGSUFF + if [ ! -e $CFGROOT/$CFGDIR ]; then + echo "Opening package $CFGROOT/$CFGDIR.$PKGSUFF into $CFGROOT/$CFGDIR..." + mkdir -p $CFGROOT/$CFGDIR && tar -C $CFGROOT/$CFGDIR -Uxpf $CFGROOT/$CFGDIR.$PKGSUFF + if [ $? != 0 ]; then + echo "There was an error during this operation. You may have to manually clean $CFGROOT/$CFGDIR. Cannot continue !" + exit 1 + else + echo "Done !" + fi + fi + fi + + if [ -e "$CFGFILE" ]; then + . $CFGFILE + else + echo "CFGFILE ($CFGFILE) not found. Cannot continue." >&2 + exit 1 + fi fi - fi - echo $packver | grep -q -- "-flx\." - if [ $? != 0 ] ; then - packver=$packver-$DISTVER - fi + if [ -z "$DISTVER" ]; then + if echo $CFGFILE | grep -q -- "-flx\." ; then + DISTVER=`echo $CFGFILE|sed 's/\(.*-\)\(flx.[0-9]\+\)\(.*\)/\2/'` + else + DISTVER='flx.1' + fi + fi - echo $packver | grep -q -- "-$FLXARCH\$" - if [ $? != 0 ] ; then packver=$packver-$FLXARCH ; fi - - prefix=${packver%%[._-][0-9]*} - suffix=${packver#$prefix[._-]} - PKGVER=${suffix%-flx*} - PKGRADIX=$prefix - #echo "packver=$packver suffix=$suffix PKGVER=$PKGVER" - if [ -z "$DISTVER" ]; then - DISTVER=${suffix#$PKGVER-} - if [ "$DISTVER" = "$PKGVER" ]; then - DISTVER="flx.1" - else - DISTVER=${DISTVER%-*} - fi - fi + echo $packver | grep -q -- "-flx\." + if [ $? != 0 ] ; then + packver=$packver-$DISTVER + fi - case "$FLXARCH" in - i686) arch=i686 cpu=i686 basearch=i386 ;; - i486) arch=i486 cpu=i486 basearch=i386 ;; - i386) arch=i386 cpu=i386 basearch=i386 ;; - *) arch=i586 cpu=i686 basearch=i386 ;; - esac + echo $packver | grep -q -- "-$FLXARCH\$" + if [ $? != 0 ] ; then packver=$packver-$FLXARCH ; fi + + prefix=${packver%%[._-][0-9]*} + suffix=${packver#$prefix[._-]} + PKGVER=${suffix%-flx*} + PKGRADIX=$prefix + #echo "packver=$packver suffix=$suffix PKGVER=$PKGVER" + if [ -z "$DISTVER" ]; then + DISTVER=${suffix#$PKGVER-} + if [ "$DISTVER" = "$PKGVER" ]; then + DISTVER="flx.1" + else + DISTVER=${DISTVER%-*} + fi + fi - if [ -z "$FLXMAKE" ]; then - FLXMAKE=make - fi + case "$FLXARCH" in + i686) arch=i686 cpu=i686 basearch=i386 ;; + i486) arch=i486 cpu=i486 basearch=i386 ;; + i386) arch=i386 cpu=i386 basearch=i386 ;; + *) arch=i586 cpu=i686 basearch=i386 ;; + esac + + if [ -z "$FLXMAKE" ]; then + FLXMAKE=make + fi - if [ -z "$PATCH_LIST" ]; then - PATCH_LIST=${CFGFILE%%.$CFGSUFF}.diff - if [ ! -e "$PATCH_LIST" ]; then - unset PATCH_LIST + if [ -z "$PATCH_LIST" ]; then + PATCH_LIST=${CFGFILE%%.$CFGSUFF}.diff + if [ ! -e "$PATCH_LIST" ]; then + unset PATCH_LIST + fi fi - fi - export DISTVER PKGRADIX PKGVER FLXMAKE PATCH_LIST FILE_LIST + export DISTVER PKGRADIX PKGVER FLXMAKE PATCH_LIST FILE_LIST - if declare -f pre_$type > /dev/null ; then ( pre_$type ) ; fi - if [ $? != 0 ] ; then exit ; fi - if declare -f do_$type > /dev/null ; then ( do_$type ) ; fi - if [ $? != 0 ] ; then exit ; fi - if declare -f post_$type > /dev/null ; then ( post_$type ) ; fi - - fi - # done + declare -f pre_$ACTION > /dev/null && ( pre_$ACTION ) + [ $? != 0 ] && exit $? + declare -f do_$ACTION > /dev/null && ( do_$ACTION ) + [ $? != 0 ] && exit $? + declare -f post_$ACTION > /dev/null && ( post_$ACTION ) + [ $? != 0 ] && exit $? + fi fi |