about summary refs log tree commit diff
diff options
context:
space:
mode:
-rwxr-xr-xpkg/aterm-2.0-build.sh13
-rw-r--r--pkg/aterm-2.0.nix11
-rw-r--r--src/nix.cc341
-rwxr-xr-xsys/bootstrap14
-rwxr-xr-xsys/start18
5 files changed, 306 insertions, 91 deletions
diff --git a/pkg/aterm-2.0-build.sh b/pkg/aterm-2.0-build.sh
new file mode 100755
index 000000000000..5d65b7878c1c
--- /dev/null
+++ b/pkg/aterm-2.0-build.sh
@@ -0,0 +1,13 @@
+#! /bin/sh
+
+export PATH=$utils/bin
+export LIBRARY_PATH=$glibc/lib
+export CC=$gcc/bin/gcc
+export CFLAGS="-isystem $glibc/include -isystem $kernel/include"
+
+top=`pwd`
+tar xvfz $src
+cd aterm-2.0
+./configure --prefix=$top
+make
+make install
diff --git a/pkg/aterm-2.0.nix b/pkg/aterm-2.0.nix
new file mode 100644
index 000000000000..2484001bef60
--- /dev/null
+++ b/pkg/aterm-2.0.nix
@@ -0,0 +1,11 @@
+# Dependencies.
+utils <- 5703121fe19cbeeaee7edd659cf4a25b # prog-bootstrap
+gcc <- 02212b3dc4e50349376975367d433929 # gcc-bootstrap
+glibc <- c0ce03ee0bab298babbe7e3b6159d36c # glibc-bootstrap
+kernel <- 3dc8333a2c2b4d627b892755417acf89 # kernel-bootstrap
+
+# Original sources.
+src = 853474e4bcf4a85f7d38a0676b36bded # aterm-2.0.tar.gz
+
+# Build script.
+build = ee7ae4ade69f846d2385871bf532ef7e # aterm-2.0-build.sh
diff --git a/src/nix.cc b/src/nix.cc
index 0c786527082c..8108c2fca9fc 100644
--- a/src/nix.cc
+++ b/src/nix.cc
@@ -1,6 +1,10 @@
 #include <iostream>
+#include <fstream>
 #include <memory>
 #include <string>
+#include <sstream>
+#include <list>
+#include <cstdio>
 
 #include <unistd.h>
 #include <sys/stat.h>
@@ -15,10 +19,16 @@ using namespace std;
 #define PKGINFO_PATH "/pkg/sys/var/pkginfo"
 
 
+static string dbRefs = "refs";
+static string dbInstPkgs = "pkginst";
+
+
 static string prog;
 static string dbfile = PKGINFO_PATH;
 
 
+/* Wrapper class that ensures that the database is closed upon
+   object destruction. */
 class Db2 : public Db 
 {
 public:
@@ -81,85 +91,250 @@ void delDB(const string & dbname, const string & key)
 }
 
 
-void getPkg(int argc, char * * argv)
+/* Verify that a reference is valid (that is, is a MD5 hash code). */
+void checkRef(const string & s)
 {
-    string pkg;
-    string src;
-    string inst;
-    string cmd;
-    int res;
+    string err = "invalid reference: " + s;
+    if (s.length() != 32)
+        throw err;
+    for (int i = 0; i < 32; i++) {
+        char c = s[i];
+        if (!((c >= '0' && c <= '9') ||
+              (c >= 'a' && c <= 'f')))
+            throw err;
+    }
+}
 
-    if (argc != 1)
-        throw string("arguments missing in get-pkg");
 
-    pkg = argv[0];
+/* Compute the MD5 hash of a file. */
+string makeRef(string filename)
+{
+    char hash[33];
+
+    FILE * pipe = popen(("md5sum " + filename).c_str(), "r");
+    if (!pipe) throw string("cannot execute md5sum");
+
+    if (fread(hash, 32, 1, pipe) != 1)
+        throw string("cannot read hash from md5sum");
+    hash[32] = 0;
+
+    pclose(pipe);
+
+    checkRef(hash);
+    return hash;
+}
 
