diff options
author | Willy Tarreau <w@1wt.eu> | 2006-07-16 14:53:35 +0200 |
---|---|---|
committer | Willy Tarreau <willy@wtap.(none)> | 2006-07-26 11:51:24 +0200 |
commit | 0781bb99431d00e7001e84245499190eb4ed05ed (patch) | |
tree | 2bbdab3eb3a78b3b8b4cb1c401614b19549d9e56 | |
parent | [RELEASE] flxutils-0.1.19 (diff) | |
download | flxutils-0781bb99431d00e7001e84245499190eb4ed05ed.tar.xz |
[RELEASE] flxutils-0.1.20v0.1.20
Diffstat (limited to '')
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | init/README.2~ | 56 | ||||
-rw-r--r-- | init/init.c~ | 1746 | ||||
-rwxr-xr-x | scripts/pkg | 6 |
4 files changed, 7 insertions, 1805 deletions
@@ -33,3 +33,7 @@ .tgz, .lst, and .dep ; do_config & do_compile_only done in sub-shells ; automatic permissions on /etc/profile.d/*. Better handling of symlinks. - release 0.1.19 + +2003/10/26 + - fixes to pkg (0.3.17) + - release 0.1.20 diff --git a/init/README.2~ b/init/README.2~ deleted file mode 100644 index 03ce196..0000000 --- a/init/README.2~ +++ /dev/null @@ -1,56 +0,0 @@ -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()) - - /path/prog args : idem. - - 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/init.c~ b/init/init.c~ deleted file mode 100644 index 3f6b45f..0000000 --- a/init/init.c~ +++ /dev/null @@ -1,1746 +0,0 @@ -/* - WARNING ! THIS CODE IS OPTIMIZED FOR SIZE WITH COMPILED-IN ARGUMENTS. IT IS - SUBJECT TO BUFFER OVERFLOWS SO DON'T USE IT WITH RUNTIME ARGUMENTS !!! -*/ - -/* TODO : - - make the config buffer bigger - - a few security checks (buffer overflows...) - - cleanup the code a bit -*/ - -/* - preinit - new try on 2002/04/20 - Willy Tarreau <willy AT meta-x.org> - - usage : /sbin/preinit [ \< config_file ] [ { init args | "rebuild" } ] - - Note : the "\< config_file" is to be used within configuration files : - #!/sbin/preinit < - .... - Thus, when you pass "init=/.preinit", the kernel executes : - /sbin/preinit < /.preinit - - The '<' character has been chosen for its rareness. - - the "rebuild" argument make the tool only rebuild a complete /dev - tree from the informations contained in the .preinit file, and then - exit. It does this even if the pid is not 1, but doesn't execute nor - mount anything. Only mkdir, links, blocks, chars and fifo devices are - created. Very useful before a lilo : - - # chroot /mnt/disk /.preinit rebuild - # lilo -r /mnt/disk - # umount /mnt/disk/dev - - If /dev/console is found under /dev, it will not be rebuilt. - - **** needs to rework the doc a bit since it's not up-to-date. **** - - This code tries to build a few filesystem squeleton so that init has enough - to work correctly : - - mount -t proc /proc /proc - - mount -t tmpfs /dev /dev - - get information from a file : /.preinit which describes what to mount, - what ramdisks, links and dirs to make : - -ln L source dest - make a symlink from <source> to <dest> -md D path [ mode ] - create a directory named <path> with the mode <mode>. If mode is left - undefined, 0755 is assumed. -mt M blkdev[(major:minor)] path fstype [ { ro | rw } [ flags ] ] - if <major:minor> is specified, create a block device <blkdev> - with <major> and <minor> and mode 0600. - mount <blkdev> under <path> with type <fstype>, read-only, except if - rw is specified, and args <flags>. -in I path - set the next init program to <path> -ex E cmd [ args ]* - execute <cmd> with args <args> and wait for its completion. -rx R dir cmd [ args ]* - chroot to <dir>, execute <cmd> with args <args> and wait for its completion. -bl B mode uid gid major minor naming_rule - create a set of block devices -ch C mode uid gid major minor naming_rule - create a set of char devices -fi F mode uid gid name - create a fifo -ma U mode - change umask -pr P <new_root> <put_old_relative> - pivot root : old root is displaced into new_root/put_old_relative, and - new_root is displaced under /. -mv K <old_dir> <new_dir> - keep directory <old_dir> after a pivot, then unmount it from old_dir. - usefull for /dev, /proc, /var ... -um O <old_dir> - umount <old_dir> after a pivot for example. -lo l </dev/loopX> <file> - losetup /dev/loopX file. - # anything - comment. - - The devices naming rules consist in strings mixed with numbering rules delimited with - brackets. Each numbering rule has 4 comma-separated fields : - - type of this string portion : 'c' for a single char, 'i' for an int, 'I' for an int - for which 0 is not printed, 'h' for an hex digit - - the range : - - chars: any concatenation of character ranges separated with a dash '-': 'a-fk-npq' - - ints : either an int or a range composed of 2 ints separated with a dash : '1-16' - - hex : same as int, but with hex digits (case insensitive) - - the scale : how much to add to the minor device for each step in the range. - - The commands may be prefixed with a '|' or '&', in which case, they will be - executed only if the previous command failed (|) or succeeded (&). - - Example : - ln hda3 /dev/disk => symlinks /dev/disk to hda3 - md /var/tmp 1777 => creates a directory /var/tmp with mode 1777 - mt /dev/hda1 /boot ext2 => attempts to mount /dev/hda1 read-only under /boot. - |mt /dev/hda1(3:1) /boot ext2 => only if the previous command failed, creates /dev/hda1 with major 3, minor 1 and mounts it under /boot - in /sbin/init-std => the following init will be this /sbin/init-std (31 chars max) - ex /sbin/initramdisk /dev/ram6 1200 => executes /sbin/initramdisk with these args and waits for its completion - bl 0600 0 0 3 1 hd[c,ab,64][i,1-16,1] => makes all hdaX and hdbX with X ranging from 1 to 16 - ch 0600 0 5 2 0 pty[c,p-za-f,16][h,0-f,1] => makes all 256 pty* - #comment => ignore this line - - For executable reduction reasons, the .preinit file is limited to 4 kB. - - The choice of the init program is quite complex, because we want to avoid - stupid loops and buggy behaviours while conservating quite a parametrable - init. Basically, we'll use environment variables that we will destroy once - read, to avoid getting them again if we loop on ourselves (imagine an - 'exec /sbin/init" from a shell cmd line, which will blindly re-exec a shell). - So there are two distinct cases (init and linuxrc) : - - 1) linuxrc - We want to be able to either return or transfer execution to the real init. - - - if we find "init2=xxxx" in the env, we memorize it and move it away from the env. - - if "in xxxx" has been specified on a keyboard input from an "rd" - statement, we unconditionnaly do an execve("xxx", "xxx", ##no args##, ##envp##). - - if the env contained "init2=xxxx", we do an execve("xxxx", "xxxx", ##no args##, ##envp##). - we don't pass the args because it is a rescue init, such as a shell, and - we don't want it to fail on "bash: auto: command not found" or similar. - - if the conf contained "in xxxx", we do an execve("xxxx", "xxxx", argv[], ##envp##) - because we want it to know about the original args. Eg: init=/linuxrc single - - if the conf didn't contain "in xxxx", we unmount all what we can and - return. The kernel will be able to switch over to the next init stage. - - 2) init, or anything else (telinit, ...) - We want to transfer execution to the real init. - - - if we find "INIT=xxxx" in the env, we memorize it and move it away from the env. - - if "in xxxx" has been specified on a keyboard input from an "rd" - statement, we unconditionnaly do an execve("xxx", "xxx", ##no args##, ##envp##). - - if the env contained "INIT=xxxx", we do an execve("xxxx", "xxxx", ##no args##, ##envp##). - we don't pass the args because it is a rescue init, such as a shell, and - we don't want it to fail on "bash: auto: command not found" or similar. - - if the conf contained "in xxxx", we do an execve("xxxx", "xxxx", argv[], ##envp##) - because we want it to know about the original args. Eg: init=/.preinit single - - if the conf didn't contain "in xxxx", we transfer execution to "/sbin/init-sysv". - - Note: basically, each time an environment variable is read, it must be killed afterwards. - Eg: init2=, INIT=, ... - - - The root directory should contain the following dirs : - - /var (directory) -> can be a ramfs or a real dir on another device - - /var/tmp (directory) -> idem - - /tmp (directory) -> idem - - /etc (directory or symlink) -> several possibilities : - - directory on the root fs (preferably) - - directory on another fs - - ramfs (or ramdisk) and directory extracted from other source - - symlink to /boot/etc (in this case, /boot/etc must be a populated directory) - /etc will already have several symlinks - - /boot (mandatory directory) contains the following : - - [kernel version] (directory) with vmlinuz, System.map, config and - the tree behind /lib/modules/[version] - - current (symlink to kernel version) - - vmlinuz (symlink to current/vmlinuz) - - System.map (symlink to current/System.map) - - config (symlink to current/config) - - eventually initrd (symlink to current/initrd) - - modules.dep (symlink to current/modules.dep) - - modules.pcimap (symlink to current/modules.pcimap) - - /boot *may* contain the following : - - etc (populated directory) - - bootfstab (if /etc and /boot/etc empty or non-existant) - - This helps in making /lib/modules : it will simply be a symlink to - /boot/current which will contain all modules. - - -wrong for now: - /tmp will always be linked to fs/var/tmp. - /var will always be linked to fs/var. - /fs must contain a description file for it (what to mount where, what to - initialize) so that init has a working filesystem hierarchy and fstab works. - /fs should be FAT-compatible, at least for its root structure. -*/ - -#include <stdio.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <fcntl.h> -#include <unistd.h> -#include <string.h> -#include <ctype.h> -#include <sys/mount.h> -#include <stdlib.h> -#include <sys/ioctl.h> -#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; - while (*p) - p++; - write(0, c, p-c); -} -#else -#define print(a,...) do{}while(0) -#endif - -//#define ATOL(x) atol(x) -#define ATOL(x) my_atoul(x) - -typedef unsigned char uchar; - - -/* 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))) dev_options[] = "size=0,nr_inodes=4096,mode=755"; -static const char __attribute__ ((__section__(STR_SECT),__aligned__(1))) str__linuxrc[] = "/linuxrc"; -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 -#define MAX_DEVNAME_LEN 64 -#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; - union { - struct { - char *set; - char *ptr; - char value; /* value to be printed */ - uchar index; /* index in the set */ - } chr; - struct { - uchar low; - uchar high; - uchar value; - } num; - } u; - uchar scale; -}; - -enum { - TOK_LN = 0, /* ln : make a symlink */ - TOK_MD, /* md : mkdir */ - TOK_MT, /* mt : mount */ - TOK_IN, /* in : set init program */ - TOK_EX, /* ex : execute */ - TOK_RX, /* rx : execute under chroot */ - TOK_BL, /* bl : make block devices */ - TOK_CH, /* ch : make char devices */ - TOK_FI, /* fi : make a fifo */ - TOK_MA, /* ma : set umask */ - TOK_PR, /* pr : pivot root */ - 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 = 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 __attribute__ ((__section__(STR_SECT),__aligned__(1))) struct { - char lcmd[2]; /* long form */ - char scmd; /* short form */ - char minargs; /* min #args */ -} tokens[NB_TOKENS] = { - "ln", 'L', 2, /* TOK_LN */ - "md", 'D', 1, /* TOK_MD */ - "mt", 'M', 3, /* TOK_MT */ - "in", 'I', 1, /* TOK_IN */ - "ex", 'E', 1, /* TOK_EX */ - "rx", 'R', 2, /* TOK_RX */ - "bl", 'B', 6, /* TOK_BL */ - "ch", 'C', 6, /* TOK_CH */ - "fi", 'F', 4, /* TOK_FI */ - "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; -//static char cmdline[MAX_CMDLINE_LEN]; -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; - unsigned long digit; - - while (*s) { - digit = *s - '0'; - if (digit > 9) - return 0; - res = res * 10 + digit; - s++; - } - return res; -} - -static int streq(const char *str1, const char *str2) { - char c1; - while ((c1 = *str1) && c1 == *str2) { /* the second test ensures that *str2 != 0 */ - str1++; - str2++; - } - return ((c1 | *str2) == 0); -} - -/* - * copies at most <size-1> chars from <src> to <dst>. Last char is always - * set to 0, unless <size> is 0. The number of chars copied is returned - * (excluding the terminating zero). - * This code has been optimized for size and speed : on x86, it's 45 bytes - * long, uses only registers, and consumes only 4 cycles per char. - */ -static inline int my_strlcpy(char *dst, const char *src, int size) { - char *orig = dst; - if (size) { - while (--size && (*dst = *src)) { - src++; dst++; - } - *dst = 0; - } - return dst - orig; -} - -static void reopen_console() { - int i, fd, oldfd; - - oldfd = dup2(0, 3); // keep a valid console on fd 3 - - for (i = 0; i < 3; i++) - close(i); - - fd = open(dev_console, O_RDWR); // fd = 0 (stdin) or -1 (error) - if (fd < 0) - dup(oldfd); // restore 0 from old console - - close(oldfd); - dup(0); // stdout - dup(0); // stderr - - print("init/info : reopened /dev/console\n"); -} - -#if 0 -/* reads the kernel command line </proc/cmdline> into memory and searches - * for the first assignment of the required variable. Return its value - * (which may be empty) or NULL if not found. - */ -char *find_arg(char *arg) { - char *a, *c; - - /* read cmdline the first time */ - if (!*cmdline) { - int fd, len; - - if ((fd = open(proc_cmdline, O_RDONLY)) == -1) - return NULL; - if ((len = read(fd, cmdline, sizeof(cmdline)-1)) == -1) { - close(fd); - return NULL; - } - cmdline[len] = 0; - close(fd); - } - - /* search for the required arg in cmdline */ - c = cmdline; - a = arg; - - while (*c) { - if (*a == 0) { - /* complete match. is it a full word ? */ - if (*c == '=') { - a = ++c; - while ((*a != ' ') && (*a != '\0') && (*a != '\n')) - a++; - *a = 0; - return c; /* return value */ - } - else if (*c == ' ' || *c == '\n' || *c == '\0') { - *c = 0; - return c; /* return pointer to empty string */ - } - else { /* not full word. bad match. */ - c -= (a - arg) - 1; - a = arg; - } - } - if (*c == *a) { - a++; - c++; - } - else { - c -= (a - arg) - 1; - a = arg; - } - } - if (*a == 0) /* complete match at end of string */ - return c; /* pointer to empty string */ - else - return NULL; /* not found */ -} -#endif - -/* - * looks for the last assignment of variable 'var=' in 'envp'. - * the value found is returned (or NULL if not found). - * if 'remove' is not zero, the assignment is removed afterwards. - * eg: init=my_getenv(envp, "init=", 1); - */ -char *my_getenv(char **envp, char *var, const int remove) { - int namelen; - char **last; - - last = NULL; - namelen = strlen(var); - while (*envp != NULL) { - //printf("comparing <%s> against <%s> for %d chars\n", *envp, var, namelen); - if (!strncmp(*envp, var, namelen)) - last = envp; - envp++; - } - //printf("found <%s>\n", (last?*last:"null")); - - if (last == NULL) { - return NULL; - } else { - char *ret = (*last) + namelen; - if (remove) - while (*last != NULL) { - //printf("moving <%s> over <%s>\n", *(last+1),*last); - *last = *(last+1); - last++; - } - //printf("returning <%s>\n", ret); - return ret; - } -} - -/* reads the configuration file <cfg_file> into memory. - * returns 0 if OK, -1 if error. - */ -static inline int read_cfg(char *cfg_file) { - int cfg_fd; - int cfg_size; - - if (cfg_line == NULL) { - if (((cfg_fd = open(cfg_file, O_RDONLY)) == -1) || - ((cfg_size = read(cfg_fd, cfg_data, sizeof(cfg_data) - 1)) == -1)) { - return -1; - } - close(cfg_fd); - cfg_line = cfg_data; - cfg_data[cfg_size] = 0; - } - return 0; -} - -/* reads one line from <cfg_data>. comments are ignored. The command token is - * returned as the result of this function, or TOK_UNK if none matches, or - * 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(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 */ - 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') { - cfg_line++; - } - - /* terminate the line cleanly to avoid further tests */ - while (c = *cfg_line) { - *cfg_line++ = '\0'; - if (c == '\n') - break; - } - - /* update the caller's pointer once for all. */ - *cfg_data = cfg_line; - - /* skip empty lines */ - if (!*p) - continue; - - /* fills the cfg_args[] array with the command itself, followed by all - * args. cfg_args[last+1]=NULL. - * - * We have a particular case here : - * if the line begins with '/', then we return TOK_EX so that it executes - * the command just as it would have done with 'ex' prefixed to the line. - * For this, we insert a fake cfg_args[0], also pointing to the '/', which - * will be matched later. - */ - nbargs = 0; - if (*p == '/') - cfg_args[nbargs++] = p; - - for (; *p && (nbargs < MAX_CFG_ARGS - 1); nbargs++) { - 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 { - backslash = (*p == '\\'); - if (*p == '"') { - memmove(p, p + 1, cfg_line - p - 1); - quote = !quote; - } - else - p++; - } - } while (*p && (backslash || quote || (*p != ' ' && *p != '\t'))); - if (*p) { - *p = 0; - do p++; while (*p == ' ' || *p == '\t'); - } - } - - /* search a matching token for the command : it can either be a single - * char (old language) or a double char (new language). - * - * We have a particular case : - * if the line begins with '/', then we return TOK_EX so that it executes - * the command just as it would have done with 'ex' prefixed to the line. - */ - if (**cfg_args == '/') - return TOK_EX | cond; - - for (token = 0; token < NB_TOKENS; token++) - if ((!cfg_args[0][1] && tokens[token].scmd == cfg_args[0][0]) || - (cfg_args[0][1] && - (tokens[token].lcmd[1] == cfg_args[0][1]) && - (tokens[token].lcmd[0] == cfg_args[0][0]))) - return token | cond; - - return TOK_UNK; - } - return TOK_EOF; -} - -/* 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"); - } - - if (chown(name, uid, gid) == -1) { - error = 1; - print("init/error : chown("); print(name); print(") failed\n"); - } - - return error; -} - -/* breaks a 3-fields, comma-separated string into 3 fields */ -static inline int varstr_break(char *str, char *type, char **set, uchar *scale) { - int state; - char *res[3]; - - for (state = 0; state < 3; state++) { - res[state] = str; - while (*str && *str != ',') - str++; - if (*str) - *str++ = 0; - else if (state < 2) - return 1; - } - - *type = *res[0]; - *set = res[1]; - *scale = ATOL(res[2]); - return 0; -} - -/* reads a range from a string of the form "low-high" or "value". - * Returns 0 if OK, or 1 if error. - */ -static int int_range(char *from, uchar *low, uchar *high) { - char c; - *low = 0; - while ((c = *from) != '\0') { - if (isdigit(c)) - *low = *low * 10 + c - '0'; - else if (c == '-') { - low = high; - *low = 0; - } - else - return 1; - from++; - } - if (low != high) /* high has not been written to */ - *high = *low; - - return 0; -} - -/* reads a range from a hex string of the form "low-high" or "value". - * Returns 0 if OK, or 1 if error. - */ -static int hex_range(char *from, uchar *low, uchar *high) { - uchar c; - *low = 0; - while ((c = *from) != '\0') { - if (c == '-') { - low = high; /* all writes will now be done on <high> */ - *low = 0; - } - else { - if (c >= '0' && c <= '9') - c -= '0'; - else if (c >= 'a' && c <= 'f') - c -= 'a' - 10; - else if (c >= 'A' && c <= 'F') - c -= 'A' - 10; - else - return 1; - - // if (((uchar)(c -= '0') > 9) /* not a digit */ - // && (((uchar)(c -= 'A' - '0' - 10) < 0xa) || ((uchar)c > 0xf)) - // && (((uchar)(c -= 'a' - 'A') < 0xa) || ((uchar)c > 0xf))) - // return 1; - - *low = (*low << 4) + c; - } - from++; - } - if (low != high) /* high has not been written to */ - *high = *low; - - return 0; -} - -static inline char *addcst(char *dest, char *cst) { - while ((*dest++ = *cst++) != '\0'); - return dest - 1; -} - -static inline char *addchr(char *dest, char chr) { - *dest++ = chr; - *dest = '\0'; - return dest; -} - -static char *addint(char *dest, uchar num) { - int div; - char *out = dest; - for (div = (1<<16) + (10<<8) + (100); div > 0;) { - int q, r, d; - d = (unsigned char)div; - q = num / d; r = num % d; - div >>= 8; - if (!div || (out != dest) || q) { - *out++ = q + '0'; - } - num = r; - } - *out = '\0'; - return out; -} - -static char *addhex(char *dest, uchar num) { - uchar c; - if (num > 0x0F) { - c = num >> 4; - *dest++ = (c > 9) ? (c - 10 + 'a') : (c + '0'); - } - c = num & 0x0F; - *dest++ = (c > 9) ? (c - 10 + 'a') : (c + '0'); - *dest = '\0'; - return dest; -} - -/* builds a device name from the current <var> and <cst_str> arrays, - * and compute the corresponding minor number by adding all the relevant - * fields' values - */ -static void name_and_minor(char *name, uchar *minor, int fields) { - uchar min; - int f; - - min = 0; - for (f = 0; f < fields; f++) { - if (*cst_str[f]) - name = addcst(name, cst_str[f]); - switch (var[f].type) { - case 'c' : - name = addchr(name, var[f].u.chr.value); - min += var[f].u.chr.index * var[f].scale; - break; - case 'h' : - name = addhex(name, var[f].u.num.value); - goto recalc_int; - case 'i' : - name = addint(name, var[f].u.num.value); - goto recalc_int; - case 'I' : - if (var[f].u.num.value) - name = addint(name, var[f].u.num.value); - recalc_int: - min += (var[f].u.num.value - var[f].u.num.low) * var[f].scale; - break; - case 0 : - break; - default: - print("init/conf : field type must be c, h, i or I\n"); - } - } - if (minor) - *minor = min; -} - -/* increments the index for variable #f. When it overflows, it goes back to the - * beginning and a carry is returned for the next variable to be incremented. - * 0 is returned if no carry is returned, otherwise, 1 is returned. - */ -static int inc_var_index(int f) { - switch (var[f].type) { - case 'c' : - if ((var[f].u.chr.ptr[1] == '-') && (var[f].u.chr.value < var[f].u.chr.ptr[2])) { - var[f].u.chr.value++; - var[f].u.chr.index++; - return 0; - } else { /* we cannot increment within the current range */ - if (*++var[f].u.chr.ptr == '-') { - if (*++var[f].u.chr.ptr) - var[f].u.chr.ptr++; - } - if (!*var[f].u.chr.ptr) { /* no other range found */ - var[f].u.chr.value = *(var[f].u.chr.ptr = var[f].u.chr.set); - var[f].u.chr.index = 0; - return 1; - } - else { /* found a new range */ - var[f].u.chr.value = *var[f].u.chr.ptr; - var[f].u.chr.index++; - return 0; - } - } - case 'h': - case 'i': - case 'I': - if (var[f].u.num.value == var[f].u.num.high) { - var[f].u.num.value = var[f].u.num.low; - return 1; - } else { - var[f].u.num.value++; - return 0; - } - default: - return 1; /* an empty variable propagates carry */ - } -} - - -/* makes one or several device inodes depending on the rule <rule> */ -static void multidev(mode_t mode, uid_t uid, gid_t gid, uchar major, uchar minor, char *rule) { - char *p1, *p2; - int state; - int i; - - enum { - ST_STRING = 0, - ST_CONST - }; - - int field; /* each field is a couple of a cst string and a var string */ - - p1 = p2 = rule; - state = ST_STRING; - field = 0; - - cst_str[field] = var_str[field] = p2; /* be sure to point to something valid */ - - while (*p2) { - if (state == ST_STRING) { - if (*p2 == '[') { - state = ST_CONST; - cst_str[field] = p1; - *p2++ = 0; - p1 = p2; - } - else - p2++; - } - else if (state == ST_CONST) { - if (*p2 == ']') { - state = ST_STRING; - var_str[field++] = p1; - *p2++ = 0; - p1 = p2; - cst_str[field] = p1; - } - else - p2++; - } - } - - if (state == ST_STRING) { - if (p2 > p1) { - state = ST_CONST; - cst_str[field] = p1; - var_str[field++] = p2; - *p2++ = 0; - } - } - else { - print("var string incomplete\n"); - } - - /* now we must "compile" the variable fields */ - for (i = 0; i < field; i++) { - memset(&var[i], 0, sizeof(var[i])); - if (varstr_break(var_str[i], &var[i].type, &var[i].u.chr.set, &var[i].scale)) { - //print("empty variable field in string <"); print(var_str[i]); print(">\n"); - continue; - } - - switch (var[i].type) { - case 'c': - var[i].u.chr.value = *(var[i].u.chr.ptr = var[i].u.chr.set); - var[i].u.chr.index = 0; - break; - case 'h': - if (hex_range(var[i].u.chr.set, &var[i].u.num.low, &var[i].u.num.high)) { - //printf("error in hex range in <%s>\n", var_str[i]); - print("init/conf : error in hex range\n"); - continue; - } - var[i].u.num.value = var[i].u.num.low; - break; - case 'i': - case 'I': - if (int_range(var[i].u.chr.set, &var[i].u.num.low, &var[i].u.num.high)) { - print("init/conf : error in int range\n"); - //printf("error in int range in <%s>\n", var_str[i]); - continue; - } - var[i].u.num.value = var[i].u.num.low; - break; - default: - // unknown type - break; - } - } - - while (1) { - char name[MAX_DEVNAME_LEN]; - uchar minor_offset; - int f; - - name_and_minor(name, &minor_offset, field); - // printf("name = %s, minor = %d\n", name, minor + minor_offset); - - mknod_chown(mode, uid, gid, major, minor + minor_offset, name); - f = 0; - while (inc_var_index(f) && (f<field)) - f++; - - if (f >= field) - break; - } -} - -/* converts an octal permission mode into the mode_t equivalent */ -static mode_t a2mode(char *ascii) { - mode_t m = 0; - while ((unsigned)(*ascii - '0') < 8) { - m = (m << 3) | (*ascii - '0'); - ascii++; - } - return m; -} - -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]; - - char *conf_init, *force_init; - - /* 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]; - argv[2] = argv[0]; - argv += 2; - argc -= 2; - } - else - cfg_file = linuxrc ? (char *)cfg_linuxrc : (char *)cfg_fname; - - 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"*/; - conf_init = (char *)&sbin_init_sysv; /*"sbin/init-sysv"*/; - force_init = my_getenv(envp, CONST_STR("INIT="), 1); - //printf("force_init=<%s>, INIT_new=%p\n", my_getenv(envp, "INIT=", 0)); - /* 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 { - conf_init = NULL; - force_init = my_getenv(envp, CONST_STR("init2="), 1); - //*argv = (char *)&sbin_init; /* "sbin/init" */ - //printf("force_init=<%s>, init2_new=%s\n", my_getenv(envp, "init2=", 0)); - } - - if (pid1 || linuxrc) { - setsid(); - } - - 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 || 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"); - else { - int i; - if (chdir(dev_name) == -1) - print("init/error : cannot chdir(/dev)\n"); - - print("init/info: /dev has been mounted.\n"); - for (i = 0; i < sizeof(dev_nodes) / sizeof(dev_nodes[0]); i++) { - mknod_chown(dev_nodes[i].mode, (uid_t)UID_ROOT, (gid_t)dev_nodes[i].gid, - dev_nodes[i].major, dev_nodes[i].minor, (char *)dev_nodes[i].name); - } - symlink(proc_self_fd, fd_dir); - print("init/info: /dev has been rebuilt.\n"); - - chdir(root_dir); - /* if /dev was empty, we may not have had /dev/console, so the - * kernel couldn't bind us to it. So let's attach to it now. - */ - reopen_console(); - } - } 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 */ - - if (stat(dev_root, &statf) == -1) { - print("init/info : /dev/root does not exist. Rebuilding...\n"); - if (stat(root_dir, &statf) == 0) { - if (mknod(dev_root, 0600 | S_IFBLK, statf.st_dev) == -1) { - //error = 1; - print("init/error : mknod(/dev/root) failed\n"); - } - } - else { - print("init/error : cannot stat(/)\n"); - } - } - } - - /* here, the cwd is still "/" */ - if (cfg_ok) { - 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; - - 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"); - continue; - } - - cond = token & TOK_COND; - token &= ~TOK_COND; - - if (cfg_args[tokens[token].minargs] == NULL) { - print("Missing args\n"); - continue; - } - - /* now we can reset the error */ - context[brace_level].error = error; - error = 0; - - 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 | 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"); - - /* 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) { - force_init = cfg_args[1]; - break; - } else { - /* non sense to switch error status when assigning init */ - error = context[brace_level].error; - conf_init = cfg_args[1]; - 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; - } - - /* 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; - - } 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; - } - - /* the second command set is available if pid==1 or if "rebuild" is set */ - switch (token) { - case TOK_MD: - /* D path [ mode ] : make a directory */ - if (mkdir(cfg_args[1], (cfg_args[2] == NULL) ? 0755 : a2mode(cfg_args[2])) == -1) { - error = 1; - print("<D>irectory : mkdir() failed\n"); - } - 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"); - } - goto finish_cmd; - case TOK_BL: - /* B <mode> <uid> <gid> <major> <minor> <naming rule> : build a block device */ - case TOK_CH: - /* C <mode> <uid> <gid> <major> <minor> <naming rule> : build a character device */ - if (chdir(dev_name) == -1) { - print("<B>lock_dev/<C>har_dev : cannot chdir(/dev)\n"); - error = 1; - 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); - goto finish_cmd; - case TOK_FI: - /* F <mode> <uid> <gid> <name> : build a fifo */ - if (chdir(dev_name) == -1) { - print("<F>ifo : cannot chdir(/dev)\n"); - error = 1; - goto finish_cmd; - } - - 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); - goto finish_cmd; - } /* end of switch() */ - - /* 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; - } - - switch (token) { - case TOK_MT: { - /* M dev[(major:minor)] mnt type [ {rw|ro} [ flags ] ]: mount dev on mnt (read-only) */ - char *maj, *min, *end; - char *mntdev; - int mntarg; - - /* if the device name doesn't begin with a slash, look for it - * in /proc/cmdline - */ - mntdev = cfg_args[1]; - // the following code handles "var=/dev/sda2" or "home=/dev/hda1(3:1)" on - // the kernel command line. - //if ((*mntdev != '/') && ((cmdline_arg = find_arg(mntdev)) != NULL)) { - // mntdev = cmdline_arg; - // print("<M>ount : using command line device\n"); - //} - - maj = mntdev; /* handles /dev/xxx(maj:min) */ - while (*maj && *maj != '(') - maj++; - if (*maj) { - int imaj = 0, imin = 0; - dev_t dev; - - *(maj++) = 0; - min = end = maj; - while (*min && *min != ':') - min++; - - if (*min) { - *(min++) = 0; - end = min; - } - - while (*end && *end != ')') - end++; - - if (*end) - *end = 0; - if (*maj) - imaj = ATOL(maj); - if (*min) - imin = ATOL(min); - dev = makedev(imaj, imin); - if (mknod(mntdev, S_IFBLK|0600, dev) == -1) { /* makes the node as required */ - error = 1; - print("<M>ount : mknod() failed\n"); - } - } - - mntarg = MS_RDONLY; - 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; - } - else { - print("<M>ount : 'rw' flag not found, mounting read only\n"); - } - - if (mount(mntdev, cfg_args[2], cfg_args[3], MS_MGC_VAL | mntarg, cfg_args[5]) == -1) { - error = 1; - print("<M>ount : error during mount()\n"); - } - - break; - } - case TOK_EX: - /* E cmd [cfg_args] : execute cmd with cfg_args, chrooted to dir */ - /* fall through TOK_RX */ - case TOK_RX: { - /* R dir cmd [cfg_args] : execute cmd with cfg_args, chrooted to dir */ - char **exec_args, *exec_dir; - int res; - - exec_args = cfg_args + 1; - if (token == TOK_EX) { - exec_dir = (char *)root_dir; - } - else { - exec_dir = cfg_args[1]; - exec_args++; - } - - res = fork(); - if (res == 0) { - chroot(exec_dir); - execve(exec_args[0], exec_args, envp); - print("<E>xec(child) : execve() failed\n"); - return 1; - } - else if (res > 0) { - int ret; - print("<E>xec(parent) : waiting for termination\n"); - while (((ret = wait(&error)) != -1) && (ret != res)) - print("<E>xec(parent) : signal received\n"); - - error = (ret == -1) || ((WIFEXITED(error) > 0) ? WEXITSTATUS(error) : 1); - print("<E>xec(parent) : child exited\n"); - } - else { - print("<E>xec : fork() failed\n"); - error = 1; - } - break; - } - case TOK_MA: - /* U <umask> : change umask */ - umask(a2mode(cfg_args[1])); - break; - case TOK_PR: - /* P <new_root> <put_old_relative> : pivot root */ - if (chdir(cfg_args[1]) == -1) { - error = 1; - print("<P>ivot : error during chdir(new root)\n"); - } - - if (pivot_root(/*CONST_STR(".")*/cur_dir, cfg_args[2]) == -1) { - error = 1; - print("<P>ivot : error during pivot_root()\n"); - } - - chroot(cur_dir/*CONST_STR(".")*/); - if (chdir(root_dir) == -1) { - error = 1; - print("<P>ivot : error during chdir(/)\n"); - } - - /* replace stdin/stdout/stderr with newer ones */ - reopen_console(); - break; - case TOK_MV: - /* 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("<bi> : error during mount|bind\n"); - } - 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 (umount2(cfg_args[1], MNT_DETACH) == -1) { - error = 1; - print("<um> : error during umount\n"); - } - break; - case TOK_LO: { - /* l </dev/loopX> <file> : losetup /dev/loopX file */ - struct loop_info loopinfo; - int lfd, ffd; - - if ((lfd = open (cfg_args[1], O_RDONLY)) < 0) { - error = 1; - print("(l)osetup : error opening loop device\n"); - break; - } - if ((ffd = open (cfg_args[2], O_RDONLY)) < 0) { - error = 1; - print("(l)osetup : error opening image\n"); - goto losetup_close_all; - } - memset(&loopinfo, 0, sizeof (loopinfo)); - my_strlcpy(loopinfo.lo_name, cfg_args[2], LO_NAME_SIZE); - if (ioctl(lfd, LOOP_SET_FD, ffd) < 0) { - error = 1; - print("(l)osetup : error during LOOP_SET_FD\n"); - goto losetup_close_all; - } - if (ioctl(lfd, LOOP_SET_STATUS, &loopinfo) < 0) { - error = 1; - ioctl(lfd, LOOP_CLR_FD, 0); - print("(l)osetup : error during LOOP_SET_STATUS\n"); - goto losetup_close_all; - } - losetup_close_all: - close (lfd); close (ffd); - break; - } - default: - print("unknown cmd in /.preinit\n"); - break; - } - 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 - * - mount /var as tmpfs if it's empty and /tmp is a symlink - */ - if (mount(proc_dir, proc_dir, proc_fs, MS_MGC_VAL, NULL) == -1) - print("init/err: cannot mount /proc.\n"); - else - print("init/info: /proc mounted RW.\n"); - - /* we'll see if we want to build /var */ - if ((stat(var_tmp, &statf) == -1) && /* no /var/tmp */ - (stat(tmp_name, &statf) == 0) && S_ISLNK(statf.st_mode)) { /* and /tmp is a symlink */ - print("init/info: building /var.\n"); - if (mount(var_dir, var_dir, tmpfs_fs, MS_MGC_VAL, NULL) == -1) - print("init/err: cannot mount /var.\n"); - else { - int i; - print("init/info: /var has been mounted.\n"); - mkdir(var_dir, 0755); - mkdir(var_tmp, 01777); - mkdir(var_run, 0755); - print("init/info: /var has been built.\n"); - } - } - } - 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; - } - - - /* 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 (force_init != NULL) { - /* we keep the cmdline args if we take it from the kernel cmdline, - * but we flush any args if it comes from the keyboard - */ - argv[0] = force_init; - if (cmd_input == INPUT_KBD) - argv[1] = NULL; - } else { - /* standard conf or new linuxrc : !NULL = chained init */ - /* old linuxrc : NULL = no chained init */ - argv[0] = conf_init; - } - - if (linuxrc && force_init == NULL) { - /* normal linuxrc : we close and unmount all what we have done, but not - * in case of forced init, because if we force, it should mean that we - * want a prompt or something special. - */ - close(2); close(1); close(0); - umount2(dev_name, MNT_DETACH); - } - -#if 0 - - 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")); - //cmdline_arg = my_getenv(envp, CONST_STR("init2="), 1); - } else { - /* handle the lilo command line "INIT=prog" */ - //cmdline_arg = find_arg(CONST_STR("INIT")); - cmdline_arg = my_getenv(envp, CONST_STR("INIT="), 1); - } - - if (cmdline_arg != NULL) { - argv[0] = cmdline_arg; - argv[1] = NULL; - } - } - - print("init/debug: *argv = "); print (*argv); print("\n"); -#endif - - umask(old_umask); -#ifdef SLOW_DEBUG - sleep(10); -#endif - /* the old linuxrc behaviour doesn't exec on exit. */ - if (*argv != NULL) { - err = execve(*argv, argv, envp); - print("init/error : last execve() failed\n"); - - /* we'll get a panic there, so let some time for the user to read messages */ - if (pid1) - sleep(60); - return err; - } - return 0; -} diff --git a/scripts/pkg b/scripts/pkg index ae0d6f7..9889ed2 100755 --- a/scripts/pkg +++ b/scripts/pkg @@ -1,6 +1,6 @@ #!/bin/bash -# pkg - Formilux package builder - version 0.3.16 - 2003-10-02 +# pkg - Formilux package builder - version 0.3.17 - 2003-10-12 # # Copyright (C) 2001-2003 Benoit Dolez & Willy Tarreau # mailto: benoit@ant-computing.com,willy@ant-computing.com @@ -636,7 +636,7 @@ function do_newpkg { fi rm -f ${LINKNAME} && mkdir -p $new_name && ln -s $new_name ${LINKNAME} && \ - tar -C $pkg_name --exclude='compiled/*' --exclude='released.*' --exclude='./pkg.*' \ + tar -C $pkg_name --exclude='./compiled/*' --exclude='./released.*' --exclude='./pkg.*' \ --exclude='./CFLAGS' --exclude='./.dep' --exclude='./.lst' --exclude='./.tgz' \ -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)'." @@ -983,7 +983,7 @@ function do_pack { ## ldconfig -nr . ) > /dev/null 2>&1 echo -n "Updating libraries ... " - ldconfig -nr . lib usr/lib > /dev/null 2>&1 + ldconfig -nr . lib usr/lib opt/*/lib > /dev/null 2>&1 echo "done." echo -n "Updating timestamps ... " |