aboutsummaryrefslogtreecommitdiff
#include "sqlite.hh"
#include "util.hh"

#include <sqlite3.h>

namespace nix {

[[noreturn]] void throwSQLiteError(sqlite3 * db, const format & f)
{
    int err = sqlite3_errcode(db);
    if (err == SQLITE_BUSY || err == SQLITE_PROTOCOL) {
        if (err == SQLITE_PROTOCOL)
            printMsg(lvlError, "warning: SQLite database is busy (SQLITE_PROTOCOL)");
        else {
            static bool warned = false;
            if (!warned) {
                printMsg(lvlError, "warning: SQLite database is busy");
                warned = true;
            }
        }
        /* Sleep for a while since retrying the transaction right away
           is likely to fail again. */
#if HAVE_NANOSLEEP
        struct timespec t;
        t.tv_sec = 0;
        t.tv_nsec = (random() % 100) * 1000 * 1000; /* <= 0.1s */
        nanosleep(&t, 0);
#else
        sleep(1);
#endif
        throw SQLiteBusy(format("%1%: %2%") % f.str() % sqlite3_errmsg(db));
    }
    else
        throw SQLiteError(format("%1%: %2%") % f.str() % sqlite3_errmsg(db));
}

SQLite::~SQLite()
{
    try {
        if (db && sqlite3_close(db) != SQLITE_OK)
            throwSQLiteError(db, "closing database");
    } catch (...) {
        ignoreException();
    }
}

void SQLiteStmt::create(sqlite3 * db, const string & s)
{
    checkInterrupt();
    assert(!stmt);
    if (sqlite3_prepare_v2(db, s.c_str(), -1, &stmt, 0) != SQLITE_OK)
        throwSQLiteError(db, "creating statement");
    this->db = db;
}

SQLiteStmt::~SQLiteStmt()
{
    try {
        if (stmt && sqlite3_finalize(stmt) != SQLITE_OK)
            throwSQLiteError(db, "finalizing statement");
    } catch (...) {
        ignoreException();
    }
}

SQLiteStmt::Use::Use(SQLiteStmt & stmt)
    : stmt(stmt)
{
    assert(stmt.stmt);
    /* Note: sqlite3_reset() returns the error code for the most
       recent call to sqlite3_step().  So ignore it. */
    sqlite3_reset(stmt);
}

SQLiteStmt::Use::~Use()
{
    sqlite3_reset(stmt);
}

SQLiteStmt::Use & SQLiteStmt::Use::operator () (const std::string & value, bool notNull)
{
    if (notNull) {
        if (sqlite3_bind_text(stmt, curArg++, value.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK)
            throwSQLiteError(stmt.db, "binding argument");
    } else
        bind();
    return *this;
}

SQLiteStmt::Use & SQLiteStmt::Use::operator () (int64_t value, bool notNull)
{
    if (notNull) {
        if (sqlite3_bind_int64(stmt, curArg++, value) != SQLITE_OK)
            throwSQLiteError(stmt.db, "binding argument");
    } else
        bind();
    return *this;
}

SQLiteStmt::Use & SQLiteStmt::Use::bind()
{
    if (sqlite3_bind_null(stmt, curArg++) != SQLITE_OK)
        throwSQLiteError(stmt.db, "binding argument");
    return *this;
}

int SQLiteStmt::Use::step()
{
    return sqlite3_step(stmt);
}

void SQLiteStmt::Use::exec()
{
    int r = step();
    assert(r != SQLITE_ROW);
    if (r != SQLITE_DONE)
        throwSQLiteError(stmt.db, "executing SQLite statement");
}

bool SQLiteStmt::Use::next()
{
    int r = step();
    if (r != SQLITE_DONE && r != SQLITE_ROW)
        throwSQLiteError(stmt.db, "executing SQLite query");
    return r == SQLITE_ROW;
}

std::string SQLiteStmt::Use::getStr(int col)
{
    auto s = (const char *) sqlite3_column_text(stmt, col);
    assert(s);
    return s;
}

int64_t SQLiteStmt::Use::getInt(int col)
{
    // FIXME: detect nulls?
    return sqlite3_column_int64(stmt, col);
}

SQLiteTxn::SQLiteTxn(sqlite3 * db)
{
    this->db = db;
    if (sqlite3_exec(db, "begin;", 0, 0, 0) != SQLITE_OK)
        throwSQLiteError(db, "starting transaction");
    active = true;
}

void SQLiteTxn::commit()
{
    if (sqlite3_exec(db, "commit;", 0, 0, 0) != SQLITE_OK)
        throwSQLiteError(db, "committing transaction");
    active = false;
}

SQLiteTxn::~SQLiteTxn()
{
    try {
        if (active && sqlite3_exec(db, "rollback;", 0, 0, 0) != SQLITE_OK)
            throwSQLiteError(db, "aborting transaction");
    } catch (...) {
        ignoreException();
    }
}

}
* gnu/system/linux-initrd.scm (flat-linux-module-directory)[build-exp]: Remove 'lookup' procedure and use 'find-module-file' instead. * gnu/system/mapped-devices.scm (check-device-initrd-modules): Add comment. Ludovic Courtès 2018-07-29linux-initrd: Improve check of initrd modules....Previously we would not strip the ".ko" suffix if present. * gnu/build/linux-modules.scm (file-name->module-name): Export. * gnu/system/mapped-devices.scm (check-device-initrd-modules): Use 'file-name->module-name' instead of 'normalize-module-name'. Ludovic Courtès 2018-06-14linux-initrd: Module check correctly handles hyphen vs. underscore....Fixes <https://bugs.gnu.org/31714>. Reported by Vagrant Cascadian <vagrant@debian.org> and Florian Pelz <pelzflorian@pelzflorian.de>. * gnu/system/mapped-devices.scm (check-device-initrd-modules): Pass LINUX-MODULES through 'normalize-module-name'. * gnu/build/linux-modules.scm (normalize-module-name): Export. Ludovic Courtès 2018-03-15linux-initrd: Autoload known-module-aliases, again....Fixes a regression introduced in 8ab10c19d72caab7459034a6e72b0117d7c5cec8. * gnu/system/mapped-devices.scm: Autoload 'known-module-aliases'. Mark H Weaver 2018-03-15linux-initrd: Move 'check-device-initrd-modules' elsewhere....This mostly reverts ca23693d280de5c4031058da4d3041d830080484, which introduced a circular dependency between (gnu system linux-initrd) and (gnu system mapped-devices). Reported by Eric Bavier. * gnu/system/linux-initrd.scm (check-device-initrd-modules): Move to... * gnu/system/mapped-devices.scm (check-device-initrd-modules): ... here. * po/guix/POTFILES.in: Adjust accordingly. Ludovic Courtès 2018-03-07linux-initrd: Factorize 'check-device-initrd-modules'....* gnu/system/mapped-devices.scm (check-device-initrd-modules): Move to... * gnu/system/linux-initrd.scm (check-device-initrd-modules): ... here. New procedure. * po/guix/POTFILES.in: Add it. * guix/scripts/system.scm (check-initrd-modules)[check-device]: Remove. Use 'check-device-initrd-modules' instead. Ludovic Courtès 2018-03-02guix system: Check for the lack of modules in the initrd....* guix/scripts/system.scm (check-mapped-devices): Take an OS instead of a list of <mapped-device>. Pass #:needed-for-boot? and #:initrd-modules to CHECK. (check-initrd-modules): New procedure. (perform-action): Move 'check-mapped-devices' call first. Add call to 'check-initrd-modules'. * gnu/system/mapped-devices.scm (check-device-initrd-modules): New procedure. (check-luks-device): Add #:initrd-modules and #:needed-for-boot?. Use them to call 'check-device-initrd-modules'. Ludovic Courtès 2017-12-22mapped-devices: 'luks-device-mapping' checks its source device....* gnu/system/mapped-devices.scm (check-luks-device): New procedure. (luks-device-mapping)[check]: New field. Ludovic Courtès 2017-12-22mapped-devices: Add 'location' and 'check' fields....* gnu/system/mapped-devices.scm (<mapped-device>)[location]: New field. (<mapped-device-type>)[check]: New field. Ludovic Courtès 2017-09-11system: Introduce a disjoint UUID type....Conceptually a UUID is just a bytevector. However, there's software out there such as GRUB that relies on the string representation of different UUID types (e.g., the string representation of DCE UUIDs differs from that of ISO-9660 UUIDs, even if they are actually bytevectors of the same length). This new <uuid> record type allows us to preserve information about the type of UUID so we can eventually convert it to a string using the right representation. * gnu/system/uuid.scm (<uuid>): New record type. (bytevector->uuid): New procedure. (uuid): Return calls to 'make-uuid'. (uuid->string): Rewrite using 'match-lambda*' to accept a single 'uuid?' argument. * gnu/bootloader/grub.scm (grub-root-search): Check for 'uuid?' instead of 'bytevector?'. * gnu/system.scm (bootable-kernel-arguments): Check whether ROOT-DEVICE is 'uuid?'. (read-boot-parameters): Use 'bytevector->uuid' when the store device is a bytevector. (read-boot-parameters-file): Check for 'uuid?' instead of 'bytevector?'. (device->sexp): New procedure. (operating-system-boot-parameters-file): Use it for 'root-device' and 'store'. (operating-system-bootcfg): Remove conditional in definition of 'root-device'. * gnu/system/file-systems.scm (file-system->spec): Check for 'uuid?' on DEVICE and take its bytevector. * gnu/system/mapped-devices.scm (open-luks-device): Likewise. * gnu/system/vm.scm (iso9660-image): Call 'uuid-bytevector' for the #:volume-uuid argument. Ludovic Courtès 2017-06-07mapped-devices: Cope with delayed appearance of LUKS source....Fixes <https://bugs.gnu.org/27242>. * gnu/system/mapped-devices.scm (open-luks-device): If 'find-partition-by-luks-uuid' fails, try again once per second, up to ten times. Mark H Weaver 2017-01-24mapped-devices: 'source' can be a list of strings....Reported by myglc2 <myglc2@gmail.com>. * gnu/system/mapped-devices.scm (<mapped-device>)[source]: Update comment to note that this can be a list of strings. Ludovic Courtès 2016-11-23mapped-devices: Use 'cryptsetup-static' in 'luks-device-mapping'....* gnu/system/mapped-devices.scm (open-luks-device): Use CRYPTSETUP-STATIC instead of CRYPTSETUP. Use 'file-append'. (close-luks-device): Likewise. Ludovic Courtès 2016-10-27mapped-devices: Use 'mdadm-static' in 'raid-device-mapping'....* gnu/system/mapped-devices.scm (open-raid-device, close-raid-device): Use MDADM-STATIC instead of MDADM. Use 'file-append'. Ludovic Courtès 2016-10-04mapped-devices: Properly open RAID devices....This fixes a type error introduced in 7f8ad82bf23b032ad6bd85bb1daa87cc83de509c, given that SOURCES is a list. * gnu/system/mapped-devices.scm (open-raid-device): Add 'apply' invocation. Ludovic Courtès 2016-09-05system: Use 'source-module-closure' where needed....* gnu/system/vm.scm (%vm-module-closure): Remove. (expression->derivation-in-linux-vm): Use 'source-module-closure' instead of %VM-MODULE-CLOSURE. (qemu-image): Likewise. * gnu/system/linux-initrd.scm (expression->initrd): Likewise. (flat-linux-module-directory, base-initrd): Likewise. * gnu/system/mapped-devices.scm (open-luks-device): Likewise. Ludovic Courtès 2016-08-03mapped-devices: raid-device-mapping: Avoid non-top-level 'use-modules'....Fixes <http://bugs.gnu.org/24135>. Reported by myglc2 <myglc2@gmail.com>. * gnu/system/mapped-devices.scm (open-raid-device): Avoid non-top-level 'use-modules' form. Ludovic Courtès 2016-08-02mapped-devices: Bail out when RAID sources don't show up....* gnu/system/mapped-devices.scm (open-raid-device): Bail out after 20 loop iterations. Ludovic Courtès 2016-08-02mapped-devices: Make RAID device opening message clearer....* gnu/system/mapped-devices.scm (open-raid-device): Rename 'source' to 'sources'. Make 'waiting' message more informative. (close-raid-device): Rename 'source' to 'sources'. Ludovic Courtès 2016-08-02mapped-devices: Do not always use (gnu build file-systems)....Fixes <http://bugs.gnu.org/24129>. Reported by myglc2 <myglc2@gmail.com>. * gnu/system/mapped-devices.scm (device-mapping-service-type): Remove 'modules' field from 'shepherd-service' form. (open-luks-device): Add 'use-modules' form. Ludovic Courtès 2016-07-25system: Add mapped devices for RAID....* gnu/system/mapped-devices.scm (raid-device-mapping, open-raid-device, close-raid-device): New variables. * doc/guix.texi (Mapped Devices): Add documentation for RAID devices, reorganize documentation for LUKS devices. Co-authored-by: Ludovic Courtès <ludo@gnu.org> Andreas Enge 2016-07-12services: <shepherd-service> no longer has an 'imported-modules' field....* gnu/services/shepherd.scm (<shepherd-service>)[imported-modules]: Remove. (%default-imported-modules): Make private. (shepherd-service-file): Use 'with-imported-modules'. (shepherd-configuration-file): Remove 'modules' and the calls to 'imported-modules' and 'compiled-modules'. Use 'with-imported-modules' instead. * doc/guix.texi (Shepherd Services): Adjust accordingly. * gnu/services/base.scm (file-system-shepherd-service): Use 'with-imported-modules'. Remove 'imported-modules' field. * gnu/system/mapped-devices.scm (device-mapping-service-type): Remove 'imported-modules'. (open-luks-device): Use 'with-imported-modules'. * gnu/tests.scm (marionette-shepherd-service): Remove 'imported-modules' field and use 'with-imported-modules'. Ludovic Courtès 2016-04-18mapped-devices: LUKS partitions can be designated by their UUID....* gnu/system/mapped-devices.scm (device-mapping-service-type): Add 'modules' and 'imported-modules' fields to 'shepherd-service'. (open-luks-device): Use 'find-partition-by-luks-uuid' to lookup the partition when SOURCE is a bytevector. * gnu/system/linux-initrd.scm (base-initrd): Augment 'use-modules' form. * doc/guix.texi (Mapped Devices): Give example with a UUID. Ludovic Courtès 2016-04-18mapped-devices: 'mapped-device-service' takes a <mapped-device>....* gnu/system/mapped-devices.scm (device-mapping-service): Take a <mapped-device> instead of 3 parameters. (device-mapping-service-type): Adjust accordingly. * gnu/system.scm (device-mapping-services): Adjust accordingly. Ludovic Courtès 2016-04-18services: Move 'device-mapping-service' to (gnu system mapped-devices)....* gnu/services/base.scm (device-mapping-service-type) (device-mapping-service): Move to... * gnu/system/mapped-devices.scm (device-mapping-service-type): (device-mapping-service): ... here. New variables. Ludovic Courtès 2016-04-18system: Move 'luks-device-mapping' to (gnu system mapped-devices)....* gnu/system.scm (open-luks-device, close-luks-device) (luks-device-mapping): Move to... * gnu/system/mapped-devices.scm: ... here. New file. Ludovic Courtès 2016-04-18system: Add (gnu system mapped-devices)....* gnu/system/file-systems.scm (<mapped-device>, <mapped-device-type>): Move to... * gnu/system/mapped-devices.scm: ... here. New file. * gnu/system.scm, gnu/services/base.scm, gnu/system/linux-initrd.scm: Use it. * gnu-system.am (GNU_SYSTEM_MODULES): Add it. * gnu.scm (%public-modules): Add it. Ludovic Courtès