Hello,I have digged up the archives of LeafOS lists and extracted RPM instructions and spec files from them. Spec files up to and including Chapter 6 bash are attached (slightly modified).
Dan: sorry for ignoring your superior work.Differences from the book: the toolchain adjustment method is from DIY next-generation build, the /usr/{man,info,doc} directories are removed.
Bugs:1) I don't split away -devel packages and binaries. This split is absolutely required for doing library transitions (such as changing over from libfoo.so.1 to libfoo.so.2) smoothly, because otherwise the two packages with different versions of the library cannot be installed simultaneously (they provide the same headers, and RPM doesn't allow one file to belong to two different packages). However, I expect disagreement among editors about the best way to split packages.
2) RPM-specific variables such as %{optflags} are ignored, because they are incompatible with the concept of making instructions for several package managers from the same XML source, proposed by Jeremy Huntwork.
3) The unpacking-and-patching part (%setup) is still in a state when we can't easily generate it.
4) Upstream RPM bugs noticed in LeafOS (namely: not stripping shared libraries by default; wrong check for "file" output that leads to non-stripping setuid ELF binaries; missing "exit 0" at the end of the brp-nobuildrootpath script) are not fixed.
5) The list of installed files should not be just "/*".6) Configuration files should come together with packages (as done in my spec files with readline and not done with bash).
Features: the --force switch is never used. Instructions:Manually follow the Chapter 5 of the regular LFS book (well, I deviated and used the next-generation toolchain instructions from DIY but that shouldn't matter), with the following changes:
a) When building bash, apply the attached bash-requires.patch (from Fedora). It adds the --rpm-requires option that is used by RPM to find out the dependencies of post-installation and pre-removal scripts.
b) When building gettext, instead of "make -C src msgfmt", do "make -C src msgfmt xgettext", and, accordingly, instead of "cp -v src/msgfmt /tools/bin", do "cp -v src/{msgfmt,xgettext} /tools/bin". This is necessary because popt can't be built without xgettext.
In Section "Creating Essential Files and Symlinks", also add the user "build" with uid and gid 98. This is only needed to demonstrate the "build as non-root, create a package as non-root, install the resulting package as root" technique, which is much safer than the "build as non-root, install as root without packaging" method described in BLFS. Of course, when things go beyond just a proof of concept, the process of changing from root to the user "build" should be replaced with the opposite process, e.g., via sudo.
As the first few steps in Chapter 6, just after "Creating Essential Files and Symlinks", compile a few packages. This has the following advantage as compared to building them at the end of Chapter 5 (i.e., before the chroot): there are absolutely no chances that unwanted dependencies from the host will be picked up.
# m4-1.4.10: beecrypt depends on it at build time # http://www.gnu.org/software/m4/ # http://ftp.gnu.org/gnu/m4/m4-1.4.10.tar.bz2 ./configure --prefix=/tools make make install # beecrypt-4.1.2: rpm depends on it # http://beecrypt.sourceforge.net/ # http://prdownloads.sourceforge.net/beecrypt/beecrypt-4.1.2.tar.gz ./configure --prefix=/tools make make install # popt-1.13: rpm depends on it # http://rpm5.org/ # http://rpm5.org/files/popt/popt-1.13.tar.gz ./configure --prefix=/tools make make install # elfutils-0.131: optional dependency of RPM, provides better tracking # of library dependencies, required for compatibility with third-party # RPMs that list symbol-versioned dependencies such as "libc.so.6(GLIBC_2.4)" # ftp://sourceware.org/pub/systemtap/elfutils/elfutils-0.131.tar.gz ./configure --prefix=/tools --enable-tls # Don't install the whole package--it will overwrite binutils! make -C libelf make -C libelf install # file-4.23: called at runtime by scripts that come with RPM # ftp://ftp.gw.com/mirrors/unix/file/file-4.23.tar.gz ./configure --prefix=/tools make make install # rpm-5.0.2: subject of this mail # Note that there are two different package managers named "RPM". # One is maintained by RedHat and is located at http://www.rpm.org/ # I use a fork by Jeff Johnson, for no particular reason. # The attached spec files are incompatible with RedHat RPM, e.g., # because they use the automatic setting of the BuildRoot variable. # http://rpm5.org/ # http://rpm5.org/files/rpm/rpm-5.0/rpm-5.0.2.tar.gz # goal: install to /tools, kee the database in /var, guess the default macros # in a way suitable for installing packages to /usr ./configure --prefix=/usr --bindir=/tools/bin --libdir=/tools/lib \ --includedir=/tools/include --datarootdir=/tools/share \ --with-path-lib=/tools/lib/rpm --with-path-locale=/tools/share/locale \ --without-perl --without-python --with-bzip2 --with-libelf sed -i 's@/tools/bin/@@' macros sed -i 's@/doc@/share/doc@' macros sed -i 's@/info@/share/info@' macros sed -i 's@/man@/share/man@' macros sed -i 's@/usr/X11R6@/tools@' macros ln -s /tools/share/file/magic /tools/lib/rpm/ make make install # /usr/lib/rpm is hard-coded in several places # but I have missed this fact during my test, # so let's have it commented out for reproducibility of my results # ln -s /tools/lib/rpm /usr/libCopy sources and patches to /usr/src/rpm/SOURCES, and copy specs to /usr/src/rpm/SPECS.
Change the ownership of the build tree: chown -R build:build /usr/src/rpmIn the following instructions, it is assumed that /usr/src/rpm/SPECS is the current directory.
Create and install two fake (empty) packages that work around circular dependencies by (virtually) providing /bin/sh and /usr/bin/perl:
su-tools build -c "rpm --clean -bb fake-bash.spec" rpm -ivh /usr/src/rpm/RPMS/i686/bash-0.0-1.i686.rpm su-tools build -c "rpm --clean -bb fake-perl.spec" rpm -ivh /usr/src/rpm/RPMS/i686/perl-0.0-1.i686.rpm Compile and install packages up to and including glibc: su-tools build -c "rpm --clean -bb linux-headers.spec" rpm -ivh /usr/src/rpm/RPMS/i686/linux-headers-2.6.24-1.i686.rpm su-tools build -c "rpm --clean -bb man-pages.spec" rpm -ivh /usr/src/rpm/RPMS/noarch/man-pages-2.78-1.noarch.rpm su-tools build -c "rpm --clean -bb glibc.spec" rpm -ivh /usr/src/rpm/RPMS/i686/glibc-2.7-1.i686.rpm Adjust the toolchain the way DIY does it: ln -sv /tools/bin/ld-new /usr/bin/ldThe whole procedure of changing the gcc specs is in the spec files of gcc and binutils, so install these two packages:
su-tools build -c "rpm --clean -bb binutils.spec" rpm -ivh /usr/src/rpm/RPMS/i686/binutils-2.18-1.i686.rpm su-tools build -c "rpm --clean -bb gcc.spec" rpm -ivh /usr/src/rpm/RPMS/i686/gcc-4.2.3-1.i686.rpm(sorry, the testsuites are commented out, but in my initial testing, the results were good)
Compile some more packages: su-tools build -c "rpm --clean -bb db.spec" rpm -ivh /usr/src/rpm/RPMS/i686/db-4.6.21-1.i686.rpm su-tools build -c "rpm --clean -bb sed.spec" rpm -ivh /usr/src/rpm/RPMS/i686/sed-4.1.5-1.i686.rpm su-tools build -c "rpm --clean -bb e2fsprogs.spec" rpm -ivh /usr/src/rpm/RPMS/i686/e2fsprogs-1.40.6-1.i686.rpm su-tools build -c "rpm --clean -bb coreutils.spec" rpm -ivh /usr/src/rpm/RPMS/i686/coreutils-6.10-1.i686.rpm su-tools build -c "rpm --clean -bb iana-etc.spec" rpm -ivh /usr/src/rpm/RPMS/noarch/iana-etc-2.20-1.noarch.rpm su-tools build -c "rpm --clean -bb m4.spec" rpm -ivh /usr/src/rpm/RPMS/i686/m4-1.4.10-1.i686.rpm su-tools build -c "rpm --clean -bb bison.spec" rpm -ivh /usr/src/rpm/RPMS/i686/bison-2.3-1.i686.rpm su-tools build -c "rpm --clean -bb ncurses.spec" rpm -ivh /usr/src/rpm/RPMS/i686/ncurses-5.6-1.i686.rpm su-tools build -c "rpm --clean -bb procps.spec" rpm -ivh /usr/src/rpm/RPMS/i686/procps-3.2.7-1.i686.rpm su-tools build -c "rpm --clean -bb libtool.spec" rpm -ivh /usr/src/rpm/RPMS/i686/libtool-1.5.26-1.i686.rpm Compile perl and upgrade from the fake perl package to the real one: su-tools build -c "rpm --clean -bb perl.spec" rpm -Uvh /usr/src/rpm/RPMS/i686/perl-5.8.8-1.i686.rpm Compile some more packages: su-tools build -c "rpm --clean -bb readline.spec" rpm -ivh /usr/src/rpm/RPMS/i686/readline-5.2-1.i686.rpm su-tools build -c "rpm --clean -bb zlib.spec" rpm -ivh /usr/src/rpm/RPMS/i686/zlib-1.2.3-1.i686.rpm su-tools build -c "rpm --clean -bb autoconf.spec" rpm -ivh /usr/src/rpm/RPMS/noarch/autoconf-2.61-1.noarch.rpm su-tools build -c "rpm --clean -bb automake.spec" rpm -ivh /usr/src/rpm/RPMS/noarch/automake-1.10.1-1.noarch.rpm Compile bash and replace the fake package: su-tools build -c "rpm --clean -bb bash.spec" rpm -Uvh /usr/src/rpm/RPMS/i686/bash-3.2-1.i686.rpmI have not written spec files past this point, but, because both fake packages are already removed, I don't expect any problems down the road. Setuid programs in, say, shadow, can be handled by adding %attr statements to the corresponding spec file, so it doesn't even interfere with the "build package as non-root" technique.
-- Alexander E. Patrakov
SPECS.tar.gz
Description: application/gzip
diff -upk.orig bash-3.1.orig/builtins/mkbuiltins.c bash-3.1/builtins/mkbuiltins.c --- bash-3.1.orig/builtins/mkbuiltins.c 2005-09-10 16:22:12 +0000 +++ bash-3.1/builtins/mkbuiltins.c 2006-01-06 00:42:16 +0000 @@ -60,8 +60,13 @@ extern char *strcpy (); #define whitespace(c) (((c) == ' ') || ((c) == '\t')) /* Flag values that builtins can have. */ +/* These flags are for the C code generator, + the C which is produced (./builtin.c) + includes the flags definitions found + in ../builtins.h */ #define BUILTIN_FLAG_SPECIAL 0x01 #define BUILTIN_FLAG_ASSIGNMENT 0x02 +#define BUILTIN_FLAG_REQUIRES 0x04 #define BASE_INDENT 4 @@ -145,9 +150,17 @@ char *assignment_builtins[] = (char *)NULL }; +/* The builtin commands that cause requirements on other files. */ +static char *requires_builtins[] = +{ + ".", "command", "exec", "source", "inlib", + (char *)NULL +}; + /* Forward declarations. */ static int is_special_builtin (); static int is_assignment_builtin (); +static int is_requires_builtin (); #if !defined (HAVE_RENAME) static int rename (); @@ -791,6 +804,8 @@ builtin_handler (self, defs, arg) new->flags |= BUILTIN_FLAG_SPECIAL; if (is_assignment_builtin (name)) new->flags |= BUILTIN_FLAG_ASSIGNMENT; + if (is_requires_builtin (name)) + new->flags |= BUILTIN_FLAG_REQUIRES; array_add ((char *)new, defs->builtins); building_builtin = 1; @@ -1208,10 +1223,11 @@ write_builtins (defs, structfile, extern else fprintf (structfile, "(sh_builtin_func_t *)0x0, "); - fprintf (structfile, "%s%s%s, %s_doc,\n", + fprintf (structfile, "%s%s%s%s, %s_doc,\n", "BUILTIN_ENABLED | STATIC_BUILTIN", (builtin->flags & BUILTIN_FLAG_SPECIAL) ? " | SPECIAL_BUILTIN" : "", (builtin->flags & BUILTIN_FLAG_ASSIGNMENT) ? " | ASSIGNMENT_BUILTIN" : "", + (builtin->flags & BUILTIN_FLAG_REQUIRES) ? " | REQUIRES_BUILTIN" : "", document_name (builtin)); fprintf @@ -1542,6 +1558,13 @@ is_assignment_builtin (name) return (_find_in_table (name, assignment_builtins)); } +static int +is_requires_builtin (name) + char *name; +{ + return (_find_in_table (name, requires_builtins)); +} + #if !defined (HAVE_RENAME) static int rename (from, to) diff -upk.orig bash-3.1.orig/builtins.h bash-3.1/builtins.h --- bash-3.1.orig/builtins.h 2004-12-30 18:59:05 +0000 +++ bash-3.1/builtins.h 2006-01-06 00:42:16 +0000 @@ -40,6 +40,7 @@ #define STATIC_BUILTIN 0x4 /* This builtin is not dynamically loaded. */ #define SPECIAL_BUILTIN 0x8 /* This is a Posix `special' builtin. */ #define ASSIGNMENT_BUILTIN 0x10 /* This builtin takes assignment statements. */ +#define REQUIRES_BUILTIN 0x20 /* This builtin requires other files. */ #define BASE_INDENT 4 diff -upk.orig bash-3.1.orig/doc/bash.1 bash-3.1/doc/bash.1 --- bash-3.1.orig/doc/bash.1 2006-01-06 00:41:57 +0000 +++ bash-3.1/doc/bash.1 2006-01-06 00:42:16 +0000 @@ -231,6 +231,13 @@ The shell becomes restricted (see .B "RESTRICTED SHELL" below). .TP +.B \-\-rpm-requires +Produce the list of files that are required for the +shell script to run. This implies '-n' and is subject +to the same limitations as compile time error checking; +Backticks, [] tests, and evals are not parsed so some +dependencies may be missed. +.TP .B \-\-verbose Equivalent to \fB\-v\fP. .TP diff -upk.orig bash-3.1.orig/doc/bashref.texi bash-3.1/doc/bashref.texi --- bash-3.1.orig/doc/bashref.texi 2006-01-06 00:41:57 +0000 +++ bash-3.1/doc/bashref.texi 2006-01-06 00:42:16 +0000 @@ -4898,6 +4898,13 @@ standard. @xref{Bash POSIX Mode}, for a @item --restricted Make the shell a restricted shell (@pxref{The Restricted Shell}). [EMAIL PROTECTED] --rpm-requires +Produce the list of files that are required for the +shell script to run. This implies '-n' and is subject +to the same limitations as compile time error checking; +Backticks, [] tests, and evals are not parsed so some +dependencies may be missed. + @item --verbose Equivalent to @option{-v}. Print shell input lines as they're read. diff -upk.orig bash-3.1.orig/eval.c bash-3.1/eval.c --- bash-3.1.orig/eval.c 2006-01-06 00:41:57 +0000 +++ bash-3.1/eval.c 2006-01-06 00:42:16 +0000 @@ -53,6 +53,7 @@ extern int last_command_exit_value, stdi extern int need_here_doc; extern int current_command_number, current_command_line_count, line_number; extern int expand_aliases; +extern int rpm_requires; static void send_pwd_to_eterm __P((void)); static sighandler alrm_catcher __P((int)); @@ -131,7 +132,7 @@ reader_loop () if (read_command () == 0) { - if (interactive_shell == 0 && read_but_dont_execute) + if (interactive_shell == 0 && (read_but_dont_execute && !rpm_requires)) { last_command_exit_value = EXECUTION_SUCCESS; dispose_command (global_command); diff -upk.orig bash-3.1.orig/execute_cmd.c bash-3.1/execute_cmd.c --- bash-3.1.orig/execute_cmd.c 2006-01-06 00:41:57 +0000 +++ bash-3.1/execute_cmd.c 2006-01-06 00:42:16 +0000 @@ -473,6 +473,8 @@ async_redirect_stdin () #define DESCRIBE_PID(pid) do { if (interactive) describe_pid (pid); } while (0) +extern int rpm_requires; + /* Execute the command passed in COMMAND, perhaps doing it asynchrounously. COMMAND is exactly what read_command () places into GLOBAL_COMMAND. ASYNCHROUNOUS, if non-zero, says to do this command in the background. @@ -498,7 +500,15 @@ execute_command_internal (command, async volatile int last_pid; volatile int save_line_number; - if (command == 0 || breaking || continuing || read_but_dont_execute) + if (command == 0 || breaking || continuing || (read_but_dont_execute && !rpm_requires)) + return (EXECUTION_SUCCESS); + + if (rpm_requires && command->type == cm_function_def) + return last_command_exit_value = + execute_intern_function (command->value.Function_def->name, + command->value.Function_def->command); + + if (read_but_dont_execute) return (EXECUTION_SUCCESS); run_pending_traps (); @@ -3984,7 +3994,7 @@ execute_intern_function (name, function) if (check_identifier (name, posixly_correct) == 0) { - if (posixly_correct && interactive_shell == 0) + if (posixly_correct && interactive_shell == 0 && rpm_requires == 0) { last_command_exit_value = EX_USAGE; jump_to_top_level (ERREXIT); diff -upk.orig bash-3.1.orig/execute_cmd.h bash-3.1/execute_cmd.h --- bash-3.1.orig/execute_cmd.h 2001-05-07 14:39:37 +0000 +++ bash-3.1/execute_cmd.h 2003-04-20 13:20:49 +0000 @@ -22,6 +22,8 @@ #define _EXECUTE_CMD_H_ #include "stdc.h" +#include "variables.h" +#include "command.h" extern struct fd_bitmap *new_fd_bitmap __P((int)); extern void dispose_fd_bitmap __P((struct fd_bitmap *)); diff -upk.orig bash-3.1.orig/make_cmd.c bash-3.1/make_cmd.c --- bash-3.1.orig/make_cmd.c 2006-01-06 00:41:57 +0000 +++ bash-3.1/make_cmd.c 2006-01-06 00:42:16 +0000 @@ -41,11 +41,15 @@ Foundation, 59 Temple Place, Suite 330, #include "flags.h" #include "make_cmd.h" #include "dispose_cmd.h" +#include "execute_cmd.h" #include "variables.h" #include "subst.h" #include "input.h" #include "ocache.h" #include "externs.h" +#include "builtins.h" + +#include "builtins/common.h" #if defined (JOB_CONTROL) #include "jobs.h" @@ -55,6 +59,10 @@ Foundation, 59 Temple Place, Suite 330, extern int line_number, current_command_line_count; extern int last_command_exit_value; +extern int rpm_requires; + +static char *alphabet_set = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; /* Object caching */ sh_obj_cache_t wdcache = {0, 0, 0}; @@ -784,6 +792,27 @@ make_subshell_command (command) return (make_command (cm_subshell, (SIMPLE_COM *)temp)); } +static void +output_requirement (deptype, filename) +const char *deptype; +char *filename; +{ + if (strchr(filename, '$') || (filename[0] != '/' && strchr(filename, '/'))) + return; + + /* + if the executable is called via variable substitution we can + not dermine what it is at compile time. + + if the executable consists only of characters not in the + alphabet we do not consider it a dependency just an artifact + of shell parsing (ex "exec < ${infile}"). + */ + + if (strpbrk(filename, alphabet_set)) + printf ("%s(%s)\n", deptype, filename); +} + /* Reverse the word list and redirection list in the simple command has just been parsed. It seems simpler to do this here the one time then by any other method that I can think of. */ @@ -801,6 +830,27 @@ clean_simple_command (command) REVERSE_LIST (command->value.Simple->redirects, REDIRECT *); } + if (rpm_requires && command->value.Simple->words) + { + char *cmd0; + char *cmd1; + struct builtin *b; + + cmd0 = command->value.Simple->words->word->word; + b = builtin_address_internal (cmd0, 0); + cmd1 = 0; + if (command->value.Simple->words->next) + cmd1 = command->value.Simple->words->next->word->word; + + if (b) { + if ( (b->flags & REQUIRES_BUILTIN) && cmd1) + output_requirement ("executable", cmd1); + } else { + if (!assignment(cmd0, 0)) + output_requirement (find_function(cmd0) ? "function" : "executable", cmd0); + } + } /*rpm_requires*/ + return (command); } diff -upk.orig bash-3.1.orig/shell.c bash-3.1/shell.c --- bash-3.1.orig/shell.c 2006-01-06 00:41:57 +0000 +++ bash-3.1/shell.c 2006-01-06 00:42:16 +0000 @@ -175,6 +175,9 @@ int running_under_emacs; /* The name of the .(shell)rc file. */ static char *bashrc_file = "~/.bashrc"; +/* Non-zero if we are finding the scripts requirements. */ +int rpm_requires; + /* Non-zero means to act more like the Bourne shell on startup. */ static int act_like_sh; @@ -233,6 +236,7 @@ struct { { "posix", Int, &posixly_correct, (char **)0x0 }, { "protected", Int, &protected_mode, (char **)0x0 }, { "rcfile", Charp, (int *)0x0, &bashrc_file }, + { "rpm-requires", Int, &rpm_requires, (char **)0x0 }, #if defined (RESTRICTED_SHELL) { "restricted", Int, &restricted, (char **)0x0 }, #endif @@ -460,6 +464,12 @@ main (argc, argv, env) if (dump_translatable_strings) read_but_dont_execute = 1; + if (rpm_requires) + { + read_but_dont_execute = 1; + initialize_shell_builtins (); + } + if (running_setuid && privileged_mode == 0) disable_priv_mode ();
-- http://linuxfromscratch.org/mailman/listinfo/lfs-dev FAQ: http://www.linuxfromscratch.org/faq/ Unsubscribe: See the above information page