aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilly Tarreau <w@1wt.eu>2006-07-16 14:53:35 +0200
committerWilly Tarreau <willy@wtap.(none)>2006-07-26 11:51:24 +0200
commit0781bb99431d00e7001e84245499190eb4ed05ed (patch)
tree2bbdab3eb3a78b3b8b4cb1c401614b19549d9e56
parent[RELEASE] flxutils-0.1.19 (diff)
downloadflxutils-0781bb99431d00e7001e84245499190eb4ed05ed.tar.gz
[RELEASE] flxutils-0.1.20v0.1.20
-rw-r--r--ChangeLog4
-rw-r--r--init/README.2~56
-rw-r--r--init/init.c~1746
-rwxr-xr-xscripts/pkg6
4 files changed, 7 insertions, 1805 deletions
diff --git a/ChangeLog b/ChangeLog
index aeced60..883dc3d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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