-    if (queryDB("pkginst", pkg, inst)) {
-        cout << inst << endl;
-        return;
+
+struct Dep
+{
+    string name;
+    string ref;
+    Dep(string _name, string _ref)
+    {
+        name = _name;
+        ref = _ref;
     }
+};
+
+typedef list<Dep> DepList;
+
+
+void readPkgDescr(const string & pkgfile,
+    DepList & pkgImports, DepList & fileImports)
+{
+    ifstream file;
+    file.exceptions(ios::badbit);
+    file.open(pkgfile.c_str());
     
-    cerr << "package " << pkg << " is not yet installed\n";
-        
-    if (!queryDB("pkgsrc", pkg, src)) 
-        throw string("source of package " + string(pkg) + " is not known");
+    while (!file.eof()) {
+        string line;
+        getline(file, line);
 
-    inst = "/pkg/" + pkg;
+        int n = line.find('#');
+        if (n >= 0) line = line.erase(n);
 
-    cmd = "rsync -a \"" + src + "\"/ \"" + inst + "\"";
+        if ((int) line.find_first_not_of(" ") < 0) continue;
         
-    res = system(cmd.c_str());
-    if (!WIFEXITED(res) || WEXITSTATUS(res) != 0)
-        throw string("unable to copy sources");
+        istringstream str(line);
+
+        string name, op, ref;
+        str >> name >> op >> ref;
+
+        checkRef(ref);
+
+        if (op == "<-") 
+            pkgImports.push_back(Dep(name, ref));
+        else if (op == "=")
+            fileImports.push_back(Dep(name, ref));
+        else throw string("invalid operator " + op);
+    }
+}
+
+
+string getPkg(string pkgref);
+
+
+typedef pair<string, string> EnvPair;
+typedef list<EnvPair> Environment;
+
+
+void installPkg(string pkgref)
+{
+    string pkgfile;
+    string src;
+    string path;
+    string cmd;
+    string builder;
+
+    if (!queryDB("refs", pkgref, pkgfile))
+        throw string("unknown package " + pkgref);
+
+    cerr << "installing package " + pkgref + " from " + pkgfile + "\n";
+
+    /* Verify that the file hasn't changed. !!! race */
+    if (makeRef(pkgfile) != pkgref)
+        throw string("file " + pkgfile + " is stale");
+
+    /* Read the package description file. */
+    DepList pkgImports, fileImports;
+    readPkgDescr(pkgfile, pkgImports, fileImports);
+
+    /* Recursively fetch all the dependencies, filling in the
+       environment as we go along. */
+    Environment env;
+
+    for (DepList::iterator it = pkgImports.begin();
+         it != pkgImports.end(); it++)
+    {
+        cerr << "fetching package dependency "
+             << it->name << " <- " << it->ref
+             << endl;
+        env.push_back(EnvPair(it->name, getPkg(it->ref)));
+    }
+
+    for (DepList::iterator it = fileImports.begin();
+         it != fileImports.end(); it++)
+    {
+        cerr << "fetching file dependency "
+             << it->name << " = " << it->ref
+             << endl;
 
-    if (chdir(inst.c_str()))
-        throw string("unable to chdir to package directory");
+        string file;
 
-    /* Prepare for building.  Clean the environment so that the
-       build process does not inherit things it shouldn't. */
-    setenv("PATH", "/pkg/sys/bin", 1);
+        if (!queryDB("refs", it->ref, file))
+            throw string("unknown file " + it->ref);
 
-    res = system("./buildme");
-    if (!WIFEXITED(res) || WEXITSTATUS(res) != 0)
+        if (makeRef(file) != it->ref)
+            throw string("file " + file + " is stale");
+
+        if (it->name == "build")
+            builder = file;
+        else
+            env.push_back(EnvPair(it->name, file));
+    }
+
+    if (builder == "")
+        throw string("no builder specified");
+
+    /* Construct a path for the installed package. */
+    path = "/pkg/" + pkgref;
+
+    /* Create the path. */
+    if (mkdir(path.c_str(), 0777))
+        throw string("unable to create directory " + path);
+
+    /* Fork a child to build the package. */
+    pid_t pid;
+    switch (pid = fork()) {
+
+    case -1:
+        throw string("unable to fork");
+
+    case 0: /* child */
+
+        /* Go to the build directory. */
+        if (chdir(path.c_str())) {
+            cout << "unable to chdir to package directory\n";
+            _exit(1);
+        }
+
+        /* Fill in the environment.  We don't bother freeing the
+           strings, since we'll exec or die soon anyway. */
+        const char * env2[env.size() + 1];
+        int i = 0;
+        for (Environment::iterator it = env.begin();
+             it != env.end(); it++, i++)
+            env2[i] = (new string(it->first + "=" + it->second))->c_str();
+        env2[i] = 0;
+
+        /* Execute the builder.  This should not return. */
+        execle(builder.c_str(), builder.c_str(), 0, env2);
+
+        cout << strerror(errno) << endl;
+
+        cout << "unable to execute builder\n";
+        _exit(1);
+    }
+
+    /* parent */
+
+    /* Wait for the child to finish. */
+    int status;
+    if (waitpid(pid, &status, 0) != pid)
+        throw string("unable to wait for child");
+    
+    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
         throw string("unable to build package");
 
-    setDB("pkginst", pkg, inst);
+    setDB(dbInstPkgs, pkgref, path);
+}
+
 
-    cout << inst << endl;
+string getPkg(string pkgref)
+{
+    string path;
+    checkRef(pkgref);
+    while (!queryDB(dbInstPkgs, pkgref, path))
+        installPkg(pkgref);
+    return path;
 }
 
 
-void registerPkg(int argc, char * * argv)
+string absPath(string filename)
 {
-    char * pkg;
-    char * src;
-    
-    if (argc != 2)
-        throw string("arguments missing in register-pkg");
+    if (filename[0] != '/') {
+        char buf[PATH_MAX];
+        if (!getcwd(buf, sizeof(buf)))
+            throw string("cannot get cwd");
+        filename = string(buf) + "/" + filename;
+        /* !!! canonicalise */
+    }
+    return filename;
+}
 
-    pkg = argv[0];
-    src = argv[1];
 
-    setDB("pkgsrc", pkg, src);
+void registerFile(string filename)
+{
+    filename = absPath(filename);
+    setDB(dbRefs, makeRef(filename), filename);
 }
 
 
 /* This is primarily used for bootstrapping. */
-void registerInstalledPkg(int argc, char * * argv)
+void registerInstalledPkg(string pkgref, string path)
 {
-    string pkg;
-    string inst;
-    
-    if (argc != 2)
-        throw string("arguments missing in register-installed-pkg");
-
-    pkg = argv[0];
-    inst = argv[1];
-    
-    if (inst == "")
-        delDB("pkginst", pkg);
+    checkRef(pkgref);
+    if (path == "")
+        delDB(dbInstPkgs, pkgref);
     else
-        setDB("pkginst", pkg, inst);
+        setDB(dbInstPkgs, pkgref, path);
+}
+
+
+void initDB()
+{
+    openDB(dbRefs, false);
+    openDB(dbInstPkgs, false);
 }
 
 
@@ -168,18 +343,29 @@ void run(int argc, char * * argv)
     string cmd;
 
     if (argc < 1)
-        throw string("command not specified\n");
+        throw string("command not specified");
 
     cmd = argv[0];
     argc--, argv++;
 
-    if (cmd == "get-pkg")
-        getPkg(argc, argv);
-    else if (cmd == "register-pkg")
-        registerPkg(argc, argv);
-    else if (cmd == "register-installed-pkg")
-        registerInstalledPkg(argc, argv);
-    else
+    if (cmd == "init") {
+        if (argc != 0)
+            throw string("init doesn't have arguments");
+        initDB();
+    } else if (cmd == "getpkg") {
+        if (argc != 1)
+            throw string("arguments missing in getpkg");
+        string path = getPkg(argv[0]);
+        cout << path << endl;
+    } else if (cmd == "reg") {
+        if (argc != 1)
+            throw string("arguments missing in reg");
+        registerFile(argv[0]);
+    } else if (cmd == "regpkg") {
+        if (argc != 2)
+            throw string("arguments missing in regpkg");
+        registerInstalledPkg(argv[0], argv[1]);
+    } else
         throw string("unknown command: " + string(cmd));
 }
     
@@ -190,31 +376,38 @@ int main(int argc, char * * argv)
 
     prog = argv[0];
 
-    while ((c = getopt(argc, argv, "d:")) != EOF) {
-        
-        switch (c) {
+    umask(0022);
 
-        case 'd':
-            dbfile = optarg;
-            break;
+    try {
 
-        default:
-            cerr << "unknown option\n";
-            break;
-        }
+        while ((c = getopt(argc, argv, "d:")) != EOF) {
+        
+            switch (c) {
 
-    }
+            case 'd':
+                dbfile = optarg;
+                break;
 
-    argc -= optind, argv += optind;
+            default:
+                throw string("unknown option");
+                break;
 
-    try {
+            }
+        }
+
+        argc -= optind, argv += optind;
         run(argc, argv);
-        return 0;
+
     } catch (DbException e) {
         cerr << "db exception: " << e.what() << endl;
         return 1;
+    } catch (exception e) {
+        cerr << e.what() << endl;
+        return 1;
     } catch (string s) {
         cerr << s << endl;
         return 1;
     }
+
+    return 0;
 }
diff --git a/sys/bootstrap b/sys/bootstrap
index e2265c1dcff0..f6aa16c8633e 100755
--- a/sys/bootstrap
+++ b/sys/bootstrap
@@ -26,7 +26,7 @@ mkdir -m 1777 $target/tmp
 pkgdb=$target/pkg/sys/var/pkginfo
 
 # Copy some programs and its libraries.
-utils="/usr/bin/vi /bin/sh /bin/mount /bin/umount /bin/ls /bin/ln /bin/cp /bin/mv /bin/rm /bin/cat /bin/df /bin/pwd /usr/bin/ld /usr/bin/as /bin/sed /bin/chmod /bin/chown /usr/bin/expr /bin/mkdir /bin/rmdir /usr/bin/sort /usr/bin/uniq /bin/uname /usr/bin/grep /bin/sleep /usr/bin/rsync /usr/bin/make /usr/bin/cmp /bin/date /usr/bin/tr /usr/bin/ar /usr/bin/ranlib /usr/bin/basename /usr/bin/less ../src/nix"
+utils="/usr/bin/vi /bin/sh /bin/mount /bin/umount /bin/ls /bin/ln /bin/cp /bin/mv /bin/rm /bin/cat /bin/df /bin/pwd /usr/bin/ld /usr/bin/as /bin/sed /bin/chmod /bin/chown /usr/bin/expr /bin/mkdir /bin/rmdir /usr/bin/sort /usr/bin/uniq /bin/uname /usr/bin/grep /bin/sleep /bin/gzip /usr/bin/make /usr/bin/cmp /bin/date /usr/bin/tr /usr/bin/ar /usr/bin/ranlib /usr/bin/basename /usr/bin/less /usr/bin/md5sum /bin/tar ../src/nix"
 bootlib=/pkg/prog-bootstrap/lib
 bootbin=/pkg/prog-bootstrap/bin
 mkdir -p $target/$bootlib
@@ -36,27 +36,27 @@ libs=`ldd $utils | awk '{ print $3 }' | sort | uniq`
 echo $libs
 cp -p $libs $target/$bootlib
 for i in libc.so.6 libdl.so.2 libpthread.so.0 librt.so.1 libresolv.so.2 ld-linux.so.2; do rm $target/$bootlib/$i; done
-../src/nix -d $pkgdb register-installed-pkg prog-bootstrap /pkg/prog-bootstrap
+../src/nix -d $pkgdb regpkg 5703121fe19cbeeaee7edd659cf4a25b /pkg/prog-bootstrap
 
 mv $target/$bootbin/nix $target/pkg/sys/bin
-../src/nix -d $pkgdb register-installed-pkg sys /pkg/sys
+../src/nix -d $pkgdb regpkg 36bcbb801f5052739af8220c6ea51434 /pkg/sys
 
 # Copy the bootstrap gcc.
 echo Copying gcc...
 rsync -a ../bootstrap/gcc/inst/pkg $target
-../src/nix -d $pkgdb register-installed-pkg gcc-bootstrap /pkg/gcc-bootstrap
+../src/nix -d $pkgdb regpkg 02212b3dc4e50349376975367d433929 /pkg/gcc-bootstrap
 
 # Copy the bootstrap glibc.
 echo Copying glibc...
 glibcdir=/pkg/glibc-bootstrap
 rsync -a ../bootstrap/glibc/inst/pkg $target
-../src/nix -d $pkgdb register-installed-pkg glibc-bootstrap $glibcdir
+../src/nix -d $pkgdb regpkg c0ce03ee0bab298babbe7e3b6159d36c $glibcdir
 
 # Copy the bootstrap kernel header files.
 echo Copying kernel headers...
 kerneldir=/pkg/kernel-bootstrap
 rsync -a ../bootstrap/kernel/inst/pkg $target
-../src/nix -d $pkgdb register-installed-pkg kernel-bootstrap $kerneldir
+../src/nix -d $pkgdb regpkg 3dc8333a2c2b4d627b892755417acf89 $kerneldir
 
 # Compatibility.
 rm -rf $target/lib
@@ -75,7 +75,7 @@ $target/$glibcdir/sbin/ldconfig -r $target
 
 # Source repository.
 rm -f $target/src
-ln -sf /mnt/host/`pwd`/../src $target/src
+ln -sf /mnt/host/`pwd`/../pkg $target/src
 
 # Copy boot script.
 cp -p ./start $target/pkg/sys/bin
diff --git a/sys/start b/sys/start
index f822b2fa7e13..b36cde297436 100755
--- a/sys/start
+++ b/sys/start
@@ -4,7 +4,7 @@
 export PATH=/pkg/sys/bin
 
 # Add in the utilities needed for booting.
-export PATH=$PATH:`nix get-pkg prog-bootstrap`/bin
+export PATH=$PATH:`nix getpkg 5703121fe19cbeeaee7edd659cf4a25b`/bin
 
 echo
 echo Starting up...
@@ -14,17 +14,15 @@ mount -n -o remount,rw /dev/root /
 mount -n -t proc none /proc
 mount -n -t hostfs none /mnt/host 
 
-echo Registering available src packages...
-( cd /src
-  for i in *; do
-    if test -d $i; then
-      echo "  $i"
-      nix register-pkg $i /src/$i
-    fi
-  done
+echo Registering available sources...
+( if cd /src; then
+    for i in *; do
+      nix reg $i
+    done
+  fi
 )
 
-export PATH=`nix get-pkg coreutils-4.5.7`/bin:$PATH
+export PATH=`nix getpkg coreutils-4.5.7`/bin:$PATH
 
 echo
 echo "=== starting interactive shell ==="