Ignore:
Timestamp:
Apr 9, 2013, 6:46:31 PM (7 years ago)
Author:
snc@…
Message:

merge from trunk

Location:
branches/gsoc11-statistics/base
Files:
3 deleted
77 edited
4 copied

Legend:

Unmodified
Added
Removed
  • branches/gsoc11-statistics/base

  • branches/gsoc11-statistics/base/src/config.h.in

    r77864 r105085  
    9090#undef HAVE_LIBMD
    9191
    92 /* Define to 1 if you have the `readline' library (-lreadline). */
     92/* Define to 1 if you have the 'readline' library (-lreadline). */
    9393#undef HAVE_LIBREADLINE
    9494
     
    270270/* Attribute to mark unused variables */
    271271#undef UNUSED
     272
     273/* define sqlite3_prepare to sqlite_prepare_v2 if the latter is not available
     274   */
     275#undef sqlite3_prepare_v2
  • branches/gsoc11-statistics/base/src/cregistry/entry.c

    r88412 r105085  
    122122    char* query = "INSERT INTO registry.ports "
    123123        "(name, version, revision, variants, epoch) VALUES (?, ?, ?, ?, ?)";
    124     if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
     124    if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
    125125            && (sqlite3_bind_text(stmt, 1, name, -1, SQLITE_STATIC)
    126126                == SQLITE_OK)
     
    191191        "AND revision=? AND variants=? AND epoch!=?";
    192192    }
    193     if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
     193    if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
    194194            && (sqlite3_bind_text(stmt, 1, name, -1, SQLITE_STATIC)
    195195                == SQLITE_OK)
     
    250250    char* files_query = "DELETE FROM registry.files WHERE id=?";
    251251    char* dependencies_query = "DELETE FROM registry.dependencies WHERE id=?";
    252     if ((sqlite3_prepare(reg->db, ports_query, -1, &ports, NULL) == SQLITE_OK)
     252    if ((sqlite3_prepare_v2(reg->db, ports_query, -1, &ports, NULL) == SQLITE_OK)
    253253            && (sqlite3_bind_int64(ports, 1, entry->id) == SQLITE_OK)
    254             && (sqlite3_prepare(reg->db, files_query, -1, &files, NULL)
     254            && (sqlite3_prepare_v2(reg->db, files_query, -1, &files, NULL)
    255255                == SQLITE_OK)
    256256            && (sqlite3_bind_int64(files, 1, entry->id) == SQLITE_OK)
    257             && (sqlite3_prepare(reg->db, dependencies_query, -1, &dependencies,
     257            && (sqlite3_prepare_v2(reg->db, dependencies_query, -1, &dependencies,
    258258                    NULL) == SQLITE_OK)
    259259            && (sqlite3_bind_int64(dependencies, 1, entry->id) == SQLITE_OK)) {
     
    497497    char* query = "SELECT id FROM registry.files WHERE actual_path=? AND active";
    498498    int lower_bound = 0;
    499     if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
     499    if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
    500500            && (sqlite3_bind_text(stmt, 1, path, -1, SQLITE_STATIC)
    501501                == SQLITE_OK)) {
     
    544544    sqlite_int64 result = 0;
    545545    char* query = "SELECT id FROM registry.files WHERE actual_path=? AND active";
    546     if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
     546    if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
    547547            && (sqlite3_bind_text(stmt, 1, path, -1, SQLITE_STATIC)
    548548                == SQLITE_OK)) {
     
    581581    query = sqlite3_mprintf("SELECT %q FROM registry.ports WHERE id=%lld", key,
    582582            entry->id);
    583     if (sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
     583    if (sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
    584584        int r;
    585585        do {
     
    639639    query = sqlite3_mprintf("UPDATE registry.ports SET %q = '%q' WHERE id=%lld",
    640640            key, value, entry->id);
    641     if (sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
     641    if (sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
    642642        int r;
    643643        do {
     
    687687    char* insert = "INSERT INTO registry.files (id, path, mtime, active) "
    688688        "VALUES (?, ?, 0, 0)";
    689     if ((sqlite3_prepare(reg->db, insert, -1, &stmt, NULL) == SQLITE_OK)
     689    if ((sqlite3_prepare_v2(reg->db, insert, -1, &stmt, NULL) == SQLITE_OK)
    690690            && (sqlite3_bind_int64(stmt, 1, entry->id) == SQLITE_OK)) {
    691691        int i;
     
    739739    sqlite3_stmt* stmt = NULL;
    740740    char* query = "DELETE FROM registry.files WHERE path=? AND id=?";
    741     if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
     741    if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
    742742            && (sqlite3_bind_int64(stmt, 2, entry->id) == SQLITE_OK)) {
    743743        int i;
     
    796796    sqlite3_stmt* stmt = NULL;
    797797    char* query = "SELECT path FROM registry.files WHERE id=? ORDER BY path";
    798     if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
     798    if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
    799799            && (sqlite3_bind_int64(stmt, 1, entry->id) == SQLITE_OK)) {
    800800        char** result = malloc(10*sizeof(char*));
     
    864864    char* query = "SELECT actual_path FROM registry.files WHERE id=? "
    865865        "AND active ORDER BY actual_path";
    866     if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
     866    if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
    867867            && (sqlite3_bind_int64(stmt, 1, entry->id) == SQLITE_OK)) {
    868868        char** result = malloc(10*sizeof(char*));
     
    947947    }
    948948
    949     if (sqlite3_prepare(reg->db, select_query, -1, &select, NULL) == SQLITE_OK){
    950         if ((sqlite3_prepare(reg->db, update_query, -1, &update, NULL)
     949    if (sqlite3_prepare_v2(reg->db, select_query, -1, &select, NULL) == SQLITE_OK){
     950        if ((sqlite3_prepare_v2(reg->db, update_query, -1, &update, NULL)
    951951                == SQLITE_OK)
    952952                && (sqlite3_bind_int64(update, 3, entry->id) == SQLITE_OK)) {
     
    10391039    sqlite3_stmt* stmt = NULL;
    10401040    char* query = "UPDATE registry.files SET active=0 WHERE actual_path=? AND id=?";
    1041     if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
     1041    if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
    10421042            && (sqlite3_bind_int64(stmt, 2, entry->id) == SQLITE_OK)) {
    10431043        for (i=0; i<file_count && result; i++) {
     
    11401140    sqlite3_stmt* stmt = NULL;
    11411141    char* query = "INSERT INTO registry.dependencies (id, name) VALUES (?,?)";
    1142     if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
     1142    if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
    11431143            && (sqlite3_bind_int64(stmt, 1, entry->id) == SQLITE_OK)
    11441144            && (sqlite3_bind_text(stmt, 2, name, -1, SQLITE_STATIC)
  • branches/gsoc11-statistics/base/src/cregistry/entry.h

    r88412 r105085  
    44 *
    55 * Copyright (c) 2007 Chris Pickel <sfiera@macports.org>
     6 * Copyright (c) 2012 The MacPorts Project
    67 * All rights reserved.
    78 *
  • branches/gsoc11-statistics/base/src/cregistry/file.c

    r88412 r105085  
    109109    int lower_bound = 0;
    110110
    111     if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
     111    if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
    112112            && (sqlite3_bind_text(stmt, 1, id, -1, SQLITE_STATIC)
    113113                == SQLITE_OK)
     
    238238    query = sqlite3_mprintf("SELECT %q FROM registry.files WHERE id=%lld "
    239239            "AND path='%q'", key, file->key.id, file->key.path);
    240     if (sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
     240    if (sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
    241241        int r;
    242242        do {
     
    293293    query = sqlite3_mprintf("UPDATE registry.files SET %q = '%q' WHERE id=%lld "
    294294            "AND path='%q'", key, value, file->key.id, file->key.path);
    295     if (sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
     295    if (sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
    296296        int r;
    297297        do {
  • branches/gsoc11-statistics/base/src/cregistry/registry.c

    r88412 r105085  
    55 *
    66 * Copyright (c) 2007 Chris Pickel <sfiera@macports.org>
     7 * Copyright (c) 2012 The MacPorts Project
    78 * All rights reserved.
    89 *
     
    118119#endif
    119120
     121        sqlite3_busy_timeout(reg->db, 25);
     122
    120123        if (init_db(reg->db, errPtr)) {
    121124            reg->status = reg_none;
     
    205208        int r;
    206209        do {
    207             r = sqlite3_prepare(reg->db, query, -1, &stmt, NULL);
     210            r = sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL);
    208211        } while (r == SQLITE_BUSY);
    209212        if (r == SQLITE_OK) {
     
    230233            } while (r == SQLITE_BUSY);
    231234
     235            sqlite3_finalize(stmt);
     236            stmt = NULL;
     237
    232238            if (result) {
    233239                result &= update_db(reg->db, errPtr);
     
    264270        return 0;
    265271    }
    266     if (sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
     272    if (sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
    267273        int r;
    268274        reg_entry* entry;
     
    361367 */
    362368int reg_start_write(reg_registry* reg, reg_error* errPtr) {
    363     if (reg_start(reg, "BEGIN EXCLUSIVE", errPtr)) {
     369    if (reg_start(reg, "BEGIN IMMEDIATE", errPtr)) {
    364370        reg->status |= reg_transacting | reg_can_write;
    365371        return 1;
     
    372378 * Helper function for `reg_commit` and `reg_rollback`.
    373379 */
    374 static int reg_end(reg_registry* reg, const char* query, reg_error* errPtr) {
     380static int reg_end(reg_registry* reg, const char* query, reg_error* errPtr, int is_rollback) {
    375381    if (!(reg->status & reg_transacting)) {
    376382        reg_throw(errPtr, REG_MISUSE, "couldn't end transaction because no "
     
    384390                return 1;
    385391            }
    386         } while (r == SQLITE_BUSY);
     392        } while (r == SQLITE_BUSY && !is_rollback);
    387393        reg_sqlite_error(reg->db, errPtr, NULL);
    388394        return 0;
     
    399405 */
    400406int reg_commit(reg_registry* reg, reg_error* errPtr) {
    401     if (reg_end(reg, "COMMIT", errPtr)) {
     407    if (reg_end(reg, "COMMIT", errPtr, 0)) {
    402408        reg->status &= ~(reg_transacting | reg_can_write);
    403409        return 1;
     
    416422 */
    417423int reg_rollback(reg_registry* reg, reg_error* errPtr) {
    418     if (reg_end(reg, "ROLLBACK", errPtr)) {
     424    if (reg_end(reg, "ROLLBACK", errPtr, 1)) {
    419425        reg->status &= ~(reg_transacting | reg_can_write);
    420426        return 1;
     
    447453    }
    448454
    449     if (sqlite3_prepare(db, "VACUUM", -1, &stmt, NULL) == SQLITE_OK) {
     455    if (sqlite3_prepare_v2(db, "VACUUM", -1, &stmt, NULL) == SQLITE_OK) {
    450456        int r;
    451457        /* XXX: Busy waiting, consider using sqlite3_busy_handler/timeout */
  • branches/gsoc11-statistics/base/src/cregistry/registry.h

    r88412 r105085  
    55 *
    66 * Copyright (c) 2007 Chris Pickel <sfiera@macports.org>
     7 * Copyright (c) 2012 The MacPorts Project
    78 * All rights reserved.
    89 *
  • branches/gsoc11-statistics/base/src/cregistry/sql.c

    r88412 r105085  
    44 *
    55 * Copyright (c) 2007 Chris Pickel <sfiera@macports.org>
     6 * Copyright (c) 2012 The MacPorts Project
    67 * All rights reserved.
    78 *
     
    5253int do_queries(sqlite3* db, char** queries, reg_error* errPtr) {
    5354    char** query;
     55    sqlite3_stmt* stmt = NULL;
     56    int r = SQLITE_OK;
     57
    5458    for (query = queries; *query != NULL; query++) {
    55         sqlite3_stmt* stmt = NULL;
    56         if ((sqlite3_prepare(db, *query, -1, &stmt, NULL) != SQLITE_OK)
    57                 || (sqlite3_step(stmt) != SQLITE_DONE)) {
     59        if ((r = sqlite3_prepare_v2(db, *query, -1, &stmt, NULL)) != SQLITE_OK) {
     60            sqlite3_finalize(stmt);
     61            break;
     62        }
     63
     64        do {
     65            r = sqlite3_step(stmt);
     66        } while (r == SQLITE_BUSY);
     67
     68        sqlite3_finalize(stmt);
     69
     70        /* Either execution succeeded and r == SQLITE_DONE | SQLITE_ROW, or there was an error */
     71        if (r != SQLITE_DONE && r != SQLITE_ROW) {
     72            /* stop executing statements in case of errors */
     73            break;
     74        }
     75    }
     76
     77    switch (r) {
     78        case SQLITE_OK:
     79        case SQLITE_DONE:
     80        case SQLITE_ROW:
     81            return 1;
     82        default:
     83            /* handle errors */
    5884            reg_sqlite_error(db, errPtr, *query);
    59             if (stmt) {
    60                 sqlite3_finalize(stmt);
    61             }
    6285            return 0;
    63         }
    64         sqlite3_finalize(stmt);
    65     }
    66     return 1;
     86    }
    6787}
    6888
     
    151171
    152172/**
     173 * Tries to ROLLBACK a currently running transaction on the SQLite database.
     174 * Errors are silently ignored to preserve errors that have been set before and
     175 * are probably the root cause of why we did the rollback in the first place.
     176 *
     177 * @param [in] db    database to rollback
     178 * @return           true if success, false on failure
     179 */
     180static int rollback_db(sqlite3* db) {
     181    char* rollback = "ROLLBACK";
     182    sqlite3_stmt* stmt = NULL;
     183
     184    /*puts("Attempting to ROLLBACK...");*/
     185
     186    if (sqlite3_prepare_v2(db, rollback, -1, &stmt, NULL) != SQLITE_OK) {
     187        /*printf("failed prepare: %d: %s\n", sqlite3_errcode(db), sqlite3_errmsg(db));*/
     188        return 0;
     189    }
     190
     191    if (sqlite3_step(stmt) != SQLITE_DONE) {
     192        /*printf("failed step: %d: %s\n", sqlite3_errcode(db), sqlite3_errmsg(db));*/
     193        return 0;
     194    }
     195
     196    /*puts("success.");*/
     197
     198    return 1;
     199}
     200
     201/**
    153202 * Updates the database if necessary. This function queries the current database version
    154203 * from the metadata table and executes SQL to update the schema to newer versions if needed.
     
    161210int update_db(sqlite3* db, reg_error* errPtr) {
    162211    const char* version;
    163     char* query = "SELECT value FROM registry.metadata WHERE key = 'version'";
    164     sqlite3_stmt *stmt = NULL;
    165 
    166     if ((sqlite3_prepare(db, query, -1, &stmt, NULL) != SQLITE_OK)
    167             || (sqlite3_step(stmt) != SQLITE_ROW)) {
    168         goto reg_err_out;
    169     }
    170     if (NULL == (version = (const char *)sqlite3_column_text(stmt, 0))) {
    171         goto reg_err_out;
    172     }
    173     /* can't call rpm_vercomp directly, because it is static, but can call sql_version */
    174     if (sql_version(NULL, strlen(version), version, strlen("1.1"), "1.1") < 0) {
    175         /* conversion necessary, add binary field and index to files table */
    176         static char* version_1_1_queries[] = {
    177             "BEGIN",
    178 
    179             "ALTER TABLE registry.files ADD COLUMN binary BOOL",
    180             "CREATE INDEX registry.file_binary ON files(binary)",
    181 
    182             "UPDATE registry.metadata SET value = '1.100' WHERE key = 'version'",
    183 
    184             "COMMIT",
    185             NULL
    186         };
    187 
    188         if (!do_queries(db, version_1_1_queries, errPtr)) {
    189             goto err_out;
    190         }
    191 
    192         /* TODO: Walk the file tree and set the binary field */
    193     }
     212    int r;
     213    int did_update = 0; /* true, if an update was done and the loop should be run again */
     214    char* q_begin = "BEGIN";
     215    char* q_version = "SELECT value FROM registry.metadata WHERE key = 'version'";
     216    char* query = q_begin;
     217    sqlite3_stmt* stmt = NULL;
     218
     219    do {
     220        did_update = 0;
     221
     222        /* open a transaction to prevent a check-and-change race condition between
     223         * multiple port(1) instances */
     224        if ((r = sqlite3_prepare_v2(db, query, -1, &stmt, NULL)) != SQLITE_OK) {
     225            break;
     226        }
     227
     228        if ((r = sqlite3_step(stmt)) != SQLITE_DONE) {
     229            break;
     230        }
     231
     232        sqlite3_finalize(stmt);
     233        stmt = NULL;
     234
     235        /* query current version number */
     236        query = q_version;
     237        if ((r = sqlite3_prepare_v2(db, query, -1, &stmt, NULL)) != SQLITE_OK) {
     238            break;
     239        }
     240
     241        r = sqlite3_step(stmt);
     242        if (r == SQLITE_DONE) {
     243            /* the version number was not found */
     244            reg_throw(errPtr, REG_INVALID, "Version number in metadata table not found.");
     245            sqlite3_finalize(stmt);
     246            rollback_db(db);
     247            return 0;
     248        }
     249        if (r != SQLITE_ROW) {
     250            /* an error occured querying */
     251            break;
     252        }
     253        if (NULL == (version = (const char *)sqlite3_column_text(stmt, 0))) {
     254            reg_throw(errPtr, REG_INVALID, "Version number in metadata table is NULL.");
     255            sqlite3_finalize(stmt);
     256            rollback_db(db);
     257            return 0;
     258        }
     259
     260        /* we can't call vercmp directly because it's static, but we have
     261         * sql_version, which is basically an alias */
     262        if (sql_version(NULL, -1, version, -1, "1.1") < 0) {
     263            /* we need to update to 1.1, add binary field and index to files
     264             * table */
     265            static char* version_1_1_queries[] = {
     266#if SQLITE_VERSION_NUMBER >= 3002000
     267                "ALTER TABLE registry.files ADD COLUMN binary BOOL",
     268#else
     269                /*
     270                 * SQLite < 3.2.0 doesn't support ALTER TABLE ADD COLUMN
     271                 * Unfortunately, Tiger ships with SQLite < 3.2.0 (#34463)
     272                 * This is taken from http://www.sqlite.org/faq.html#q11
     273                 */
     274
     275                /* Create a temporary table */
     276                "CREATE TEMPORARY TABLE mp_files_backup (id INTEGER, path TEXT, "
     277                    "actual_path TEXT, active INT, mtime DATETIME, md5sum TEXT, editable INT, "
     278                    "FOREIGN KEY(id) REFERENCES ports(id))",
     279
     280                /* Copy all data into the temporary table */
     281                "INSERT INTO mp_files_backup SELECT id, path, actual_path, active, mtime, "
     282                    "md5sum, editable FROM registry.files",
     283
     284                /* Drop the original table and re-create it with the new structure */
     285                "DROP TABLE registry.files",
     286                "CREATE TABLE registry.files (id INTEGER, path TEXT, actual_path TEXT, "
     287                    "active INT, mtime DATETIME, md5sum TEXT, editable INT, binary BOOL, "
     288                    "FOREIGN KEY(id) REFERENCES ports(id))",
     289                "CREATE INDEX registry.file_port ON files(id)",
     290                "CREATE INDEX registry.file_path ON files(path)",
     291                "CREATE INDEX registry.file_actual ON files(actual_path)",
     292
     293                /* Copy all data back from temporary table */
     294                "INSERT INTO registry.files (id, path, actual_path, active, mtime, md5sum, "
     295                    "editable) SELECT id, path, actual_path, active, mtime, md5sum, "
     296                    "editable FROM mp_files_backup",
     297
     298                /* Remove temporary table */
     299                "DROP TABLE mp_files_backup",
     300#endif
     301                "CREATE INDEX registry.file_binary ON files(binary)",
     302
     303                "UPDATE registry.metadata SET value = '1.100' WHERE key = 'version'",
     304
     305                "COMMIT",
     306                NULL
     307            };
     308
     309            /* don't forget to finalize the version query here, or it might
     310             * cause "cannot commit transaction - SQL statements in progress",
     311             * see #32686 */
     312            sqlite3_finalize(stmt);
     313            stmt = NULL;
     314
     315            if (!do_queries(db, version_1_1_queries, errPtr)) {
     316                rollback_db(db);
     317                return 0;
     318            }
     319
     320            did_update = 1;
     321            continue;
     322        }
     323
     324        /* add new versions here, but remember to:
     325         *  - finalize the version query statement and set stmt to NULL
     326         *  - do _not_ use "BEGIN" in your query list, since a transaction has
     327         *    already been started for you
     328         *  - end your query list with "COMMIT", NULL
     329         *  - set did_update = 1 and continue;
     330         */
     331
     332        /* if we arrive here, no update was done and we should end the
     333         * transaction. Using ROLLBACK here causes problems when rolling back
     334         * other transactions later in the program. */
     335        sqlite3_finalize(stmt);
     336        stmt = NULL;
     337        r = sqlite3_exec(db, "COMMIT", NULL, NULL, NULL);
     338    } while (did_update);
     339
    194340    sqlite3_finalize(stmt);
    195     return 1;
    196 
    197 reg_err_out:
    198     reg_sqlite_error(db, errPtr, query);
    199 err_out:
    200     sqlite3_finalize(stmt);
    201     return 0;
     341    switch (r) {
     342        case SQLITE_OK:
     343        case SQLITE_DONE:
     344        case SQLITE_ROW:
     345            return 1;
     346        default:
     347            reg_sqlite_error(db, errPtr, query);
     348            return 0;
     349    }
    202350}
    203351
  • branches/gsoc11-statistics/base/src/cregistry/sql.h

    r88412 r105085  
    44 *
    55 * Copyright (c) 2007 Chris Pickel <sfiera@macports.org>
     6 * Copyright (c) 2012 The MacPorts Project
    67 * All rights reserved.
    78 *
  • branches/gsoc11-statistics/base/src/cregistry/util.c

    r88412 r105085  
    55 *
    66 * Copyright (c) 2007 Chris Pickel <sfiera@macports.org>
     7 * Copyright (c) 2012 The MacPorts Project
    78 * All rights reserved.
    89 *
     
    123124 * @param [out] objects  the objects selected
    124125 * @param [in] fn        a function to convert sqlite3_stmts to the desired type
     126 * @param [inout] data   data passed along to the cast function
    125127 * @param [in] del       a function to delete the desired type of object
    126128 * @param [out] errPtr   on error, a description of the error that occurred
     
    137139        return -1;
    138140    }
    139     if (sqlite3_prepare(reg->db, query, query_len, &stmt, NULL) == SQLITE_OK) {
     141    if (sqlite3_prepare_v2(reg->db, query, query_len, &stmt, NULL) == SQLITE_OK) {
    140142        int r;
    141143        void* row;
  • branches/gsoc11-statistics/base/src/darwintracelib1.0/darwintrace.c

    r82923 r105085  
    6060#endif
    6161
     62#include <dirent.h>
     63#include <dlfcn.h>
     64#include <errno.h>
    6265#include <fcntl.h>
    6366#include <stdarg.h>
     
    6568#include <stdlib.h>
    6669#include <string.h>
     70#include <sys/param.h>
     71#include <sys/socket.h>
     72#include <sys/stat.h>
     73#include <sys/syscall.h>
     74#include <sys/types.h>
     75#include <sys/un.h>
    6776#include <unistd.h>
    68 #include <sys/types.h>
    69 #include <sys/stat.h>
    70 #include <sys/param.h>
    71 #include <sys/syscall.h>
    72 #include <errno.h>
    73 #include <sys/socket.h>
    74 #include <sys/un.h>
    7577
    7678#ifndef HAVE_STRLCPY
     
    139141inline char* __darwintrace_alloc_env(const char* varName, const char* varValue);
    140142inline char* const* __darwintrace_restore_env(char* const envp[]);
    141 inline void __darwintrace_setup();
     143static inline void __darwintrace_setup();
    142144inline void __darwintrace_cleanup_path(char *path);
    143 static char * exchange_with_port(const char * buf, size_t len, int answer, char failures);
    144 
    145 #define START_FD 81
    146 static int __darwintrace_fd = -1;
     145static char * exchange_with_port(const char * buf, size_t len, int answer);
     146
     147static int __darwintrace_fd = -2;
     148static FILE *__darwintrace_debug = NULL;
     149static pid_t __darwintrace_pid = (pid_t) -1;
    147150#define BUFFER_SIZE     1024
    148151
     
    161164static char* __env_dyld_force_flat_namespace;
    162165static char* __env_darwintrace_log;
    163 
     166static char* __env_darwintrace_debug_log;
     167
     168#if DARWINTRACE_DEBUG_OUTPUT
    164169#if __STDC_VERSION__>=199901L
    165 #if DARWINTRACE_DEBUG_OUTPUT
    166 #define debug_printf(...) fprintf(stderr, __VA_ARGS__)
     170#define debug_printf(format, ...) fprintf(stderr, "darwintrace[%d]: " format, getpid(), __VA_ARGS__); \
     171        if (__darwintrace_debug) { \
     172                fprintf(__darwintrace_debug, "darwintrace: " format, __VA_ARGS__); \
     173        }
    167174#else
    168 #define debug_printf(...)
    169 #endif
    170 #else
    171 #if DARWINTRACE_DEBUG_OUTPUT
    172175__attribute__ ((format (printf, 1, 2)))
    173176static inline
     
    180183    return ret;
    181184}
     185#endif
    182186#else
    183 #define debug_printf(format, param)
    184 #endif
    185 #endif
    186 
    187 /*
    188  * char wait_for_socket(int sock, char w)
    189  * Function used for read/write operation to socket...
    190  * Args:
    191  *  sock - socket
    192  *  w - what should socket do in next operation. 1 for write, 0 for read
    193  * Return value:
    194  *  1 - everything is ok, we can read/write to/from it
    195  *  0 - something's went wrong
    196  */
    197 static int wait_for_socket(int sock, char w)
    198 {
    199         struct timeval tv;
    200         fd_set fds;
    201        
    202         if(sock==-1)
    203                 return 0;
    204        
    205         tv.tv_sec=10;
    206         tv.tv_usec=0;
    207         FD_ZERO(&fds);
    208         FD_SET(sock, &fds);
    209         if(select(sock+1, (w==0 ? &fds : 0), (w==1 ? &fds : 0), 0, &tv)<1)
    210                 return 0;
    211         return FD_ISSET(sock, &fds)!=0;
    212 }
    213 
     187#define debug_printf(...)
     188#endif
    214189
    215190/*
     
    248223        } else {
    249224                __env_darwintrace_log = NULL;
     225        }
     226        theValue = getenv("DARWINTRACE_DEBUG_LOG");
     227        if (theValue != NULL) {
     228                __env_darwintrace_debug_log = strdup(theValue);
     229        } else {
     230                __env_darwintrace_debug_log = NULL;
    250231        }
    251232}
     
    292273                        "DARWINTRACE_LOG",
    293274                        __env_darwintrace_log);
     275        char* darwintrace_debug_log_ptr =       
     276                __darwintrace_alloc_env(
     277                        "DARWINTRACE_DEBUG_LOG",
     278                        __env_darwintrace_debug_log);
    294279
    295280        char* const * theEnvIter = envp;
     
    319304                        theValue = darwintrace_log_ptr;
    320305                        darwintrace_log_ptr = NULL;
     306                } else if (__darwintrace_strbeginswith(theValue, "DARWINTRACE_DEBUG_LOG=")) {
     307                        theValue = darwintrace_debug_log_ptr;
     308                        darwintrace_debug_log_ptr = NULL;
    321309                }
    322310               
     
    337325                *theCopyIter++ = darwintrace_log_ptr;
    338326        }
     327        if (darwintrace_debug_log_ptr) {
     328                *theCopyIter++ = darwintrace_debug_log_ptr;
     329        }
    339330
    340331        *theCopyIter = 0;
     
    345336static void ask_for_filemap()
    346337{
    347         filemap=exchange_with_port("filemap\t", sizeof("filemap\t"), 1, 0);
     338        filemap=exchange_with_port("filemap\t", sizeof("filemap\t"), 1);
    348339        if(filemap==(char*)-1)
    349340                filemap=0;
     
    351342
    352343__attribute__((always_inline))
    353 inline void __darwintrace_setup() {
     344static inline void __darwintrace_setup() {
    354345#define open(x,y,z) syscall(SYS_open, (x), (y), (z))
    355346#define close(x) syscall(SYS_close, (x))
    356         if (__darwintrace_fd == -1) {
     347        pid_t oldpid = __darwintrace_pid;
     348        if (__darwintrace_pid != (pid_t) -1 && __darwintrace_pid != getpid()) {
     349                if (__darwintrace_fd != -2) {
     350                        close(__darwintrace_fd);
     351                        __darwintrace_fd = -2;
     352                }
     353                if (__darwintrace_debug) {
     354                        fclose(__darwintrace_debug);
     355                        __darwintrace_debug = NULL;
     356                }
     357                __darwintrace_pid = (pid_t) -1;
     358        }
     359        if (__darwintrace_pid == (pid_t) -1) {
     360                __darwintrace_pid = getpid();
    357361                if (__env_darwintrace_log != NULL) {
    358362                        int olderrno = errno;
    359                         int sock=socket(AF_UNIX, SOCK_STREAM, 0);
     363                        int sock = socket(AF_UNIX, SOCK_STREAM, 0);
    360364                        struct sockaddr_un sun;
    361                         sun.sun_family=AF_UNIX;
     365                        sun.sun_family = AF_UNIX;
    362366                        strncpy(sun.sun_path, __env_darwintrace_log, sizeof(sun.sun_path));
    363                         if(connect(sock, (struct sockaddr*)&sun, strlen(__env_darwintrace_log)+1+sizeof(sun.sun_family))!=-1)
    364                         {
    365                                 debug_printf("darwintrace: connect successful. socket %d\n", sock);
    366                                 __darwintrace_fd=sock;
     367                        if (connect(sock, (struct sockaddr*)&sun, strlen(__env_darwintrace_log) + 1 + sizeof(sun.sun_family)) != -1) {
     368                                debug_printf("connect successful, socket %d in pid %d\n", sock, __darwintrace_pid);
     369                                __darwintrace_fd = sock;
    367370                                ask_for_filemap();
    368371                        } else {
     
    372375                        errno = olderrno;
    373376                }
     377                if (__darwintrace_debug == NULL) {
     378                        if (__env_darwintrace_debug_log != NULL) {
     379                                char logpath[MAXPATHLEN];
     380                                snprintf(logpath, MAXPATHLEN, __env_darwintrace_debug_log, getpid());
     381                                if (NULL == (__darwintrace_debug = fopen(logpath, "w"))) {
     382                                        fprintf(stderr, "failed to open logfile: %s\n", strerror(errno));
     383                                        abort();
     384                                }
     385                                fprintf(__darwintrace_debug, "pid %d is process %s\n", getpid(), getenv("_"));
     386                                debug_printf("logging socket communication to: %s\n", logpath);
     387                        }
     388                }
     389                if (oldpid != (pid_t) -1) {
     390                        debug_printf("seems to have forked from %d, re-opened files\n", oldpid);
     391                }
    374392        }
    375393#undef close
     
    387405        char somepath[MAXPATHLEN];
    388406        char logbuffer[BUFFER_SIZE];
    389        
     407
    390408        do {
    391409#ifdef __APPLE__ /* Only Darwin has volfs and F_GETPATH */
     
    417435        size = snprintf(logbuffer, sizeof(logbuffer),
    418436                "%s\t%s",
    419                 op, somepath );
    420 
    421         exchange_with_port(logbuffer, size+1, 0, 0);
     437                op, somepath);
     438
     439        exchange_with_port(logbuffer, size+1, 0);
    422440       
    423441        return;
     
    428446 */
    429447inline void __darwintrace_cleanup_path(char *path) {
    430   size_t pathlen;
     448        size_t pathlen;
    431449#ifdef __APPLE__
    432   size_t rsrclen;
    433 #endif
    434   size_t i, shiftamount;
    435   enum { SAWSLASH, NOTHING } state = NOTHING;
    436 
    437   /* if this is a foo/..namedfork/rsrc, strip it off */
    438   pathlen = strlen(path);
    439   /* ..namedfork/rsrc is only on OS X */
    440 #ifdef __APPLE__
    441   rsrclen = strlen(_PATH_RSRCFORKSPEC);
    442   if(pathlen > rsrclen
    443      && 0 == strcmp(path + pathlen - rsrclen,
    444                     _PATH_RSRCFORKSPEC)) {
    445     path[pathlen - rsrclen] = '\0';
    446     pathlen -= rsrclen;
    447   }
    448 #endif
    449 
    450   /* for each position in string (including
    451      terminal \0), check if we're in a run of
    452      multiple slashes, and only emit the
    453      first one
    454   */
    455   for(i=0, shiftamount=0; i <= pathlen; i++) {
    456     if(state == SAWSLASH) {
    457       if(path[i] == '/') {
    458         /* consume it */
    459         shiftamount++;
    460       } else {
    461         state = NOTHING;
    462         path[i - shiftamount] = path[i];
    463       }
    464     } else {
    465       if(path[i] == '/') {
    466         state = SAWSLASH;
    467       }
    468       path[i - shiftamount] = path[i];
    469     }
    470   }
    471 
    472   debug_printf("darwintrace: cleanup resulted in %s\n", path);
    473 }
    474 
    475 /*
    476  * return 1 if path is directory or not exists
    477  * return 0 otherwise
    478  */
    479 static int is_directory(const char * path)
    480 {
    481 #define stat(path, sb) syscall(SYS_stat, path, sb)
    482         struct stat s;
    483         if(stat(path, &s)==-1)
    484                 /* Actually is not directory, but anyway, we shouldn't test a dependency unless file exists */
    485                 return 1;
    486        
    487         return S_ISDIR(s.st_mode);
    488 #undef stat
    489 }
    490 
     450        size_t rsrclen;
     451#endif
     452        size_t i, shiftamount;
     453        enum { SAWSLASH, NOTHING } state = NOTHING;
     454
     455        /* if this is a foo/..namedfork/rsrc, strip it off */
     456        pathlen = strlen(path);
     457        /* ..namedfork/rsrc is only on OS X */
     458#ifdef __APPLE__
     459        rsrclen = strlen(_PATH_RSRCFORKSPEC);
     460        if (pathlen > rsrclen && 0 == strcmp(path + pathlen - rsrclen, _PATH_RSRCFORKSPEC)) {
     461                path[pathlen - rsrclen] = '\0';
     462                pathlen -= rsrclen;
     463        }
     464#endif
     465
     466        /* for each position in string (including terminal \0), check if we're in
     467         * a run of multiple slashes, and only emit the first one */
     468        for(i = 0, shiftamount = 0; i <= pathlen; i++) {
     469                if (state == SAWSLASH) {
     470                        if (path[i] == '/') {
     471                                /* consume it */
     472                                shiftamount++;
     473                                continue;
     474                        } else {
     475                                state = NOTHING;
     476                        }
     477                } else {
     478                        if (path[i] == '/') {
     479                                state = SAWSLASH;
     480                        }
     481                }
     482                path[i - shiftamount] = path[i];
     483        }
     484}
    491485
    492486/*
    493487 * return 1 if path allowed, 0 otherwise
    494488 */
    495 static int ask_for_dependency(char * path)
    496 {
     489static int ask_for_dependency(char * path) {
     490#define stat(y, z) syscall(SYS_stat, (y), (z))
    497491        char buffer[BUFFER_SIZE], *p;
    498         int result=0;
    499        
    500         if(is_directory(path))
     492        int result = 0;
     493        struct stat st;
     494
     495        debug_printf("ask_for_dependency: %s\n", path);
     496
     497        if (-1 == stat(path, &st)) {
    501498                return 1;
     499        }
     500        if (S_ISDIR(st.st_mode)) {
     501                debug_printf("%s is directory\n", path);
     502                return 1;
     503        }
    502504       
    503505        strncpy(buffer, "dep_check\t", sizeof(buffer));
    504506        strncpy(buffer+10, path, sizeof(buffer)-10);
    505         p=exchange_with_port(buffer, strlen(buffer)+1, 1, 0);
     507        p=exchange_with_port(buffer, strlen(buffer)+1, 1);
    506508        if(p==(char*)-1||!p)
    507509                return 0;
     
    512514        free(p);
    513515        return result;
     516#undef stat
    514517}
    515518
     
    526529 *    string -- answer (caller shoud free it)
    527530 */
    528 static char * exchange_with_port(const char * buf, size_t len, int answer, char failures)
    529 {
    530         wait_for_socket(__darwintrace_fd, 1);
    531         if(send(__darwintrace_fd, buf, len, 0)==-1)
    532         {
    533                 if(errno==ENOTSOCK && failures<3)
    534                 {
    535                         __darwintrace_fd=-1;
    536                         __darwintrace_setup();
    537                         return exchange_with_port(buf, len, answer, failures+1);
    538                 }
    539                 return (char*)-1;
    540         }
    541         if(!answer)
     531static char * exchange_with_port(const char * buf, size_t len, int answer) {
     532        size_t sent = 0;
     533
     534        if (__darwintrace_debug) {
     535                fprintf(__darwintrace_debug, "> %s\n", buf);
     536        }
     537        while (sent < len) {
     538                ssize_t local_sent = send(__darwintrace_fd, buf + sent, len - sent, 0);
     539                if (local_sent == -1) {
     540                        debug_printf("error communicating with socket %d: %s\n", __darwintrace_fd, strerror(errno));
     541                        if (__darwintrace_debug)
     542                                fprintf(__darwintrace_debug, "darwintrace: error communicating with socket %d: %s\n", __darwintrace_fd, strerror(errno));
     543                        abort();
     544                }
     545                sent += local_sent;
     546        }
     547        if (!answer) {
    542548                return 0;
    543         {
    544                 size_t l=0;
    545                 char * b;
     549        } else {
     550                size_t recv_len = 0, received;
     551                char *recv_buf;
    546552               
    547                 wait_for_socket(__darwintrace_fd, 0);
    548                 recv(__darwintrace_fd, &l, sizeof(l),0);
    549                 if(!l)
     553                received = 0;
     554                while (received < sizeof(recv_len)) {
     555                        ssize_t local_received = recv(__darwintrace_fd, ((char *) &recv_len) + received, sizeof(recv_len) - received, 0);
     556                        if (local_received == -1) {
     557                                debug_printf("error reading data from socket %d: %s\n", __darwintrace_fd, strerror(errno));
     558                                if (__darwintrace_debug)
     559                                        fprintf(__darwintrace_debug, "darwintrace: error reading data from socket %d: %s\n", __darwintrace_fd, strerror(errno));
     560                                abort();
     561                        }
     562                        received += local_received;
     563                }
     564                if (recv_len == 0) {
    550565                        return 0;
    551                 b=(char*)malloc(l+1);
    552                 b[l]=0;
    553                 recv(__darwintrace_fd, b, l, 0);
    554                 return b;
    555         }
    556 }
     566                }
     567
     568                recv_buf = malloc(recv_len + 1);
     569                recv_buf[recv_len] = '\0';
     570
     571                received = 0;
     572                while (received < recv_len) {
     573                        ssize_t local_received = recv(__darwintrace_fd, recv_buf + received, recv_len - received, 0);
     574                        if (local_received == -1) {
     575                                debug_printf("error reading data from socket %d: %s\n", __darwintrace_fd, strerror(errno));
     576                                if (__darwintrace_debug)
     577                                        fprintf(__darwintrace_debug, "darwintrace: error reading data from socket %d: %s\n", __darwintrace_fd, strerror(errno));
     578                                abort();
     579                        }
     580                        received += local_received;
     581                }
     582                if (__darwintrace_debug) {
     583                        fprintf(__darwintrace_debug, "< %s\n", recv_buf);
     584                }
     585                return recv_buf;
     586        }
     587}
     588
     589#define DARWINTRACE_STATUS_PATH    ((char) 0)
     590#define DARWINTRACE_STATUS_COMMAND ((char) 1)
     591#define DARWINTRACE_STATUS_DONE    ((char) 2)
    557592
    558593/*
     
    561596__attribute__((always_inline))
    562597inline int __darwintrace_is_in_sandbox(const char* path, char * newpath) {
    563         char * t, * p, * _;
    564         int result=-1;
     598        char *t, *p, *_;
     599        char lpath[MAXPATHLEN];
    565600       
    566601        __darwintrace_setup();
    567602       
    568         if(!filemap)
     603        if (!filemap)
    569604                return 1;
    570605       
    571         if(*path=='/')
    572                 p=strdup(path);
    573         else
    574         {
    575                 p=(char*)malloc(MAXPATHLEN);
    576                 if (getcwd(p, MAXPATHLEN-1) == NULL) {
     606        if (*path=='/') {
     607                p = strcpy(lpath, path);
     608        } else {
     609                if (getcwd(lpath, MAXPATHLEN - 1) == NULL) {
    577610                        fprintf(stderr, "darwintrace: getcwd: %s, path was: %s\n", strerror(errno), path);
    578611                        abort();
    579612                }
    580                 if (p[strlen(p)-1] != '/')
    581                         strcat(p, "/");
    582                 strcat(p, path);
    583         }
    584         __darwintrace_cleanup_path(p);
    585                        
    586         do
    587         {
    588                 for(t=filemap; *t;)
    589                 {
    590                         if(__darwintrace_strbeginswith(p, t))
    591                         {
    592                                 t+=strlen(t)+1;
    593                                 switch(*t)
    594                                 {
     613                strcat(lpath, "/");
     614                strcat(lpath, path);
     615        }
     616
     617        p = lpath;
     618
     619        for (t = filemap; *t;) {
     620                char state;
     621               
     622                if (__darwintrace_strbeginswith(p, t)) {
     623                        /* move t to the integer describing how to handle this match */
     624                        t += strlen(t) + 1;
     625                        switch (*t) {
    595626                                case 0:
    596                                         result=1;
     627                                        return 1;
     628                                case 1:
     629                                        if (!newpath) {
     630                                                return 0;
     631                                        }
     632                                        /* the redirected path starts right after the byte telling
     633                                         * us we should redirect */
     634                                        strcpy(newpath, t + 1);
     635                                        _ = newpath + strlen(newpath);
     636                                        /* append '/' if it's missing */
     637                                        if (_[-1] != '/') {
     638                                                *_ = '/';
     639                                        }
     640                                        strcpy(_, p);
     641                                        return 1;
     642                                case 2:
     643                                        /* ask the socket whether this file is OK */
     644                                        return ask_for_dependency(p);
     645                                default:
     646                                        fprintf(stderr, "darwintrace: error: unexpected byte in file map: `%x'\n", *t);
     647                                        abort();
     648                        }
     649                }
     650
     651                /* advance the cursor: if the number after the string is not 1, there's
     652                 * no path behind it and we can advance by strlen(t) + 3. If it is 1,
     653                 * make sure to skip the path, too.
     654                 */
     655                state = DARWINTRACE_STATUS_PATH;
     656                while (state != DARWINTRACE_STATUS_DONE) {
     657                        switch (state) {
     658                                case DARWINTRACE_STATUS_PATH:
     659                                        if (!*t) {
     660                                                state = DARWINTRACE_STATUS_COMMAND;
     661                                        }
    597662                                        break;
    598                                 case 1:
    599                                         if(!newpath)
    600                                         {
    601                                                 result=0;
    602                                                 break;
     663                                case DARWINTRACE_STATUS_COMMAND:
     664                                        if (*t == 1) {
     665                                                state = DARWINTRACE_STATUS_PATH;
     666                                                t++;
     667                                        } else {
     668                                                state = DARWINTRACE_STATUS_DONE;
    603669                                        }
    604                                         strcpy(newpath, t+1);
    605                                         _=newpath+strlen(newpath);
    606                                         if(_[-1]!='/')
    607                                                 *_++='/';
    608                                         strcpy(_, p);
    609                                         result=1;
    610670                                        break;
    611                                 case 2:
    612                                         result=ask_for_dependency(p);
    613                                         break;
    614                                 }
    615671                        }
    616                         if(result!=-1)
    617                                 break;
    618                         t+=strlen(t)+1;
    619                         if(*t==1)
    620                                 t+=strlen(t)+1;
    621                         else
    622                                 t+=2;
    623                 }
    624                 if(result!=-1)
    625                         break;
    626                 __darwintrace_log_op("sandbox_violation", path, 0);
    627                 result=0;
    628         }
    629         while(0);
    630         free(p);
    631         return result;
    632 }
    633 
    634 /* Log calls to open(2) into the file specified by DARWINTRACE_LOG.
    635    Only logs if the DARWINTRACE_LOG environment variable is set.
    636    Only logs files (or rather, do not logs directories)
    637    Only logs files where the open succeeds.
    638    Only logs files opened for read access, without the O_CREAT flag set
    639         (unless DARWINTRACE_LOG_CREATE is set).
    640    The assumption is that any file that can be created isn't necessary
    641    to build the project.
    642 */
    643 
     672                        t++;
     673                }
     674                t++;
     675        }
     676
     677        __darwintrace_log_op("sandbox_violation", path, 0);
     678        return 0;
     679}
     680
     681/* wrapper for open(2) preventing opening files outside the sandbox */
    644682int open(const char* path, int flags, ...) {
    645683#define open(x,y,z) syscall(SYS_open, (x), (y), (z))
    646684        mode_t mode;
    647         int result;
    648685        va_list args;
    649         struct stat sb;
    650686        char newpath[MAXPATHLEN];
    651         int isInSandbox;       
     687
     688        debug_printf("open(%s)\n", path);
     689
     690        *newpath = '\0';
     691        if (!__darwintrace_is_in_sandbox(path, newpath)) {
     692                debug_printf("open %s was forbidden\n", path);
     693                errno = ((flags & O_CREAT) > 0) ? EACCES : ENOENT;
     694                return -1;
     695        }
     696
     697        if (*newpath) {
     698                path = newpath;
     699        }
    652700
    653701        /* Why mode here ? */
     
    655703        mode = va_arg(args, int);
    656704        va_end(args);
    657        
    658         result = 0;
    659        
    660         if((stat(path, &sb)!=-1 && !(sb.st_mode&S_IFDIR)) || flags & O_CREAT )
    661         {
    662                 *newpath=0;
    663                 __darwintrace_setup();
    664                 isInSandbox = __darwintrace_is_in_sandbox(path, newpath);
    665                 if (isInSandbox == 0) {
    666                         debug_printf("darwintrace: creation/writing was forbidden at %s\n", path);
    667                         errno = EACCES;
    668                         result = -1;
    669                 }
    670                 if(*newpath)
    671                         path=newpath;
    672         }
    673         if (result == 0) {
    674                 result = open(path, flags, mode);
    675         }
    676         return result;
     705
     706        return open(path, flags, mode);
    677707#undef open
    678708}
     
    683713*/
    684714#ifdef READLINK_IS_NOT_P1003_1A
    685 int  readlink(const char * path, char * buf, int bufsiz) {
     715int readlink(const char * path, char * buf, int bufsiz) {
    686716#else
    687 ssize_t  readlink(const char * path, char * buf, size_t bufsiz) {
     717ssize_t readlink(const char * path, char * buf, size_t bufsiz) {
    688718#endif
    689719#define readlink(x,y,z) syscall(SYS_readlink, (x), (y), (z))
    690         ssize_t result;
    691         int isInSandbox;
    692 
    693         result = readlink(path, buf, bufsiz);
    694         if (result >= 0) {
    695                 __darwintrace_setup();
    696                 isInSandbox = __darwintrace_is_in_sandbox(path, 0);
    697                 if (!isInSandbox)
    698                 {
    699                         errno=EACCES;
    700                         result=-1;
    701                 }
    702         }
    703         return result;
     720        char newpath[MAXPATHLEN];
     721
     722        debug_printf("readlink(%s)\n", path);
     723
     724        *newpath = '\0';
     725        if (!__darwintrace_is_in_sandbox(path, newpath)) {
     726                errno = ENOENT;
     727                return -1;
     728        }
     729
     730        if (*newpath) {
     731                path = newpath;
     732        }
     733
     734        return readlink(path, buf, bufsiz);
    704735#undef readlink
    705736}
     
    710741#define close(x) syscall(SYS_close, (x))
    711742#define lstat(x, y) syscall(SYS_lstat, (x), (y))
    712         int result;
     743        debug_printf("execve(%s)\n", path);
    713744        __darwintrace_setup();
    714745        if (__darwintrace_fd >= 0) {
    715           struct stat sb;
    716           /* for symlinks, we want to capture
    717            * both the original path and the modified one,
    718            * since for /usr/bin/gcc -> gcc-4.0,
    719            * both "gcc_select" and "gcc" are contributors
    720            */
    721           if (lstat(path, &sb) == 0) {
    722                 int fd;
    723 
    724             if(S_ISLNK(sb.st_mode)) {
    725               /* for symlinks, print both */
    726                   __darwintrace_log_op("execve", path, 0);
    727             }
    728                
    729                 fd = open(path, O_RDONLY, 0);
    730                 if (fd > 0) {
    731                   char buffer[MAXPATHLEN+1], newpath[MAXPATHLEN+1];
    732                   ssize_t bytes_read;
    733                
    734                   *newpath=0;
    735                   if(__darwintrace_is_in_sandbox(path, newpath)==0)
    736                   {
    737                         close(fd);
    738                         errno=ENOENT;
    739                     return -1;
    740                   }
    741                   if(*newpath)
    742                     path=newpath;
     746                struct stat sb;
     747                /* for symlinks, we want to capture both the original path and the
     748                 * modified one, since for /usr/bin/gcc -> gcc-4.0, both "gcc_select"
     749                 * and "gcc" are contributors
     750                 */
     751                if (lstat(path, &sb) == 0) {
     752                        int fd;
     753                        if (S_ISLNK(sb.st_mode)) {
     754                                /* for symlinks, print both */
     755                                __darwintrace_log_op("execve", path, 0);
     756                        }
     757
     758                        fd = open(path, O_RDONLY, 0);
     759                        if (fd > 0) {
     760                                char buffer[MAXPATHLEN+1];
     761                                ssize_t bytes_read;
     762
     763                                if(!__darwintrace_is_in_sandbox(path, NULL)) {
     764                                        close(fd);
     765                                        errno = ENOENT;
     766                                        return -1;
     767                                }
    743768       
    744                   /* once we have an open fd, if a full path was requested, do it */
    745                   __darwintrace_log_op("execve", path, fd);
    746 
    747                   /* read the file for the interpreter */
    748                   bytes_read = read(fd, buffer, MAXPATHLEN);
    749                   buffer[bytes_read] = 0;
    750                   if (bytes_read > 2 &&
    751                         buffer[0] == '#' && buffer[1] == '!') {
    752                         const char* interp = &buffer[2];
    753                         int i;
    754                         /* skip past leading whitespace */
    755                         for (i = 2; i < bytes_read; ++i) {
    756                           if (buffer[i] != ' ' && buffer[i] != '\t') {
    757                                 interp = &buffer[i];
    758                                 break;
    759                           }
     769                                /* once we have an open fd, if a full path was requested, do it */
     770                                __darwintrace_log_op("execve", path, fd);
     771       
     772                                /* read the file for the interpreter */
     773                                bytes_read = read(fd, buffer, MAXPATHLEN);
     774                                buffer[bytes_read] = 0;
     775                                if (bytes_read > 2 && buffer[0] == '#' && buffer[1] == '!') {
     776                                        const char* interp = &buffer[2];
     777                                        int i;
     778                                        /* skip past leading whitespace */
     779                                        for (i = 2; i < bytes_read; ++i) {
     780                                                if (buffer[i] != ' ' && buffer[i] != '\t') {
     781                                                        interp = &buffer[i];
     782                                                        break;
     783                                                }
     784                                        }
     785                                        /* found interpreter (or ran out of data); skip until next
     786                                         * whitespace, then terminate the string */
     787                                        for (; i < bytes_read; ++i) {
     788                                                if (buffer[i] == ' ' || buffer[i] == '\t' || buffer[i] == '\n') {
     789                                                        buffer[i] = 0;
     790                                                        break;
     791                                                }
     792                                        }
     793                                        /* we have liftoff */
     794                                        if (interp && interp[0] != '\0') {
     795                                                __darwintrace_log_op("execve", interp, 0);
     796                                        }
     797                                }
     798                                close(fd);
    760799                        }
    761                         /* found interpreter (or ran out of data)
    762                            skip until next whitespace, then terminate the string */
    763                         for (; i < bytes_read; ++i) {
    764                           if (buffer[i] == ' ' || buffer[i] == '\t' || buffer[i] == '\n') {
    765                                 buffer[i] = 0;
    766                                 break;
    767                           }
    768                         }
    769                         /* we have liftoff */
    770                         if (interp && interp[0] != '\0') {
    771                           __darwintrace_log_op("execve", interp, 0);
    772                         }
    773                   }
    774                   close(fd);
    775                 }
    776           }
    777         close(__darwintrace_fd);
    778         __darwintrace_fd=-1;
    779         }
    780        
     800                }
     801        }
     802        /* our variables won't survive exec, clean up */
     803        if (__darwintrace_fd != -2) {
     804                close(__darwintrace_fd);
     805                __darwintrace_fd = -2;
     806        }
     807        if (__darwintrace_debug) {
     808                fclose(__darwintrace_debug);
     809                __darwintrace_debug = NULL;
     810        }
     811        __darwintrace_pid = (pid_t) -1;
     812
    781813        /* call the original execve function, but fix the environment if required. */
    782         result = __execve(path, argv, __darwintrace_restore_env(envp));
    783         return result;
     814        return __execve(path, argv, __darwintrace_restore_env(envp));
    784815#undef lstat
    785816#undef close
     
    788819}
    789820
    790 /* if darwintrace has been initialized, trap
    791    attempts to close our file descriptor
    792 */
     821/* if darwintrace has been initialized, trap attempts to close our file
     822 * descriptor */
    793823int close(int fd) {
    794824#define close(x) syscall(SYS_close, (x))
    795 
    796   if(__darwintrace_fd != -2 && fd == __darwintrace_fd) {
    797     errno = EBADF;
    798     return -1;
    799   }
    800 
    801   return close(fd);
     825        if (__darwintrace_fd != -2 && fd == __darwintrace_fd) {
     826                errno = EBADF;
     827                return -1;
     828        }
     829
     830        return close(fd);
    802831#undef close
    803832}
    804833
    805 /* Trap attempts to unlink a file outside the sandbox.
    806  */
     834/* if darwintrace has been initialized, trap attempts to dup2 over our file descriptor */
     835int dup2(int filedes, int filedes2) {
     836#define dup2(x, y) syscall(SYS_dup2, (x), (y))
     837
     838        debug_printf("dup2(%d, %d)\n", filedes, filedes2);
     839        if (__darwintrace_fd != -2 && filedes2 == __darwintrace_fd) {
     840                /* if somebody tries to close our file descriptor, just move it out of
     841                 * the way. Make sure it doesn't end up as stdin/stdout/stderr, though!
     842                 * */
     843                int new_darwintrace_fd;
     844
     845                if (-1 == (new_darwintrace_fd = fcntl(__darwintrace_fd, F_DUPFD, STDOUT_FILENO + 1))) {
     846                        /* if duplicating fails, do not allow overwriting either! */
     847                        return -1;
     848                }
     849
     850                debug_printf("moving __darwintrace_fd from %d to %d\n", __darwintrace_fd, new_darwintrace_fd);
     851                __darwintrace_fd = new_darwintrace_fd;
     852        }
     853
     854        return dup2(filedes, filedes2);
     855#undef dup2
     856}
     857
     858
     859/* Trap attempts to unlink a file outside the sandbox. */
    807860int unlink(const char* path) {
    808861#define __unlink(x) syscall(SYS_unlink, (x))
    809         int result = 0;
    810         int isInSandbox = __darwintrace_is_in_sandbox(path, 0);
    811         if (isInSandbox == 1) {
    812                 debug_printf("darwintrace: unlink was allowed at %s\n", path);
    813         } else if (isInSandbox == 0) {
    814                 /* outside sandbox, but sandbox is defined: forbid */
    815                 debug_printf("darwintrace: unlink was forbidden at %s\n", path);
    816                 errno = EACCES;
    817                 result = -1;
    818         }
    819        
    820         if (result == 0) {
    821                 result = __unlink(path);
    822         }
    823        
    824         return result;
     862        char newpath[MAXPATHLEN];
     863
     864        *newpath = '\0';
     865        if (!__darwintrace_is_in_sandbox(path, newpath)) {
     866                debug_printf("unlink %s was forbidden\n", path);
     867                errno = ENOENT;
     868                return -1;
     869        }
     870
     871        if (*newpath) {
     872                path = newpath;
     873        }
     874
     875        debug_printf("unlink %s was allowed\n", path);
     876
     877        return __unlink(path);
    825878}
    826879
     
    829882int mkdir(const char* path, mode_t mode) {
    830883#define __mkdir(x,y) syscall(SYS_mkdir, (x), (y))
    831         int result = 0;
    832         int isInSandbox = __darwintrace_is_in_sandbox(path, 0);
    833         if (isInSandbox == 1) {
    834                 debug_printf("darwintrace: mkdir was allowed at %s\n", path);
    835         } else if (isInSandbox == 0) {
    836                 /* outside sandbox, but sandbox is defined: forbid */
    837                 /* only consider directories that do not exist. */
    838                 struct stat theInfo;
    839                 int err;
    840                 err = lstat(path, &theInfo);
    841                 if ((err == -1) && (errno == ENOENT))
    842                 {
    843                         debug_printf("darwintrace: mkdir was forbidden at %s\n", path);
    844                         errno = EACCES;
    845                         result = -1;
    846                 } /* otherwise, mkdir will do nothing (directory exists) or fail
    847                      (another error) */
    848         }
    849        
    850         if (result == 0) {
    851                 result = __mkdir(path, mode);
    852         }
    853        
    854         return result;
     884        char newpath[MAXPATHLEN];
     885
     886        *newpath = '\0';
     887        if (!__darwintrace_is_in_sandbox(path, newpath)) {
     888                struct stat st;
     889                if (-1 == lstat(path, &st)) {
     890                        if (errno == ENOENT) {
     891                                /* directory doesn't exist yet */
     892                                debug_printf("mkdir was forbidden at %s\n", path);
     893                                errno = EACCES;
     894                                return -1;
     895                        }
     896                }
     897                /* otherwise, mkdir will do nothing or fail with a hopefully meaningful
     898                 * error */
     899        } else {
     900                if (*newpath) {
     901                        path = newpath;
     902                }
     903
     904                debug_printf("mkdir was allowed at %s\n", path);
     905        }
     906
     907        return __mkdir(path, mode);
    855908}
    856909
     
    859912int rmdir(const char* path) {
    860913#define __rmdir(x) syscall(SYS_rmdir, (x))
    861         int result = 0;
    862         int isInSandbox = __darwintrace_is_in_sandbox(path, 0);
    863         if (isInSandbox == 1) {
    864                 debug_printf("darwintrace: rmdir was allowed at %s\n", path);
    865         } else if (isInSandbox == 0) {
    866                 /* outside sandbox, but sandbox is defined: forbid */
    867                 debug_printf("darwintrace: removing directory %s was forbidden\n", path);
    868                 errno = EACCES;
    869                 result = -1;
    870         }
    871        
    872         if (result == 0) {
    873                 result = __rmdir(path);
    874         }
    875        
    876         return result;
     914        if (!__darwintrace_is_in_sandbox(path, NULL)) {
     915                debug_printf("removing directory %s was forbidden\n", path);
     916                errno = ENOENT;
     917                return -1;
     918        }
     919
     920        debug_printf("rmdir %s was allowed\n", path);
     921
     922        return __rmdir(path);
    877923}
    878924
     
    881927int rename(const char* from, const char* to) {
    882928#define __rename(x,y) syscall(SYS_rename, (x), (y))
     929        if (!__darwintrace_is_in_sandbox(from, NULL)) {
     930                /* outside sandbox, forbid */
     931                debug_printf("renaming from %s was forbidden\n", from);
     932                errno = ENOENT;
     933                return -1;
     934        }
     935        if (!__darwintrace_is_in_sandbox(to, NULL)) {
     936                debug_printf("renaming to %s was forbidden\n", to);
     937                errno = EACCES;
     938                return -1;
     939        }
     940
     941        debug_printf("renaming from %s to %s was allowed\n", from, to);
     942
     943        return __rename(from, to);
     944}
     945
     946int stat(const char * path, struct stat * sb) {
     947#define stat(path, sb) syscall(SYS_stat, path, sb)
    883948        int result = 0;
    884         int isInSandbox = __darwintrace_is_in_sandbox(from, 0);
    885         if (isInSandbox == 1) {
    886                 debug_printf("darwintrace: rename was allowed at %s\n", from);
    887         } else if (isInSandbox == 0) {
    888                 /* outside sandbox, but sandbox is defined: forbid */
    889                 debug_printf("darwintrace: renaming from %s was forbidden\n", from);
    890                 errno = EACCES;
    891                 result = -1;
    892         }
    893 
    894         if (result == 0) {
    895                 isInSandbox = __darwintrace_is_in_sandbox(to, 0);
    896                 if (isInSandbox == 1) {
    897                         debug_printf("darwintrace: rename was allowed at %s\n", to);
    898                 } else if (isInSandbox == 0) {
    899                         /* outside sandbox, but sandbox is defined: forbid */
    900                         debug_printf("darwintrace: renaming to %s was forbidden\n", to);
    901                         errno = EACCES;
    902                         result = -1;
    903                 }
    904         }
    905        
    906         if (result == 0) {
    907                 result = __rename(from, to);
    908         }
    909        
    910         return result;
    911 }
    912 
    913 int stat(const char * path, struct stat * sb)
    914 {
    915 #define stat(path, sb) syscall(SYS_stat, path, sb)
    916         int result=0;
    917         char newpath[260];
    918                
    919         *newpath=0;
    920         if(!is_directory(path)&&__darwintrace_is_in_sandbox(path, newpath)==0)
    921         {
    922                 errno=ENOENT;
    923                 result=-1;
    924         }else
    925         {
    926                 if(*newpath)
    927                         path=newpath;
    928                        
    929                 result=stat(path, sb);
    930         }
    931        
     949        char newpath[MAXPATHLEN];
     950
     951        debug_printf("stat(%s)\n", path);
     952        if (-1 == (result = stat(path, sb))) {
     953                return -1;
     954        }
     955
     956        if (S_ISDIR(sb->st_mode)) {
     957                return result;
     958        }
     959
     960        *newpath = '\0';
     961        if (!__darwintrace_is_in_sandbox(path, newpath)) {
     962                errno = ENOENT;
     963                return -1;
     964        }
     965
     966        if (*newpath) {
     967                result = stat(newpath, sb);
     968        }
     969
    932970        return result;
    933971#undef stat
     
    936974#if defined(__DARWIN_64_BIT_INO_T) && !defined(_DARWIN_FEATURE_ONLY_64_BIT_INODE)
    937975
    938 int stat64(const char * path, struct stat64 * sb)
    939 {
     976int stat64(const char * path, struct stat64 * sb) {
    940977#define stat64(path, sb) syscall(SYS_stat64, path, sb)
    941         int result=0;
    942         char newpath[260];
    943                
    944         *newpath=0;
    945         if(!is_directory(path)&&__darwintrace_is_in_sandbox(path, newpath)==0)
    946         {
    947                 errno=ENOENT;
    948                 result=-1;
    949         }else
    950         {
    951                 if(*newpath)
    952                         path=newpath;
    953                        
    954                 result=stat64(path, sb);
    955         }
    956        
     978        int result = 0;
     979        char newpath[MAXPATHLEN];
     980
     981        debug_printf("stat64(%s)\n", path);
     982        if (-1 == (result = stat64(path, sb))) {
     983                return -1;
     984        }
     985
     986        if (S_ISDIR(sb->st_mode)) {
     987                return result;
     988        }
     989
     990        *newpath = '\0';
     991        if (!__darwintrace_is_in_sandbox(path, newpath)) {
     992                errno = ENOENT;
     993                return -1;
     994        }
     995
     996        if (*newpath) {
     997                result = stat64(newpath, sb);
     998        }
     999
    9571000        return result;
    9581001#undef stat64
    9591002}
    9601003
    961 int stat$INODE64(const char * path, struct stat64 * sb)
    962 {
     1004int stat$INODE64(const char * path, struct stat64 * sb) {
    9631005    return stat64(path, sb);
    9641006}
     
    9671009
    9681010
    969 int lstat(const char * path, struct stat * sb)
    970 {
     1011int lstat(const char * path, struct stat * sb) {
    9711012#define lstat(path, sb) syscall(SYS_lstat, path, sb)
    972         int result=0;
    973         char newpath[260];
    974        
    975         *newpath=0;
    976         if(!is_directory(path)&&__darwintrace_is_in_sandbox(path, newpath)==0)
    977         {
    978                 errno=ENOENT;
    979                 result=-1;
    980         }else
    981         {
    982                 if(*newpath)
    983                         path=newpath;
    984                        
    985                 result=lstat(path, sb);
    986         }
    987        
     1013        int result = 0;
     1014        char newpath[MAXPATHLEN];
     1015
     1016        debug_printf("lstat(%s)\n", path);
     1017        if (-1 == (result = lstat(path, sb))) {
     1018                return -1;
     1019        }
     1020
     1021        if (S_ISDIR(sb->st_mode)) {
     1022                return result;
     1023        }
     1024
     1025        *newpath = '\0';
     1026        if (!__darwintrace_is_in_sandbox(path, newpath)) {
     1027                errno = ENOENT;
     1028                return -1;
     1029        }
     1030
     1031        if (*newpath) {
     1032                result = lstat(newpath, sb);
     1033        }
     1034
    9881035        return result;
    9891036#undef lstat
     
    9921039#if defined(__DARWIN_64_BIT_INO_T) && !defined(_DARWIN_FEATURE_ONLY_64_BIT_INODE)
    9931040
    994 int lstat64(const char * path, struct stat64 * sb)
    995 {
     1041int lstat64(const char * path, struct stat64 * sb) {
    9961042#define lstat64(path, sb) syscall(SYS_lstat64, path, sb)
    997         int result=0;
    998         char newpath[260];
    999        
    1000         *newpath=0;
    1001         if(!is_directory(path)&&__darwintrace_is_in_sandbox(path, newpath)==0)
    1002         {
    1003                 errno=ENOENT;
    1004                 result=-1;
    1005         }else
    1006         {
    1007                 if(*newpath)
    1008                         path=newpath;
    1009                        
    1010                 result=lstat64(path, sb);
    1011         }
    1012        
     1043        int result = 0;
     1044        char newpath[MAXPATHLEN];
     1045
     1046        debug_printf("lstat64(%s)\n", path);
     1047        if (-1 == (result = lstat64(path, sb))) {
     1048                return -1;
     1049        }
     1050
     1051        if (S_ISDIR(sb->st_mode)) {
     1052                return result;
     1053        }
     1054
     1055        *newpath = '\0';
     1056        if (!__darwintrace_is_in_sandbox(path, newpath)) {
     1057                errno = ENOENT;
     1058                return -1;
     1059        }
     1060
     1061        if (*newpath) {
     1062                result = lstat64(newpath, sb);
     1063        }
     1064
    10131065        return result;
    10141066#undef lstat64
    10151067}
    10161068
    1017 int lstat$INODE64(const char * path, struct stat64 * sb)
    1018 {
     1069int lstat$INODE64(const char * path, struct stat64 * sb) {
    10191070    return lstat64(path, sb);
    10201071}
    10211072
    10221073#endif /* defined(__DARWIN_64_BIT_INO_T) && !defined(_DARWIN_FEATURE_ONLY_64_BIT_INODE) */
     1074
     1075/**
     1076 * re-implementation of getdirent(2) and __getdirent64(2) preventing paths
     1077 * outside the sandbox to show up when reading the contents of a directory.
     1078 * Unfortunately, since we need to access the contents of the buffer, but the
     1079 * contents differ by architecture, we can not rely on the dirent structure
     1080 * defined by the header included by this program, because we don't know
     1081 * whether darwintrace.dylib has been compiled for 64bit or 32bit inodes. We
     1082 * thus copy both structs and decide at runtime.
     1083 */
     1084
     1085#ifdef __APPLE__
     1086/* only do this on mac, because fcntl(fd, F_GETPATH) might not be available on
     1087 * other systems, and because other system's syscall names are probably
     1088 * different anyway */
     1089
     1090#pragma pack(4)
     1091struct dirent32 {
     1092        ino_t d_ino;                    /* file number of entry */
     1093        __uint16_t d_reclen;            /* length of this record */
     1094        __uint8_t  d_type;              /* file type, see below */
     1095        __uint8_t  d_namlen;            /* length of string in d_name */
     1096        char d_name[__DARWIN_MAXNAMLEN + 1];    /* name must be no longer than this */
     1097};
     1098#pragma pack()
     1099
     1100struct dirent64  {
     1101        __uint64_t  d_ino;      /* file number of entry */
     1102        __uint64_t  d_seekoff;  /* seek offset (optional, used by servers) */
     1103        __uint16_t  d_reclen;   /* length of this record */
     1104        __uint16_t  d_namlen;   /* length of string in d_name */
     1105        __uint8_t   d_type;     /* file type, see below */
     1106        char      d_name[__DARWIN_MAXPATHLEN]; /* entry name (up to MAXPATHLEN bytes) */
     1107};
     1108
     1109size_t __getdirentries64(int fd, void *buf, size_t bufsize, __darwin_off_t *basep) {
     1110#define __getdirentries64(w,x,y,z) syscall(SYS_getdirentries64, (w), (x), (y), (z))
     1111        size_t sz = __getdirentries64(fd, buf, bufsize, basep);
     1112        char dirname[MAXPATHLEN];
     1113        size_t dnamelen;
     1114
     1115        if (-1 == fcntl(fd, F_GETPATH, dirname)) {
     1116                errno = EBADF;
     1117                return 0;
     1118        }
     1119
     1120        dnamelen = strlen(dirname);
     1121        if (dirname[dnamelen - 1] != '/') {
     1122                dirname[dnamelen] = '/';
     1123                dirname[dnamelen + 1] = '\0';
     1124                dnamelen++;
     1125        }
     1126
     1127        dnamelen = strlen(dirname);
     1128        size_t offset;
     1129        for (offset = 0; offset < sz;) {
     1130                struct dirent64 *dent = (struct dirent64 *)(((char *) buf) + offset);
     1131                dirname[dnamelen] = '\0';
     1132                strcat(dirname, dent->d_name);
     1133                if (!__darwintrace_is_in_sandbox(dirname, NULL)) {
     1134                        debug_printf("__getdirentries64: filtered %s\n", dirname);
     1135                        dent->d_ino = 0;
     1136                } else {
     1137                        debug_printf("__getdirentries64:  allowed %s\n", dirname);
     1138                }
     1139                offset += dent->d_reclen;
     1140        }
     1141
     1142        return sz;
     1143#undef __getdirentries64
     1144}
     1145
     1146int getdirentries(int fd, char *buf, int nbytes, long *basep) {
     1147#define getdirentries(w,x,y,z) syscall(SYS_getdirentries, (w), (x), (y), (z))
     1148        size_t sz = getdirentries(fd, buf, nbytes, basep);
     1149        char dirname[MAXPATHLEN];
     1150        size_t dnamelen;
     1151
     1152        if (-1 == fcntl(fd, F_GETPATH, dirname)) {
     1153                errno = EBADF;
     1154                return 0;
     1155        }
     1156
     1157        dnamelen = strlen(dirname);
     1158        if (dirname[dnamelen - 1] != '/') {
     1159                dirname[dnamelen] = '/';
     1160                dirname[dnamelen + 1] = '\0';
     1161                dnamelen++;
     1162        }
     1163
     1164        size_t offset;
     1165        for (offset = 0; offset < sz;) {
     1166                struct dirent32 *dent = (struct dirent32 *)(buf + offset);
     1167                dirname[dnamelen] = '\0';
     1168                strcat(dirname, dent->d_name);
     1169                if (!__darwintrace_is_in_sandbox(dirname, NULL)) {
     1170                        debug_printf("getdirentries: filtered %s\n", dirname);
     1171                        dent->d_ino = 0;
     1172                } else {
     1173                        debug_printf("getdirentries:  allowed %s\n", dirname);
     1174                }
     1175                offset += dent->d_reclen;
     1176        }
     1177
     1178        return sz;
     1179#undef getdirentries
     1180}
     1181#endif /* __APPLE__ */
  • branches/gsoc11-statistics/base/src/images_to_archives.tcl

    r82923 r105085  
    7575        set found 0
    7676        foreach adir [list $oldarchivedir $olderarchivedir] {
    77             foreach type {tbz2 tbz tgz tar txz tlz xar xpkg zip cpgz cpio} {
     77            foreach type {tbz2 tbz tgz tar txz tlz xar zip cpgz cpio} {
    7878                set oldarchivefullpath "[file join $adir $oldarchiverootname].${type}"
    7979                if {[file isfile $oldarchivefullpath]} {
     
    9393        } else {
    9494            set targetdir [file join ${macports::registry.path} software ${iname}]
    95             file mkdir $targetdir
     95        }
     96        if {$location == "" || ![file isdirectory $location]} {
    9697            set contents [$iref imagefiles]
    9798        }
     99        file mkdir $targetdir
    98100        set newlocation [file join $targetdir $archivename]
    99101
    100102        if {$found} {
    101103            file rename $oldarchivefullpath $newlocation
    102         } elseif {$installtype == "image"} {
     104        } elseif {$installtype == "image" && [file isdirectory $location]} {
    103105            # create archive from image dir
    104             system "cd $location && $tarcmd -cjf $newlocation * > ${targetdir}/error.log 2>&1"
     106            system -W $location "$tarcmd -cjf $newlocation * > ${targetdir}/error.log 2>&1"
    105107            file delete -force ${targetdir}/error.log
    106108        } else {
    107             # direct mode, create archive from installed files
     109            # direct mode (or missing image dir), create archive from installed files
    108110            # we tell tar to read filenames from a file so as not to run afoul of command line length limits
    109111            set fd [open ${targetdir}/tarlist w]
  • branches/gsoc11-statistics/base/src/machista1.0/Makefile.in

    r81529 r105085  
    3838clean::
    3939        rm -f ${SWIG_OBJS} ${PKG_INDEX}
    40 ifdef SWIG
    41         rm -f ${SWIG_SRCS}
    42 else
    43         @echo "Not cleaning SWIG-generated sources, because you have configured MacPorts without SWIG." >&2
    44 endif
    4540        rm -f ${TESTS}
    4641        rm -rf ${TESTS:%=%.dSYM}
     42
     43distclean::
     44        rm -f Makefile
    4745
    4846test:: ${TESTS}
  • branches/gsoc11-statistics/base/src/machista1.0/libmachista.c

    r81757 r105085  
    4343#include <string.h>
    4444
     45#ifdef __MACH__
    4546#include <mach-o/fat.h>
    4647#include <mach-o/loader.h>
    4748
    4849#include <libkern/OSAtomic.h>
     50#endif
    4951
    5052#include "libmachista.h"
    5153#include "hashmap.h"
     54
     55#ifdef __MACH__
     56/* Tiger compatibility */
     57#ifndef LC_RPATH
     58#define LC_RPATH       (0x1c | LC_REQ_DYLD)    /* runpath additions */
     59/*
     60 * The rpath_command contains a path which at runtime should be added to
     61 * the current run path used to find @rpath prefixed dylibs.
     62 */
     63struct rpath_command {
     64    uint32_t     cmd;       /* LC_RPATH */
     65    uint32_t     cmdsize;   /* includes string */
     66    union lc_str path;      /* path to add to run path */
     67};
     68#endif
     69#ifndef LC_REEXPORT_DYLIB
     70#define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD) /* load and re-export dylib */
     71#endif
     72#endif /* __MACH__ */
    5273
    5374typedef struct macho_input {
     
    6182};
    6283
     84#ifdef __MACH__
    6385/* Verify that the given range is within bounds. */
    6486static const void *macho_read (macho_input_t *input, const void *address, size_t length) {
     
    7698    return macho_read(input, result, length);
    7799}
     100#endif
    78101
    79102/* return a human readable formatted version number. the result must be free()'d. */
     
    85108
    86109const char *macho_get_arch_name (cpu_type_t cputype) {
     110#ifdef __MACH__
    87111    const NXArchInfo *archInfo = NXGetArchInfoFromCpuType(cputype, CPU_SUBTYPE_MULTIPLE);       
    88112    if (!archInfo) {
     
    90114    }
    91115    return archInfo->name;
    92 }
    93 
     116#else
     117    return NULL;
     118#endif
     119}
     120
     121#ifdef __MACH__
    94122/* Some byteswap wrappers */
    95123static uint32_t macho_swap32 (uint32_t input) {
     
    133161    return mlt;
    134162}
     163#endif
    135164
    136165/* Frees a previously allocated macho_loadcmd_t and all it's associated resources */
     
    175204}
    176205
     206#ifdef __MACH__
    177207/* Creates a new element in the architecture list of a macho_t (mt_archs), increases the counter of
    178208 * architectures (mt_arch_count) and returns a pointer to the newly allocated element or NULL on
     
    204234    return mat->mat_loadcmds;
    205235}
     236#endif
    206237
    207238/* Parse a Mach-O header */
    208239static int parse_macho (macho_t *mt, macho_input_t *input) {
     240#ifdef __MACH__
    209241    /* Read the file type. */
    210242    const uint32_t *magic = macho_read(input, input->data, sizeof(uint32_t));
     
    402434
    403435    return MACHO_SUCCESS;
     436#else
     437    return 0;
     438#endif
    404439}
    405440
    406441/* Parse a (possible Mach-O) file. For a more detailed description, see the header */
    407442int macho_parse_file(macho_handle_t *handle, const char *filepath, const macho_t **res) {
     443#ifdef __MACH__
    408444    int fd;
    409445    struct stat st;
     
    465501
    466502    return ret;
     503#else
     504    return 0;
     505#endif
    467506}
    468507
  • branches/gsoc11-statistics/base/src/machista1.0/libmachista.h

    r81757 r105085  
    55 *
    66 * Copyright (c) 2011 The MacPorts Project
    7  * Copyright (c) 2011 Clemens Lang
     7 * Copyright (c) 2011 Clemens Lang <cal@macports.org>
    88 * All rights reserved.
    99 *
     
    3939 */
    4040
     41#ifdef __MACH__
    4142#include <mach-o/arch.h>
     43#else
     44typedef int cpu_type_t;
     45#endif
    4246#include <inttypes.h>
    4347
  • branches/gsoc11-statistics/base/src/machista1.0/machista.i

    r81761 r105085  
    77
    88%inline %{
     9#ifdef __MACH__
    910    #include <mach-o/arch.h>
     11#endif
    1012    #include <inttypes.h>
    1113    #include <stdint.h>
  • branches/gsoc11-statistics/base/src/machista1.0/machista_wrap.c

    r81761 r105085  
    16751675
    16761676
     1677#ifdef __MACH__
    16771678    #include <mach-o/arch.h>
     1679#endif
    16781680    #include <inttypes.h>
    16791681    #include <stdint.h>
     
    24572459  int found, init;
    24582460 
    2459   clientdata = clientdata;
    2460  
    24612461  /* check to see if the circular list has been setup, if not, set it up */
    24622462  if (swig_module.next==0) {
  • branches/gsoc11-statistics/base/src/machista1.0/tests/libmachista-test.c

    r81268 r105085  
     1#ifdef __MACH__
     2
    13#include <libmachista.h>
    24#include <limits.h>
     
    341343        return false;
    342344}
     345#endif
    343346
    344347int main() {
     348#ifdef __MACH__
    345349        bool result = true;
    346350        result &= test_destroy_null();
     
    348352        result &= test_format_dylib_version();
    349353        result &= test_libsystem();
    350         exit(!result);
    351 }
    352 
     354        return !result;
     355#else
     356        return 0;
     357#endif
     358}
     359
  • branches/gsoc11-statistics/base/src/macports1.0/macports.tcl

    r88412 r105085  
    77# Copyright (c) 2004 - 2006 Ole Guldberg Jensen <olegb@opendarwin.org>.
    88# Copyright (c) 2004 - 2005 Robert Shaw <rshaw@opendarwin.org>
    9 # Copyright (c) 2004 - 2011 The MacPorts Project
     9# Copyright (c) 2004 - 2012 The MacPorts Project
    1010# All rights reserved.
    1111#
     
    3838package require macports_index 1.0
    3939package require macports_util 1.0
    40 package require machista 1.0
    4140
    4241namespace eval macports {
     
    4645        portarchivetype portautoclean \
    4746        porttrace portverbose keeplogs destroot_umask variants_conf rsync_server rsync_options \
    48         rsync_dir startupitem_type place_worksymlink xcodeversion xcodebuildcmd gccversion \
    49         mp_remote_url mp_remote_submit_url configureccache ccache_dir ccache_size configuredistcc configurepipe buildnicevalue buildmakejobs \
     47        rsync_dir startupitem_type startupitem_install place_worksymlink xcodeversion xcodebuildcmd gccversion \
     48        configureccache ccache_dir ccache_size configuredistcc configurepipe buildnicevalue buildmakejobs \
    5049        applications_dir frameworks_dir developer_dir universal_archs build_arch macosx_deployment_target \
    5150        macportsuser proxy_override_env proxy_http proxy_https proxy_ftp proxy_rsync proxy_skip \
    52         master_site_local patch_site_local archive_site_local buildfromsource stats_participate stats_url stats_id"
    53     variable user_options "submitter_name submitter_email submitter_key"
     51        master_site_local patch_site_local archive_site_local buildfromsource stats_participate stats_url stats_id \
     52        revupgrade_autorun revupgrade_mode revupgrade_check_id_loadcmds \
     53        host_blacklist preferred_hosts\
     54        packagemaker_path default_compilers"
     55    variable user_options ""
    5456    variable portinterp_options "\
    5557        portdbpath porturl portpath portbuildpath auto_path prefix prefix_frozen portsharepath \
    56         registry.path registry.format \
     58        registry.path registry.format user_home \
    5759        portarchivetype archivefetch_pubkeys portautoclean porttrace keeplogs portverbose destroot_umask \
    58         rsync_server rsync_options rsync_dir startupitem_type place_worksymlink macportsuser \
    59         mp_remote_url mp_remote_submit_url configureccache ccache_dir ccache_size configuredistcc configurepipe buildnicevalue buildmakejobs \
     60        rsync_server rsync_options rsync_dir startupitem_type startupitem_install place_worksymlink macportsuser \
     61        configureccache ccache_dir ccache_size configuredistcc configurepipe buildnicevalue buildmakejobs \
    6062        applications_dir current_phase frameworks_dir developer_dir universal_archs build_arch \
    61         os_arch os_endian os_version os_major os_platform macosx_version macosx_deployment_target $user_options"
     63        os_arch os_endian os_version os_major os_platform macosx_version macosx_deployment_target \
     64        packagemaker_path default_compilers $user_options"
    6265
    6366    # deferred options are only computed when needed.
    6467    # they are not exported to the trace thread.
    6568    # they are not exported to the interpreter in system_options array.
    66     variable portinterp_deferred_options "xcodeversion xcodebuildcmd gccversion"
     69    variable portinterp_deferred_options "xcodeversion xcodebuildcmd developer_dir gccversion"
    6770
    6871    variable open_mports {}
     
    366369    trace remove variable macports::xcodebuildcmd read macports::setxcodeinfo
    367370
    368     if {[catch {set xcodebuild [binaryInPath "xcodebuild"]}] == 0} {
     371    if {![catch {findBinary xcodebuild $macports::autoconf::xcodebuild_path} xcodebuild]} {
    369372        if {![info exists xcodeversion]} {
    370373            # Determine xcode version
     
    449452    }
    450453}
     454
     455# deferred calculation of developer_dir
     456proc macports::set_developer_dir {name1 name2 op} {
     457    global macports::developer_dir macports::os_major macports::xcodeversion
     458
     459    trace remove variable macports::developer_dir read macports::set_developer_dir
     460   
     461    # Look for xcodeselect, and make sure it has a valid value
     462    if {![catch {findBinary xcode-select $macports::autoconf::xcode_select_path} xcodeselect]} {
     463
     464        # We have xcode-select: ask it where xcode is and check if it's valid.
     465        # If no xcode is selected, xcode-select will fail, so catch that
     466        if {![catch {exec $xcodeselect -print-path 2> /dev/null} devdir] &&
     467            [_is_valid_developer_dir $devdir]} {
     468            set macports::developer_dir $devdir
     469            return
     470        }
     471
     472        # The directory from xcode-select isn't correct.
     473       
     474        # Ask mdfind where Xcode is and make some suggestions for the user,
     475        # searching by bundle identifier for various Xcode versions (3.x and 4.x)
     476        set installed_xcodes {}
     477        if {![catch {findBinary mdfind $macports::autoconf::mdfind_path} mdfind]} {
     478            set installed_xcodes [exec $mdfind "kMDItemCFBundleIdentifier == 'com.apple.Xcode' || kMDItemCFBundleIdentifier == 'com.apple.dt.Xcode'"]
     479        }
     480       
     481        # In case mdfind metadata wasn't complete, also look in two well-known locations for Xcode.app
     482        foreach app {/Applications/Xcode.app /Developer/Applications/Xcode.app} {
     483            if {[file isdirectory $app]} {
     484                lappend installed_xcodes $app
     485            }
     486        }
     487       
     488        # Form a list of unique xcode installations
     489        set installed_xcodes [lsort -unique $installed_xcodes]
     490
     491        # Present instructions to the user
     492        ui_error
     493        if {[llength $installed_xcodes] > 0 && ![catch {findBinary mdls $macports::autoconf::mdls_path} mdls]} {
     494            # One, or more than one, Xcode installations found
     495            ui_error "No valid Xcode installation is properly selected."
     496            ui_error "Please use xcode-select to select an Xcode installation:"
     497            foreach xcode $installed_xcodes {
     498                set vers [exec $mdls -raw -name kMDItemVersion $xcode]
     499                if {$vers == "(null)"} { set vers "unknown" }
     500                if {[_is_valid_developer_dir "${xcode}/Contents/Developer"]} {
     501                    # Though xcode-select shipped with xcode 4.3 supports and encourages
     502                    # direct use of the app path, older xcode-select does not.
     503                    # Specify the Contents/Developer directory if it exists
     504                    ui_error "    sudo xcode-select -switch ${xcode}/Contents/Developer # version ${vers}"
     505                } elseif {[vercmp $vers 4.3] >= 0} {
     506                    # Future proofing: fall back to the app-path only for xcode >= 4.3, since Contents/Developer doesn't exist
     507                    ui_error "    sudo xcode-select -switch ${xcode} # version ${vers}"
     508                } elseif {[_is_valid_developer_dir "${xcode}/../.."]} {
     509                    # Older xcode (< 4.3) is below the developer directory
     510                    ui_error "    sudo xcode-select -switch [file normalize ${xcode}/../..] # version ${vers}"
     511                } else {
     512                    ui_error "    # malformed Xcode at ${xcode}, version ${vers}"
     513                }
     514            }
     515        } else {
     516            ui_error "No Xcode installation was found."
     517            ui_error "Please install Xcode and/or run xcode-select to specify its location."
     518        }
     519        ui_error
     520    }
     521
     522    # Try the default
     523    if {$os_major >= 11 && [vercmp $xcodeversion 4.3] >= 0} {
     524        set devdir "/Applications/Xcode.app/Contents/Developer"
     525    } else {
     526        set devdir "/Developer"
     527    }
     528
     529    set macports::developer_dir $devdir
     530}
     531
     532proc macports::_is_valid_developer_dir {dir} {
     533    # Check whether specified directory looks valid for an Xcode installation
     534
     535    # Verify that the directory exists
     536    if {![file isdirectory $dir]} {
     537        return 0
     538    }
     539
     540    # Verify that the directory has some key subdirectories
     541    foreach subdir {Library usr} {
     542        if {![file isdirectory "${dir}/${subdir}"]} {
     543            return 0
     544        }
     545    }
     546
     547    # The specified directory seems valid for Xcode
     548    return 1
     549}
     550
    451551
    452552proc mportinit {{up_ui_options {}} {up_options {}} {up_variations {}}} {
     
    520620    global macports::macosx_deployment_target
    521621    global macports::archivefetch_pubkeys
     622    global macports::ping_cache
     623    global macports::host_blacklisted
     624    global macports::host_preferred
    522625
    523626    # Set the system encoding to utf-8
    524627    encoding system utf-8
    525 
    526     # Ensure that the macports user directory exists if HOME is defined
    527     if {[info exists env(HOME)]} {
    528         set macports::macports_user_dir [file normalize $macports::autoconf::macports_user_dir]
    529     } else {
    530         # Otherwise define the user directory as a direcotory that will never exist
    531         set macports::macports_user_dir "/dev/null/NO_HOME_DIR"
    532         # Tcl library code wants to do tilde expansion in various places
    533         set env(HOME) ${macports::macports_user_dir}
    534     }
    535628
    536629    # set up platform info variables
     
    549642    }
    550643
     644    # Ensure that the macports user directory (i.e. ~/.macports) exists if HOME is defined.
     645    # Also save $HOME for later use before replacing it with our own.
     646    if {[info exists env(HOME)]} {
     647        set macports::user_home $env(HOME)
     648        set macports::macports_user_dir [file normalize $macports::autoconf::macports_user_dir]
     649    } elseif {[info exists env(SUDO_USER)] && $os_platform == "darwin"} {
     650        set macports::user_home [exec dscl -q . -read /Users/$env(SUDO_USER) NFSHomeDirectory | cut -d ' ' -f 2]
     651        set macports::macports_user_dir [file join ${macports::user_home} [string range $macports::autoconf::macports_user_dir 2 end]]
     652    } elseif {[exec id -u] != 0 && $os_platform == "darwin"} {
     653        set macports::user_home [exec dscl -q . -read /Users/[exec id -un] NFSHomeDirectory | cut -d ' ' -f 2]
     654        set macports::macports_user_dir [file join ${macports::user_home} [string range $macports::autoconf::macports_user_dir 2 end]]
     655    } else {
     656        # Otherwise define the user directory as a directory that will never exist
     657        set macports::macports_user_dir "/dev/null/NO_HOME_DIR"
     658        set macports::user_home "/dev/null/NO_HOME_DIR"
     659    }
     660
    551661    # Configure the search path for configuration files
    552662    set conf_files ""
     
    567677            while {[gets $fd line] >= 0} {
    568678                if {[regexp {^(\w+)([ \t]+(.*))?$} $line match option ignore val] == 1} {
    569                     if {[lsearch $bootstrap_options $option] >= 0} {
     679                    if {[lsearch -exact $bootstrap_options $option] >= 0} {
    570680                        set macports::$option [string trim $val]
    571681                        global macports::$option
     
    583693        while {[gets $fd line] >= 0} {
    584694            if {[regexp {^(\w+)([ \t]+(.*))?$} $line match option ignore val] == 1} {
    585                 if {[lsearch $user_options $option] >= 0} {
     695                if {[lsearch -exact $user_options $option] >= 0} {
    586696                    set macports::$option $val
    587697                    global macports::$option
     
    688798    }
    689799
     800    set env(HOME) [file join $portdbpath home]
    690801    set registry.path $portdbpath
    691802
     
    703814        global macports::portautoclean
    704815    }
    705         # whether to keep logs after successful builds
    706         if {![info exists keeplogs]} {
     816    # whether to keep logs after successful builds
     817    if {![info exists keeplogs]} {
    707818        set macports::keeplogs "no"
    708819        global macports::keeplogs
     
    732843        if {${macports::buildfromsource} == "never"} {
    733844            set macports::global_options(ports_binary_only) yes
     845            set temp_options(ports_binary_only) yes
    734846        } elseif {${macports::buildfromsource} == "always"} {
    735847            set macports::global_options(ports_source_only) yes
     848            set temp_options(ports_source_only) yes
    736849        } elseif {${macports::buildfromsource} != "ifneeded"} {
    737850            ui_warn "'buildfromsource' set to unknown value '${macports::buildfromsource}', using 'ifneeded' instead"
     
    742855    # can always get to the original prefix, even if a portfile overrides prefix
    743856    set macports::prefix_frozen $prefix
     857
     858    if {![info exists macports::applications_dir]} {
     859        set macports::applications_dir /Applications/MacPorts
     860    }
    744861
    745862    # Export verbosity.
     
    797914    }
    798915
     916    # Set whether startupitems are symlinked into system directories
     917    if {![info exists macports::startupitem_install]} {
     918        set macports::startupitem_install yes
     919    }
     920
    799921    # Default place_worksymlink
    800922    if {![info exists macports::place_worksymlink]} {
    801923        set macports::place_worksymlink yes
    802     }
    803 
    804     # Default mp remote options
    805     if {![info exists macports::mp_remote_url]} {
    806         set macports::mp_remote_url "http://db.macports.org"
    807     }
    808     if {![info exists macports::mp_remote_submit_url]} {
    809         set macports::mp_remote_submit_url "${macports::mp_remote_url}/submit"
    810924    }
    811925
     
    876990    if {![info exists macports::macosx_deployment_target]} {
    877991        set macports::macosx_deployment_target $macosx_version
     992    }
     993
     994    if {![info exists macports::revupgrade_autorun]} {
     995        set macports::revupgrade_autorun yes
     996    }
     997    if {![info exists macports::revupgrade_mode]} {
     998        set macports::revupgrade_mode "rebuild"
     999    }
     1000    if {![info exists macports::global_options(ports_rev-upgrade_id-loadcmd-check)]
     1001         && [info exists macports::revupgrade_check_id_loadcmds]} {
     1002        set macports::global_options(ports_rev-upgrade_id-loadcmd-check) ${macports::revupgrade_check_id_loadcmds}
     1003        set temp_options(ports_rev-upgrade_id-loadcmd-check) ${macports::revupgrade_check_id_loadcmds}
    8781004    }
    8791005
     
    9061032        package require registry 1.0
    9071033        package require registry2 2.0
     1034        package require machista 1.0
    9081035    } else {
    9091036        return -code error "Library directory '$libpath' must exist"
     
    9471074    }
    9481075
     1076    if {![info exists developer_dir]} {
     1077        if {$os_platform == "darwin"} {
     1078            trace add variable macports::developer_dir read macports::set_developer_dir
     1079        } else {
     1080            set macports::developer_dir ""
     1081        }
     1082    } else {
     1083        if {$os_platform == "darwin" && ![file isdirectory $developer_dir]} {
     1084            ui_warn "Your developer_dir setting in macports.conf points to a non-existing directory.\
     1085                Since this is known to cause problems, please correct the setting or comment it and let\
     1086                macports auto-discover the correct path."
     1087        }
     1088    }
     1089
     1090    if {[getuid] == 0 && $os_major >= 11 && $os_platform == "darwin" &&
     1091            [file isfile "${macports::user_home}/Library/Preferences/com.apple.dt.Xcode.plist"]} {
     1092        macports::copy_xcode_plist $env(HOME)
     1093    }
     1094
    9491095    # Set the default umask
    9501096    if {![info exists destroot_umask]} {
     
    10061152    set env(CCACHE_DIR) ${macports::ccache_dir}
    10071153
     1154    # load cached ping times
     1155    if {[catch {
     1156        set pingfile [open ${macports::portdbpath}/pingtimes r]
     1157        array set macports::ping_cache [gets $pingfile]
     1158        close $pingfile
     1159    }]} { array set macports::ping_cache {} }
     1160    # set up arrays of blacklisted and preferred hosts
     1161    if {[info exists macports::host_blacklist]} {
     1162        foreach host ${macports::host_blacklist} {
     1163            set macports::host_blacklisted($host) 1
     1164        }
     1165    }
     1166    if {[info exists macports::preferred_hosts]} {
     1167        foreach host ${macports::preferred_hosts} {
     1168            set macports::host_preferred($host) 1
     1169        }
     1170    }
     1171
    10081172    # load the quick index
    10091173    _mports_load_quickindex
     
    10141178            set default_portindex [macports::getindex $default_source_url]
    10151179            if {[file exists $default_portindex] && [expr [clock seconds] - [file mtime $default_portindex]] > 1209600} {
    1016                 ui_warn "port definitions are more than two weeks old, consider using selfupdate"
     1180                ui_warn "port definitions are more than two weeks old, consider updating them by running 'port selfupdate'."
    10171181            }
    10181182        }
     
    10411205# call this just before you exit
    10421206proc mportshutdown {} {
     1207    # save ping times
     1208    global macports::ping_cache macports::portdbpath
     1209    if {[file writable ${macports::portdbpath}]} {
     1210        catch {
     1211            foreach host [array names ping_cache] {
     1212                # don't save expired entries
     1213                if {[expr [clock seconds] - [lindex $ping_cache($host) 1]] < 86400} {
     1214                    lappend pinglist_fresh $host $ping_cache($host)
     1215                }
     1216            }
     1217            set pingfile [open ${macports::portdbpath}/pingtimes w]
     1218            puts $pingfile $pinglist_fresh
     1219            close $pingfile
     1220        }
     1221    }
    10431222    # close it down so the cleanup stuff is called, e.g. vacuuming the db
    10441223    registry::close
     1224}
     1225
     1226# link plist for xcode 4.3's benefit
     1227proc macports::copy_xcode_plist {target_homedir} {
     1228    global macports::user_home macports::macportsuser
     1229    set user_plist "${user_home}/Library/Preferences/com.apple.dt.Xcode.plist"
     1230    set target_dir "${target_homedir}/Library/Preferences"
     1231    file delete -force "${target_dir}/com.apple.dt.Xcode.plist"
     1232    if {[file isfile $user_plist]} {
     1233        if {![file isdirectory "${target_dir}"]} {
     1234            if {[catch {file mkdir "${target_dir}"} result]} {
     1235                ui_warn "Failed to create Library/Preferences in ${target_homedir}: $result"
     1236                return
     1237            }
     1238        }
     1239        if {[file writable ${target_dir}] && [catch {
     1240            ui_debug "Copying $user_plist to ${target_dir}"
     1241            file copy -force $user_plist $target_dir
     1242            file attributes "${target_dir}/com.apple.dt.Xcode.plist" -owner $macportsuser -permissions 0644
     1243        } result]} {
     1244            ui_warn "Failed to copy com.apple.dt.Xcode.plist to ${target_dir}: $result"
     1245        }
     1246    }
    10451247}
    10461248
     
    11241326    $workername alias registry_file_registered registry::file_registered
    11251327    $workername alias registry_port_registered registry::port_registered
     1328    $workername alias registry_list_depends registry::list_depends
    11261329
    11271330    # deferred options processing.
    11281331    $workername alias getoption macports::getoption
     1332
     1333    # ping cache
     1334    $workername alias get_pingtime macports::get_pingtime
     1335    $workername alias set_pingtime macports::set_pingtime
     1336
     1337    # archive_sites.conf handling
     1338    $workername alias get_archive_sites_conf_values macports::get_archive_sites_conf_values
    11291339
    11301340    foreach opt $portinterp_options {
     
    14421652    }
    14431653
     1654    $workername eval port::run_callbacks
     1655
    14441656    ditem_key $mport provides [$workername eval return \$subport]
    14451657
     
    15551767                break
    15561768            }
     1769        }
     1770
     1771        if {$found} {
     1772            break
    15571773        }
    15581774    }
     
    17031919        ui_debug "$::errorInfo"
    17041920        if {[info exists ::logenabled] && $::logenabled && [info exists ::debuglogname]} {
    1705             ui_notice "Log for $portname is at: $::debuglogname"
     1921            ui_notice "Please see the log file for port $portname for details:\n    $::debuglogname"
    17061922        }
    17071923        macports::pop_log
     
    17241940    if {$target != "clean"} {
    17251941        macports::push_log $mport
     1942    }
     1943
     1944    # Use _target_needs_deps as a proxy for whether we're going to
     1945    # build and will therefore need to check Xcode version and
     1946    # supported_archs.
     1947    if {[macports::_target_needs_deps $target]} {
     1948        # possibly warn or error out depending on how old xcode is
     1949        if {[$workername eval _check_xcode_version] != 0} {
     1950            return 1
     1951        }
     1952        # error out if selected arch(s) not supported by this port
     1953        if {[$workername eval check_supported_archs] != 0} {
     1954            return 1
     1955        }
    17261956    }
    17271957
     
    17331963        if {($target != "activate" && $target != "install") ||
    17341964            ![$workername eval registry_exists \$subport \$version \$revision \$portvariants]} {
    1735             # possibly warn or error out depending on how old xcode is
    1736             if {[$workername eval _check_xcode_version] != 0} {
    1737                 return 1
    1738             }
    1739             # error out if selected arch(s) not supported by this port
    1740             if {[$workername eval check_supported_archs] != 0} {
    1741                 return 1
    1742             }
    17431965   
    17441966            # upgrade dependencies that are already installed
     
    18232045    if {[info exists ::logenabled] && $::logenabled && [info exists ::debuglogname]} {
    18242046        if {$result != 0} {
    1825             ui_notice "Log for $portname is at: $::debuglogname"
     2047            ui_notice "Please see the log file for port $portname for details:\n    $::debuglogname"
    18262048        }
    18272049        macports::pop_log
     
    18462068    foreach deptype $deptypes {
    18472069        if {![info exists portinfo($deptype)]} {
    1848             set portinfo($deptype) ""
     2070            continue
    18492071        }
    18502072        foreach depspec $portinfo($deptype) {
     
    18732095                    }
    18742096                    if {[llength $missing] > 0} {
    1875                         if {[info exists dep_portinfo(variants)] && [lsearch $dep_portinfo(variants) universal] != -1} {
     2097                        if {[info exists dep_portinfo(variants)] && [lsearch -exact $dep_portinfo(variants) universal] != -1} {
    18762098                            # dep offers a universal variant
    18772099                            if {[llength $active_archs] == 1} {
     
    20062228    set numfailed 0
    20072229
    2008     ui_debug "Synchronizing ports tree(s)"
     2230    ui_msg "$macports::ui_prefix Updating the ports tree"
    20092231    foreach source $sources {
    20102232        set flags [lrange $source 1 end]
     
    20212243                set svn_cmd ""
    20222244                catch {set svn_cmd [macports::findBinary svn]}
     2245                set git_cmd ""
     2246                catch {set git_cmd [macports::findBinary git]}
    20232247                if {$svn_cmd != "" && ([file exists $portdir/.svn] || ![catch {exec $svn_cmd info $portdir > /dev/null 2>@1}])} {
    20242248                    set svn_commandline "$svn_cmd update --non-interactive ${portdir}"
     
    20422266                        ui_debug "$::errorInfo"
    20432267                        ui_error "Synchronization of the local ports tree failed doing an svn update"
     2268                        incr numfailed
     2269                        continue
     2270                    }
     2271                } elseif {$git_cmd != "" && [file exists $portdir/.git]} {
     2272                    set git_commandline "pushd $portdir ; $git_cmd pull --rebase ; popd"
     2273                    ui_debug $git_commandline
     2274                    if {
     2275                        [catch {
     2276                            if {[getuid] == 0} {
     2277                                set euid [geteuid]
     2278                                set egid [getegid]
     2279                                ui_debug "changing euid/egid - current euid: $euid - current egid: $egid"
     2280                                setegid [name_to_gid [file attributes $portdir -group]]
     2281                                seteuid [name_to_uid [file attributes $portdir -owner]]
     2282                            }
     2283                            system $git_commandline
     2284                            if {[getuid] == 0} {
     2285                                seteuid $euid
     2286                                setegid $egid
     2287                            }
     2288                        }]
     2289                    } {
     2290                        ui_debug "$::errorInfo"
     2291                        ui_error "Synchronization of the local ports tree failed doing a git pull --rebase"
    20442292                        incr numfailed
    20452293                        continue
     
    23722620    }
    23732621    if {!$found} {
    2374         return -code error "No index(es) found! Have you synced your source indexes?"
     2622        return -code error "No index(es) found! Have you synced your port definitions? Try running 'port selfupdate'."
    23752623    }
    23762624
     
    25292777    }
    25302778    if {!$found} {
    2531         return -code error "No index(es) found! Have you synced your source indexes?"
     2779        return -code error "No index(es) found! Have you synced your port definitions? Try running 'port selfupdate'."
    25322780    }
    25332781
     
    25502798        set index [macports::getindex $source]
    25512799        if {![file exists ${index}]} {
     2800            incr sourceno
    25522801            continue
    25532802        }
     
    25552804            ui_warn "No quick index file found, attempting to generate one for source: $source"
    25562805            if {[catch {set quicklist [mports_generate_quickindex ${index}]}]} {
     2806                incr sourceno
    25572807                continue
    25582808            }
     
    25622812            if {[catch {set fd [open ${index}.quick r]} result]} {
    25632813                ui_warn "Can't open quick index file for source: $source"
     2814                incr sourceno
    25642815                continue
    25652816            } else {
     
    25742825    }
    25752826    if {!$sourceno} {
    2576         ui_warn "No index(es) found! Have you synced your source indexes?"
     2827        ui_warn "No index(es) found! Have you synced your port definitions? Try running 'port selfupdate'."
    25772828    }
    25782829}
     
    26652916
    26662917    array set portinfo [mportinfo $mport]
    2667     set deptypes {}
    26682918    if {$accDeps} {
    2669         upvar depspec_seen depspec_seen
     2919        upvar port_seen port_seen
    26702920    } else {
    2671         array set depspec_seen {}
     2921        array set port_seen {}
    26722922    }
    26732923
     
    27042954        }
    27052955        foreach depspec $portinfo($deptype) {
    2706             # skip depspec/archs combos we've already seen, and ones with less archs than ones we've seen
    2707             set seenkey "${depspec},[join $required_archs ,]"
     2956            # get the portname that satisfies the depspec
     2957            set dep_portname [$workername eval _get_dep_port $depspec]
     2958            # skip port/archs combos we've already seen, and ones with the same port but less archs than ones we've seen (or noarch)
     2959            set seenkey "${dep_portname},[join $required_archs ,]"
    27082960            set seen 0
    2709             if {[info exists depspec_seen($seenkey)]} {
     2961            if {[info exists port_seen($seenkey)]} {
    27102962                set seen 1
    27112963            } else {
    2712                 set prev_seenkeys [array names depspec_seen ${depspec},*]
     2964                set prev_seenkeys [array names port_seen ${dep_portname},*]
    27132965                set nrequired [llength $required_archs]
    27142966                foreach key $prev_seenkeys {
    27152967                    set key_archs [lrange [split $key ,] 1 end]
    2716                     if {[llength $key_archs] > $nrequired} {
     2968                    if {$key_archs == "noarch" || $required_archs == "noarch" || [llength $key_archs] > $nrequired} {
    27172969                        set seen 1
    27182970                        set seenkey $key
     
    27222974            }
    27232975            if {$seen} {
    2724                 if {$depspec_seen($seenkey) != 0} {
     2976                if {$port_seen($seenkey) != 0} {
    27252977                    # nonzero means the dep is not satisfied, so we have to record it
    2726                     ditem_append_unique $mport requires $depspec_seen($seenkey)
     2978                    ditem_append_unique $mport requires $port_seen($seenkey)
    27272979                }
    27282980                continue
     
    27332985            set present [_mportispresent $mport $depspec]
    27342986
    2735             # get the portname that satisfies the depspec
    2736             set dep_portname [$workername eval _get_dep_port $depspec]
    27372987            if {!$skipSatisfied && $dep_portname == ""} {
    27382988                set dep_portname [lindex [split $depspec :] end]
     
    27703020                    set check_archs 0
    27713021                }
    2772                 lappend options subport $dep_portinfo(name)
     3022                set dep_options $options
     3023                lappend dep_options subport $dep_portinfo(name)
    27733024                # Figure out the depport. Check the open_mports list first, since
    27743025                # we potentially leak mport references if we mportopen each time,
    27753026                # because mportexec only closes each open mport once.
    2776                 set depport [dlist_match_multi $macports::open_mports [list porturl $dep_portinfo(porturl) options $options variations $variations]]
    2777                
     3027                set depport [dlist_match_multi $macports::open_mports [list porturl $dep_portinfo(porturl) options $dep_options]]
     3028
    27783029                if {$depport == {}} {
    27793030                    # We haven't opened this one yet.
    2780                     set depport [mportopen $dep_portinfo(porturl) $options $variations]
     3031                    set depport [mportopen $dep_portinfo(porturl) $dep_options $variations]
    27813032                }
    27823033            }
     
    27873038
    27883039                set supported_archs [_mportkey $depport supported_archs]
     3040                array unset variation_array
     3041                array set variation_array [[ditem_key $depport workername] eval "array get variations"]
    27893042                mportclose $depport
    27903043                set arch_mismatch 1
     
    27933046                    # a universal variant is offered
    27943047                    set has_universal 1
    2795                     array unset variation_array
    2796                     array set variation_array $variations
    27973048                    if {![info exists variation_array(universal)] || $variation_array(universal) != "+"} {
    27983049                        set variation_array(universal) +
    27993050                        # try again with +universal
    2800                         set depport [mportopen $dep_portinfo(porturl) $options [array get variation_array]]
     3051                        set depport [mportopen $dep_portinfo(porturl) $dep_options [array get variation_array]]
    28013052                        if {[macports::_mport_supports_archs $depport $required_archs]} {
    28023053                            set arch_mismatch 0
     
    28193070                set depport_provides "[ditem_key $depport provides]"
    28203071                ditem_append_unique $mport requires $depport_provides
    2821                 set depspec_seen($seenkey) $depport_provides
    2822             } else {
    2823                 set depspec_seen($seenkey) 0
     3072                # record actual archs we ended up getting
     3073                set port_seen(${dep_portname},[join [macports::_mport_archs $depport] ,]) $depport_provides
     3074            } elseif {$present && $dep_portname != ""} {
     3075                # record actual installed archs
     3076                set port_seen(${dep_portname},[join [macports::_active_archs $dep_portname] ,]) 0
    28243077            }
    28253078        }
     
    28453098        return 1
    28463099    }
    2847     set workername [ditem_key $mport workername]
    2848     set provided_archs [$workername eval get_canonical_archs]
     3100    set provided_archs [_mport_archs $mport]
    28493101    if {$provided_archs == "noarch"} {
    28503102        return 1
     
    28563108    }
    28573109    return 1
     3110}
     3111
     3112# return the archs of the given mport
     3113proc macports::_mport_archs {mport} {
     3114    set workername [ditem_key $mport workername]
     3115    return [$workername eval get_canonical_archs]
    28583116}
    28593117
     
    28633121        return 1
    28643122    }
    2865     if {[catch {set ilist [registry::active $portname]}]} {
     3123    if {[catch {registry::active $portname}]} {
    28663124        return 0
    28673125    }
    2868     set i [lindex $ilist 0]
    2869     set regref [registry::open_entry $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
    2870     set provided_archs [registry::property_retrieve $regref archs]
     3126    set provided_archs [_active_archs $portname]
    28713127    if {$provided_archs == "noarch" || $provided_archs == "" || $provided_archs == 0} {
    28723128        return 1
     
    28783134    }
    28793135    return 1
     3136}
     3137
     3138# get the archs for a given active port
     3139proc macports::_active_archs {portname} {
     3140    if {[catch {set ilist [registry::active $portname]}]} {
     3141        return ""
     3142    }
     3143    set i [lindex $ilist 0]
     3144    set regref [registry::open_entry $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
     3145    return [registry::property_retrieve $regref archs]
    28803146}
    28813147
     
    29643230        rpm         -
    29653231        dpkg        {
    2966             if {[$workername eval _archive_available]} {
     3232            if {[global_option_isset ports_binary_only] ||
     3233                (![global_option_isset ports_source_only] && [$workername eval _archive_available])} {
    29673234                return "depends_lib depends_run"
    29683235            } else {
     
    29733240        activate    -
    29743241        ""          {
    2975             if {[$workername eval registry_exists \$subport \$version \$revision \$portvariants]
    2976                 || [$workername eval _archive_available]} {
     3242            if {[global_option_isset ports_binary_only] ||
     3243                [$workername eval registry_exists \$subport \$version \$revision \$portvariants]
     3244                || (![global_option_isset ports_source_only] && [$workername eval _archive_available])} {
    29773245                return "depends_lib depends_run"
    29783246            } else {
     
    30883356    # syncing ports tree.
    30893357    if {![info exists options(ports_selfupdate_nosync)] || $options(ports_selfupdate_nosync) != "yes"} {
    3090         ui_msg "$macports::ui_prefix Updating the ports tree"
    30913358        if {$comp > 0} {
    30923359            # updated portfiles potentially need new base to parse - tell sync to try to
     
    31403407            set cc_arg ""
    31413408            if {$::macports::os_platform == "darwin"} {
    3142                 set cc_arg "CC=/usr/bin/cc "
     3409                set cc_arg "CC=/usr/bin/cc OBJC=/usr/bin/cc "
    31433410            }
    31443411
    31453412            # do the actual configure, build and installation of new base
    31463413            ui_msg "Installing new MacPorts release in $prefix as $owner:$group; permissions $perms; Tcl-Package in $tclpackage\n"
    3147             if { [catch { system "cd $mp_source_path && ${cc_arg}./configure $configure_args && make && make install SELFUPDATING=1" } result] } {
     3414            if { [catch { system "cd $mp_source_path && ${cc_arg}./configure $configure_args && make SELFUPDATING=1 && make install SELFUPDATING=1" } result] } {
    31483415                return -code error "Error installing new MacPorts base: $result"
    31493416            }
     
    31793446
    31803447# upgrade API wrapper procedure
    3181 # return codes: 0 = success, 1 = general failure, 2 = port name not found in index
     3448# return codes:
     3449#   0 = success
     3450#   1 = general failure
     3451#   2 = port name not found in index
     3452#   3 = port not installed
    31823453proc macports::upgrade {portname dspec variationslist optionslist {depscachename ""}} {
    31833454    # only installed ports can be upgraded
    31843455    if {![registry::entry_exists_for_name $portname]} {
    31853456        ui_error "$portname is not installed"
    3186         return 1
     3457        return 3
    31873458    }
    31883459    if {![string match "" $depscachename]} {
     
    32253496    # Is this a rev-upgrade-called run?
    32263497    set is_revupgrade no
    3227     if {[macports::global_option_isset ports_revupgrade]} {
     3498    if {[info exists options(ports_revupgrade)] && $options(ports_revupgrade)} {
    32283499        set is_revupgrade yes
    32293500    }
    32303501    set is_revupgrade_second_run no
    3231     if {[macports::global_option_isset ports_revupgrade_second_run]} {
     3502    if {[info exists options(ports_revupgrade_second_run)] && $options(ports_revupgrade_second_run)} {
    32323503        set is_revupgrade_second_run yes
    32333504    }
     
    32803551               
    32813552                # upgrade its dependencies first
    3282                 set status [_upgrade_dependencies portinfo depscache variationslist options yes]
     3553                set status [_upgrade_dependencies portinfo depscache variationslist options]
    32833554                if {$status != 0 && $status != 2 && ![ui_isset ports_processall]} {
    32843555                    catch {mportclose $workername}
     
    34893760            set build_override 1
    34903761        } elseif {$is_revupgrade_second_run} {
     3762            ui_debug "rev-upgrade override ... upgrading (from source)!"
    34913763            set build_override 1
    34923764        } elseif {$is_revupgrade} {
     3765            ui_debug "rev-upgrade override ... upgrading!"
    34933766            # in the first run of rev-upgrade, only activate possibly already existing files and check for missing dependencies
    34943767            set will_install yes
     
    35083781
    35093782    set will_build no
     3783    set already_installed [registry::entry_exists $newname $version_in_tree $revision_in_tree $portinfo(canonical_active_variants)]
    35103784    # avoid building again unnecessarily
    35113785    if {$will_install &&
    35123786        ([info exists options(ports_upgrade_force)]
    35133787            || $build_override == 1
    3514             || ![registry::entry_exists $newname $version_in_tree $revision_in_tree $portinfo(canonical_active_variants)])} {
     3788            || !$already_installed)} {
    35153789        set will_build yes
    35163790    }
     
    35183792    # first upgrade dependencies
    35193793    if {![info exists options(ports_nodeps)] && !$is_revupgrade} {
    3520         set status [_upgrade_dependencies portinfo depscache variationslist options $will_build]
     3794        # the last arg is because we might have to build from source if a rebuild is being forced
     3795        set status [_upgrade_dependencies portinfo depscache variationslist options [expr $will_build && $already_installed]]
    35213796        if {$status != 0 && $status != 2 && ![ui_isset ports_processall]} {
    35223797            catch {mportclose $workername}
     
    35703845
    35713846    # are we installing an existing version due to force or epoch override?
    3572     if {[registry::entry_exists $newname $version_in_tree $revision_in_tree $portinfo(canonical_active_variants)]
     3847    if {$already_installed
    35733848        && ([info exists options(ports_upgrade_force)] || $build_override == 1)} {
    35743849         ui_debug "Uninstalling $newname ${version_in_tree}_${revision_in_tree}$portinfo(canonical_active_variants)"
     
    37023977# Calls upgrade on each dependency listed in the PortInfo.
    37033978# Uses upvar to access the variables.
    3704 proc macports::_upgrade_dependencies {portinfoname depscachename variationslistname optionsname {build_needed yes}} {
     3979proc macports::_upgrade_dependencies {portinfoname depscachename variationslistname optionsname {build_needed no}} {
    37053980    upvar $portinfoname portinfo $depscachename depscache \
    37063981          $variationslistname variationslist \
     
    37203995    unset -nocomplain options(ports_do_dependents)
    37213996
     3997    set parent_interp [ditem_key $parentworker workername]
     3998    # each required dep type is upgraded
     3999    if {$build_needed && ![global_option_isset ports_binary_only]} {
     4000        set dtypes [_deptypes_for_target destroot $parent_interp]
     4001    } else {
     4002        set dtypes [_deptypes_for_target install $parent_interp]
     4003    }
     4004
    37224005    set status 0
    3723     # each required dep type is upgraded
    3724     if {$build_needed} {
    3725         set dtypes {depends_fetch depends_extract depends_build depends_lib depends_run}
    3726     } else {
    3727         set dtypes {depends_lib depends_run}
    3728     }
    37294006    foreach dtype $dtypes {
    37304007        if {[info exists portinfo($dtype)]} {
    37314008            foreach i $portinfo($dtype) {
    3732                 set parent_interp [ditem_key $parentworker workername]
    37334009                set d [$parent_interp eval _get_dep_port $i]
    37344010                if {![llength [array get depscache port:${d}]] && ![llength [array get depscache $i]]} {
     
    38754151}
    38764152
     4153# check if the system we're on can run code of the given architecture
     4154proc macports::arch_runnable {arch} {
     4155    global macports::os_major macports::os_arch macports::os_platform
     4156    if {${macports::os_platform} == "darwin"} {
     4157        if {${macports::os_major} >= 11 && [string first "ppc" $arch] == 0} {
     4158            return no
     4159        } elseif {${macports::os_arch} == "i386" && $arch == "ppc64"} {
     4160            return no
     4161        } elseif {${macports::os_major} <= 8 && $arch == "x86_64"} {
     4162            return no
     4163        }
     4164    }
     4165    return yes
     4166}
     4167
    38774168proc macports::revupgrade {opts} {
    38784169    set run_loop 1
     
    38814172        set run_loop [revupgrade_scanandrebuild broken_port_counts $opts]
    38824173    }
    3883     return 0;
     4174    return 0
    38844175}
    38854176
    38864177# returns 1 if ports were rebuilt and revupgrade_scanandrebuild should be called again
    3887 proc revupgrade_scanandrebuild {broken_port_counts_name opts} {
     4178proc macports::revupgrade_scanandrebuild {broken_port_counts_name opts} {
    38884179    upvar $broken_port_counts_name broken_port_counts
    38894180    array set options $opts
    38904181
    38914182    set files [registry::file search active 1 binary -null]
    3892     if {[llength $files] > 0} {
    3893         set files_count [llength $files]
     4183    set files_count [llength $files]
     4184    set fancy_output [expr ![macports::ui_isset ports_debug] && [isatty stdout]]
     4185    if {$files_count > 0} {
    38944186        registry::write {
    38954187            try {
     
    38974189                set i 1
    38984190                foreach f $files {
    3899                     if {![macports::ui_isset ports_debug]} {
    3900                         ui_msg -nonewline "\r$macports::ui_prefix Updating database of binaries: [expr $i * 100 / $files_count]%"
    3901                         flush stdout
    3902                     }
    3903                     ui_debug "Updating binary flag for file $i of [llength $files]: [$f path]"
     4191                    if {$fancy_output} {
     4192                        if {$files_count < 10000 || $i % 10 == 1 || $i == $files_count} {
     4193                            ui_msg -nonewline "\r$macports::ui_prefix Updating database of binaries: [expr ($i * 1000 / $files_count) / 10.0]%"
     4194                            flush stdout
     4195                        }
     4196                    }
     4197                    set fpath [$f actual_path]
     4198                    ui_debug "Updating binary flag for file $i of $files_count: $fpath"
    39044199                    incr i
    3905                     $f binary [fileIsBinary [$f path]]
     4200
     4201                    if {0 != [catch {$f binary [fileIsBinary $fpath]} fileIsBinaryError]} {
     4202                        # handle errors (e.g. file not found, permission denied) gracefully
     4203                        if {$fancy_output} {
     4204                            ui_msg ""
     4205                        }
     4206                        ui_warn "Error determining file type of `$fpath': $fileIsBinaryError"
     4207                        ui_warn "A file belonging to the `[[registry::entry owner $fpath] name]' port is missing or unreadable. Consider reinstalling it."
     4208                    }
    39064209                }
    39074210            } catch {*} {
     
    39154218    set broken_files {};
    39164219    set binaries [registry::file search active 1 binary 1]
    3917     ui_msg -nonewline "$macports::ui_prefix Scanning binaries for linking errors"
    3918     if {[llength $binaries] > 0} {
     4220    set binary_count [llength $binaries]
     4221    if {$binary_count > 0} {
     4222        ui_msg -nonewline "$macports::ui_prefix Scanning binaries for linking errors"
    39194223        set handle [machista::create_handle]
    39204224        if {$handle == "NULL"} {
     
    39254229
    39264230        set i 1
    3927         set binary_count [llength $binaries]
    39284231        foreach b $binaries {
    3929             if {![macports::ui_isset ports_debug]} {
    3930                 ui_msg -nonewline "\r$macports::ui_prefix Scanning binaries for linking errors: [expr $i * 100 / $binary_count]%"
    3931                 flush stdout
    3932             }
    3933             #ui_debug "$i/[llength $binaries]: [$b path]"
     4232            if {$fancy_output} {
     4233                if {$binary_count < 10000 || $i % 10 == 1 || $i == $binary_count} {
     4234                    ui_msg -nonewline "\r$macports::ui_prefix Scanning binaries for linking errors: [expr ($i * 1000 / $binary_count) / 10.0]%"
     4235                    flush stdout
     4236                }
     4237            }
     4238            set bpath [$b actual_path]
     4239            #ui_debug "$i/$binary_count: $bpath"
    39344240            incr i
    39354241
    3936             set resultlist [machista::parse_file $handle [$b path]]
     4242            set resultlist [machista::parse_file $handle $bpath]
    39374243            set returncode [lindex $resultlist 0]
    39384244            set result     [lindex $resultlist 1]
     
    39424248                    # not a Mach-O file
    39434249                    # ignore silently, these are only static libs anyway
    3944                     #ui_debug "Error parsing file [$b path]: [machista::strerror $returncode]"
     4250                    #ui_debug "Error parsing file ${bpath}: [machista::strerror $returncode]"
    39454251                } else {
    3946                     if {![macports::ui_isset ports_debug]} {
     4252                    if {$fancy_output} {
    39474253                        ui_msg ""
    39484254                    }
    3949                     ui_warn "Error parsing file [$b path]: [machista::strerror $returncode]"
     4255                    ui_warn "Error parsing file ${bpath}: [machista::strerror $returncode]"
    39504256                }
    39514257                continue;
     
    39584264                        # check if this lib's install name actually refers to this file itself
    39594265                        # if this is not the case software linking against this library might have erroneous load commands
    3960                         if {0 == [catch {set idloadcmdpath [revupgrade_handle_special_paths [$b path] [$architecture cget -mat_install_name]]}]} {
     4266                        if {0 == [catch {set idloadcmdpath [revupgrade_handle_special_paths $bpath [$architecture cget -mat_install_name]]}]} {
    39614267                            if {[string index $idloadcmdpath 0] != "/"} {
    3962                                 set port [registry::entry owner [$b path]]
     4268                                set port [registry::entry owner $bpath]
    39634269                                if {$port != ""} {
    39644270                                    set portname [$port name]
     
    39664272                                    set portname "<unknown-port>"
    39674273                                }
    3968                                 if {![macports::ui_isset ports_debug]} {
     4274                                if {$fancy_output} {
    39694275                                    ui_msg ""
    39704276                                }
    3971                                 ui_warn "ID load command in [$b path], arch [machista::get_arch_name [$architecture cget -mat_arch]] (belonging to port $portname) contains relative path"
     4277                                ui_warn "ID load command in ${bpath}, arch [machista::get_arch_name [$architecture cget -mat_arch]] (belonging to port $portname) contains relative path"
    39724278                            } elseif {![file exists $idloadcmdpath]} {
    3973                                 set port [registry::entry owner [$b path]]
     4279                                set port [registry::entry owner $bpath]
    39744280                                if {$port != ""} {
    39754281                                    set portname [$port name]
     
    39774283                                    set portname "<unknown-port>"
    39784284                                }
    3979                                 if {![macports::ui_isset ports_debug]} {
     4285                                if {$fancy_output} {
    39804286                                    ui_msg ""
    39814287                                }
    3982                                 ui_warn "ID load command in [$b path], arch [machista::get_arch_name [$architecture cget -mat_arch]] refers to non-existant file $idloadcmdpath"
     4288                                ui_warn "ID load command in ${bpath}, arch [machista::get_arch_name [$architecture cget -mat_arch]] refers to non-existant file $idloadcmdpath"
    39834289                                ui_warn "This is probably a bug in the $portname port and might cause problems in libraries linking against this file"
    39844290                            } else {
    39854291   
    3986                                 set hash_this [sha256 file [$b path]]
     4292                                set hash_this [sha256 file $bpath]
    39874293                                set hash_idloadcmd [sha256 file $idloadcmdpath]
    39884294   
    39894295                                if {$hash_this != $hash_idloadcmd} {
    3990                                     set port [registry::entry owner [$b path]]
     4296                                    set port [registry::entry owner $bpath]
    39914297                                    if {$port != ""} {
    39924298                                        set portname [$port name]
     
    39944300                                        set portname "<unknown-port>"
    39954301                                    }
    3996                                     if {![macports::ui_isset ports_debug]} {
     4302                                    if {$fancy_output} {
    39974303                                        ui_msg ""
    39984304                                    }
    3999                                     ui_warn "ID load command in [$b path], arch [machista::get_arch_name [$architecture cget -mat_arch]] refers to file $idloadcmdpath, which is a different file"
     4305                                    ui_warn "ID load command in ${bpath}, arch [machista::get_arch_name [$architecture cget -mat_arch]] refers to file $idloadcmdpath, which is a different file"
    40004306                                    ui_warn "This is probably a bug in the $portname port and might cause problems in libraries linking against this file"
    40014307                                }
     
    40044310                    }
    40054311                }
     4312
     4313                set archname [machista::get_arch_name [$architecture cget -mat_arch]]
     4314                if {![arch_runnable $archname]} {
     4315                    ui_debug "skipping $archname in $bpath since this system can't run it anyway"
     4316                    set architecture [$architecture cget -next]
     4317                    continue
     4318                }
     4319
    40064320                set loadcommand [$architecture cget -mat_loadcmds]
    40074321
    40084322                while {$loadcommand != "NULL"} {
    4009                     if {0 != [catch {set filepath [revupgrade_handle_special_paths [$b path] [$loadcommand cget -mlt_install_name]]}]} {
     4323                    if {0 != [catch {set filepath [revupgrade_handle_special_paths $bpath [$loadcommand cget -mlt_install_name]]}]} {
    40104324                        set loadcommand [$loadcommand cget -next]
    40114325                        continue;
     
    40184332                    if {$libreturncode != $machista::SUCCESS} {
    40194333                        if {![info exists files_warned_about($filepath)]} {
    4020                             if {![macports::ui_isset ports_debug]} {
     4334                            if {[macports::ui_isset ports_verbose]} {
    40214335                                ui_msg ""
    40224336                            }
    4023                             ui_warn "Could not open $filepath: [machista::strerror $libreturncode]"
     4337                            ui_info "Could not open $filepath: [machista::strerror $libreturncode] (referenced from $bpath)"
    40244338                            set files_warned_about($filepath) yes
    40254339                        }
    40264340                        if {$libreturncode == $machista::EFILE} {
    4027                             ui_debug "Marking [$b path] as broken"
    4028                             lappend broken_files [$b path]
     4341                            ui_debug "Marking $bpath as broken"
     4342                            lappend broken_files $bpath
    40294343                        }
    40304344                        set loadcommand [$loadcommand cget -next]
     
    40414355
    40424356                        if {[$loadcommand cget -mlt_version] != [$libarchitecture cget -mat_version] && [$loadcommand cget -mlt_comp_version] > [$libarchitecture cget -mat_comp_version]} {
    4043                             if {![macports::ui_isset ports_debug]} {
     4357                            if {[macports::ui_isset ports_verbose]} {
    40444358                                ui_msg ""
    40454359                            }
    4046                             ui_warn "Incompatible library version of file [$loadcommand cget -mlt_install_name]: Expected [$loadcommand cget -mlt_comp_version], but got [$libarchitecture cget -mat_comp_version]"
    4047                             ui_debug "Marking [$b path] as broken"
    4048                             lappend broken_files [$b path]
     4360                            ui_info "Incompatible library version: $bpath requires version [machista::format_dylib_version [$loadcommand cget -mlt_comp_version]] or later, but $filepath provides version [machista::format_dylib_version [$libarchitecture cget -mat_comp_version]]"
     4361                            ui_debug "Marking $bpath as broken"
     4362                            lappend broken_files $bpath
    40494363                        }
    40504364
     
    40564370                        ui_debug "Missing architecture [machista::get_arch_name [$architecture cget -mat_arch]] in file $filepath"
    40574371                        if {[path_is_in_prefix $filepath]} {
    4058                             ui_debug "Marking [$b path] as broken"
    4059                             lappend broken_files [$b path]
     4372                            ui_debug "Marking $bpath as broken"
     4373                            lappend broken_files $bpath
    40604374                        } else {
    4061                             ui_debug "Missing architecture [machista::get_arch_name [$architecture cget -mat_arch]] in file outside prefix referenced from [$b path]"
     4375                            ui_debug "Missing architecture [machista::get_arch_name [$architecture cget -mat_arch]] in file outside prefix referenced from $bpath"
    40624376                            # ui_debug "   How did you get that compiled anyway?"
    40634377                        }
     
    40744388
    40754389        if {[llength $broken_files] == 0} {
    4076             ui_msg "$macports::ui_prefix No broken files found. :)"
    4077             return 0;
     4390            ui_msg "$macports::ui_prefix No broken files found."
     4391            return 0
    40784392        }
    40794393        ui_msg "$macports::ui_prefix Found [llength $broken_files] broken file(s), matching files to ports"
     
    40824396        foreach file $broken_files {
    40834397            set port [registry::entry owner $file]
    4084             if {$port == ""} {
     4398            if {$port != ""} {
     4399                lappend broken_ports $port
     4400                lappend broken_files_by_port($port) $file
     4401            } else {
    40854402                ui_error "Broken file $file doesn't belong to any port."
    40864403            }
     4404        }
     4405        set broken_ports [lsort -unique $broken_ports]
     4406
     4407        if {${macports::revupgrade_mode} == "rebuild"} {
     4408            # don't try to rebuild ports that don't exist in the tree
     4409            set temp_broken_ports {}
     4410            foreach port $broken_ports {
     4411                set portname [$port name]
     4412                if {[catch {mportlookup $portname} result]} {
     4413                    ui_debug "$::errorInfo"
     4414                    error "lookup of portname $portname failed: $result"
     4415                }
     4416                if {[llength $result] >= 2} {
     4417                    lappend temp_broken_ports $port
     4418                } else {
     4419                    ui_warn "No port $portname found in the index; can't rebuild"
     4420                }
     4421            }
     4422
     4423            if {[llength $temp_broken_ports] == 0} {
     4424                ui_msg "$macports::ui_prefix Broken files found, but all associated ports are not in the index and so cannot be rebuilt."
     4425                return 0
     4426            }
     4427        } else {
     4428            set temp_broken_ports $broken_ports
     4429        }
     4430
     4431        set broken_ports {}
     4432
     4433        foreach port $temp_broken_ports {
     4434            set portname [$port name]
     4435
     4436            if {![info exists broken_port_counts($portname)]} {
     4437                set broken_port_counts($portname) 0
     4438            }
     4439            incr broken_port_counts($portname)
     4440            if {$broken_port_counts($portname) > 3} {
     4441                ui_error "Port $portname is still broken after rebuilding it more than 3 times."
     4442                if {$fancy_output} {
     4443                    ui_error "Please run port -d -y rev-upgrade and use the output to report a bug."
     4444                }
     4445                error "Port $portname still broken after rebuilding [expr $broken_port_counts($portname) - 1] time(s)"
     4446            } elseif {$broken_port_counts($portname) > 1 && [global_option_isset ports_binary_only]} {
     4447                error "Port $portname still broken after reinstalling -- can't rebuild due to binary-only mode"
     4448            }
    40874449            lappend broken_ports $port
    40884450        }
    4089         set broken_ports [lsort -unique $broken_ports]
    4090 
    4091         foreach port $broken_ports {
    4092             if {![info exists broken_port_counts([$port name])]} {
    4093                 set broken_port_counts([$port name]) 0
    4094             }
    4095             incr broken_port_counts([$port name])
    4096             if {$broken_port_counts([$port name]) > 3} {
    4097                 ui_error "Port [$port name] is still broken after rebuiling it more than 3 times. You might want to file a bug for this."
    4098                 error "Port [$port name] still broken after rebuilding [expr $broken_port_counts([$port name]) - 1] time(s)"
    4099             }
     4451        unset temp_broken_ports
     4452
     4453        if {${macports::revupgrade_mode} != "rebuild"} {
     4454            ui_msg "$macports::ui_prefix Found [llength $broken_ports] broken port(s):"
     4455            foreach port $broken_ports {
     4456                ui_msg "     [$port name] @[$port version] [$port variants][$port negated_variants]"
     4457                foreach f $broken_files_by_port($port) {
     4458                    ui_msg "         $f"
     4459                }
     4460            }
     4461            return 0
    41004462        }
    41014463
     
    41074469            set adjlist($port) {}
    41084470            set revadjlist($port) {}
     4471            ui_debug "Broken: [$port name]"
    41094472        }
    41104473
     
    41244487        set topsort_ports {}
    41254488        while {[llength $unsorted_ports] > 0} {
     4489            set lowest_adj_number [llength $adjlist([lindex $unsorted_ports 0])]
     4490            set lowest_adj_port [lindex $unsorted_ports 0]
     4491
    41264492            foreach port $unsorted_ports {
    4127                 if {[llength $adjlist($port)] == 0} {
     4493                set len [llength $adjlist($port)]
     4494                if {$len < $lowest_adj_number} {
     4495                    set lowest_adj_port $port
     4496                    set lowest_adj_number $len
     4497                }
     4498                if {$len == 0} {
    41284499                    # this node has no further dependencies
    41294500                    # add it to topsorted list
     
    41384509                        set adjlist($target) [lreplace $adjlist($target) $index $index]
    41394510                    }
     4511
     4512                    break;
     4513                }
     4514            }
     4515
     4516            # if we arrive here and lowest_adj_number is larger than 0, then we
     4517            # have a loop in the graph and need to break it somehow
     4518            if {$lowest_adj_number > 0} {
     4519                ui_debug "Breaking loop in dependency graph by starting with [$lowest_adj_port name], which has $lowest_adj_number dependencies"
     4520                lappend topsort_ports $lowest_adj_port
     4521
     4522                set index [lsearch -exact $unsorted_ports $lowest_adj_port]
     4523                set unsorted_ports [lreplace $unsorted_ports $index $index]
     4524
     4525                foreach target $revadjlist($port) {
     4526                    set index [lsearch -exact $adjlist($target) $lowest_adj_port]
     4527                    set adjlist($target) [lreplace $adjlist($target) $index $index]
    41404528                }
    41414529            }
     
    41504538        array set depscache {}
    41514539        set status 0
     4540        array set my_options [array get macports::global_options]
    41524541        foreach port $topsort_ports {
    4153             if {![info exists depscache(port:[$port name])]} {
    4154 
    4155                 # convert variations into the format macports::upgrade needs
    4156                 set minusvariant [lrange [split [$port negated_variants] "-"] 1 end]
    4157                 set plusvariant  [lrange [split [$port variants]         "+"] 1 end]
    4158                 set variants     [list]
    4159                 foreach v $minusvariant {
    4160                     lappend variants $v "-"
    4161                 }
    4162                 foreach v $plusvariant {
    4163                     lappend variants $v "+"
    4164                 }
    4165                 array unset variations
    4166                 array set variations $variants
    4167 
     4542            set portname [$port name]
     4543            if {![info exists depscache(port:$portname)]} {
    41684544                # set rev-upgrade options and nodeps if this is not the first run
    4169                 set macports::global_options(ports_revupgrade) "yes"
    4170                 unset -nocomplain macports::global_options(ports_nodeps)
    4171                 unset -nocomplain macports::global_options(ports_revupgrade_second_run)
    4172                 unset -nocomplain macports::global_options(ports_source_only)
    4173                 if {$broken_port_counts([$port name]) > 1} {
    4174                     set macports::global_options(ports_revupgrade_second_run) yes
    4175                     set macports::global_options(ports_nodeps) yes
     4545                set my_options(ports_revupgrade) "yes"
     4546                unset -nocomplain my_options(ports_nodeps)
     4547                unset -nocomplain my_options(ports_revupgrade_second_run)
     4548                if {$broken_port_counts($portname) > 1} {
     4549                    set my_options(ports_revupgrade_second_run) yes
     4550                    set my_options(ports_nodeps) yes
    41764551                    # build from source only until the buildbot has some method of rev-upgrade, too
    4177                     set macports::global_options(ports_source_only) yes
     4552                    set my_options(ports_source_only) yes
    41784553                }
    41794554
    41804555                # call macports::upgrade with ports_revupgrade option to rebuild the port
    4181                 set status [macports::upgrade [$port name] "port:[$port name]" \
    4182                     [array get variations] [array get macports::global_options] depscache]
     4556                set status [macports::upgrade $portname "port:$portname" \
     4557                    {} [array get my_options] depscache]
     4558                ui_debug "Rebuilding port $portname finished with status $status"
    41834559                if {$status != 0} {
    4184                     error "Error rebuilding [$port name]"
     4560                    error "Error rebuilding $portname"
    41854561                }
    41864562            }
     
    42004576# Usage: path_is_in_prefix path_to_test
    42014577# Returns true if the path is in the prefix, false otherwise
    4202 proc path_is_in_prefix {path} {
     4578proc macports::path_is_in_prefix {path} {
     4579    global macports::prefix macports::applications_dir
    42034580    if {[string first $macports::prefix $path] == 0} {
    42044581        return yes
     
    42164593# Replacing @rpath does not work yet, but it might be possible to get it working using the rpath attribute in the file containing the
    42174594# loadcommand
    4218 proc revupgrade_handle_special_paths {fname path} {
     4595proc macports::revupgrade_handle_special_paths {fname path} {
    42194596    set corrected_path $path
    42204597
     
    42264603    set executablepath_idx [string first "@executable_path" $corrected_path]
    42274604    if {$executablepath_idx != -1} {
    4228         ui_debug "Ignoring loadcommand containing @exectuable_path in $fname"
    4229         error "@exectuable_path in loadcommand"
     4605        ui_debug "Ignoring loadcommand containing @executable_path in $fname"
     4606        error "@executable_path in loadcommand"
    42304607    }
    42314608
     
    42414618# Recursively build the dependency graph between broken ports
    42424619# Usage: revupgrade_buildgraph start_port name_of_stack name_of_adjacency_list name_of_reverse_adjacency_list name_of_visited_map
    4243 proc revupgrade_buildgraph {port stackname adjlistname revadjlistname visitedname} {
     4620proc macports::revupgrade_buildgraph {port stackname adjlistname revadjlistname visitedname} {
    42444621    upvar $stackname stack
    42454622    upvar $adjlistname adjlist
     
    42474624    upvar $visitedname visited
    42484625
     4626    set visited($port) true
     4627
    42494628    ui_debug "Processing port [$port name] @[$port epoch]:[$port version]_[$port revision] [$port variants] [$port negated_variants]"
    42504629    set dependent_ports [$port dependents]
    42514630    foreach dep $dependent_ports {
    4252         if {[info exists visited($dep)]} {
    4253             continue
    4254         }
    4255         set visited($dep) true
    42564631        set is_broken_port false
    42574632
    42584633        if {[info exists adjlist($dep)]} {
    4259             #ui_debug "Dependency [$dep name] is broken, adding edge from [[lindex $stack 0] name] to [$dep name]"
    4260             #ui_debug "Making [$dep name] new head of stack"
     4634            ui_debug "Dependent [$dep name] is broken, adding edge from [$dep name] to [[lindex $stack 0] name]"
     4635            ui_debug "Making [$dep name] new head of stack"
    42614636            # $dep is one of the broken ports
    42624637            # add an edge to the last broken port in the DFS
     
    42684643            set is_broken_port true
    42694644        }
    4270         revupgrade_buildgraph $dep stack adjlist revadjlist visited
     4645        if {![info exists visited($dep)]} {
     4646            revupgrade_buildgraph $dep stack adjlist revadjlist visited
     4647        }
    42714648        if {$is_broken_port} {
    4272             #ui_debug "Removing [$dep name] from stack"
     4649            ui_debug "Removing [$dep name] from stack"
    42734650            # remove $dep from the stack
    42744651            set stack [lrange $stack 1 end]
     
    42774654}
    42784655
     4656# get cached ping time for host, modified by blacklist and preferred list
     4657proc macports::get_pingtime {host} {
     4658    global macports::ping_cache macports::host_blacklisted macports::host_preferred
     4659    if {[info exists host_blacklisted($host)]} {
     4660        return -1
     4661    } elseif {[info exists host_preferred($host)]} {
     4662        return 1
     4663    } elseif {[info exists ping_cache($host)]} {
     4664        # expire entries after 1 day
     4665        if {[expr [clock seconds] - [lindex $ping_cache($host) 1]] <= 86400} {
     4666            return [lindex $ping_cache($host) 0]
     4667        }
     4668    }
     4669    return {}
     4670}
     4671
     4672# cache a ping time of ms for host
     4673proc macports::set_pingtime {host ms} {
     4674    global macports::ping_cache
     4675    set ping_cache($host) [list $ms [clock seconds]]
     4676}
     4677
     4678# read and cache archive_sites.conf (called from port1.0 code)
     4679proc macports::get_archive_sites_conf_values {} {
     4680    global macports::archive_sites_conf_values macports::autoconf::macports_conf_path
     4681    if {![info exists archive_sites_conf_values]} {
     4682        set archive_sites_conf_values {}
     4683        set all_names {}
     4684        array set defaults {applications_dir /Applications/MacPorts prefix /opt/local type tbz2}
     4685        set conf_file "${macports_conf_path}/archive_sites.conf"
     4686        set conf_options {applications_dir frameworks_dir name prefix type urls}
     4687        if {[file isfile $conf_file]} {
     4688            set fd [open $conf_file r]
     4689            while {[gets $fd line] >= 0} {
     4690                if {[regexp {^(\w+)([ \t]+(.*))?$} $line match option ignore val] == 1} {
     4691                    if {[lsearch -exact $conf_options $option] >= 0} {
     4692                        if {$option == "name"} {
     4693                            set cur_name $val
     4694                            lappend all_names $val
     4695                        } elseif {[info exists cur_name]} {
     4696                            set trimmedval [string trim $val]
     4697                            if {$option == "urls"} {
     4698                                set processed_urls {}
     4699                                foreach url $trimmedval {
     4700                                    lappend processed_urls ${url}:nosubdir
     4701                                }
     4702                                lappend archive_sites_conf_values portfetch::mirror_sites::sites($cur_name) $processed_urls
     4703                                set sites($cur_name) $processed_urls
     4704                            } else {
     4705                                lappend archive_sites_conf_values portfetch::mirror_sites::archive_${option}($cur_name) $trimmedval
     4706                                set archive_${option}($cur_name) $trimmedval
     4707                            }
     4708                        } else {
     4709                            ui_warn "archive_sites.conf: ignoring '$option' occurring before name"
     4710                        }
     4711                    } else {
     4712                        ui_warn "archive_sites.conf: ignoring unknown key '$option'"
     4713                    }
     4714                }
     4715            }
     4716            close $fd
     4717
     4718            # check for unspecified values and set to defaults
     4719            foreach cur_name $all_names {
     4720                foreach key [array names defaults] {
     4721                    if {![info exists archive_${key}($cur_name)]} {
     4722                        set archive_${key}($cur_name) $defaults($key)
     4723                        lappend archive_sites_conf_values portfetch::mirror_sites::archive_${key}($cur_name) $defaults($key)
     4724                    }
     4725                }
     4726                if {![info exists archive_frameworks_dir($cur_name)]} {
     4727                    set archive_frameworks_dir($cur_name) $archive_prefix($cur_name)/Library/Frameworks
     4728                    lappend archive_sites_conf_values portfetch::mirror_sites::archive_frameworks_dir($cur_name) $archive_frameworks_dir($cur_name)
     4729                }
     4730                if {![info exists sites($cur_name)]} {
     4731                    ui_warn "archive_sites.conf: no urls set for $cur_name"
     4732                    set sites($cur_name) ""
     4733                    lappend archive_sites_conf_values portfetch::mirror_sites::sites($cur_name) ""
     4734                }
     4735            }
     4736        }
     4737    }
     4738    return $archive_sites_conf_values
     4739}
  • branches/gsoc11-statistics/base/src/macports1.0/macports_autoconf.tcl.in

    r79672 r105085  
    4141    variable macports_user_dir "~/.macports"
    4242    variable macportsuser "@RUNUSR@"
     43    variable mdfind_path "@MDFIND@"
     44    variable mdls_path "@MDLS@"
    4345    variable open_path "@OPEN@"
    4446    variable openssl_path "@OPENSSL@"
     
    5052    variable unzip_path "@UNZIP@"
    5153    variable xar_path "@XAR@"
     54    variable xcode_select_path "@XCODE_SELECT@"
     55    variable xcodebuild_path "@XCODEBUILD@"
    5256}
  • branches/gsoc11-statistics/base/src/macports1.0/macports_dlist.tcl

    r79672 r105085  
    307307        while {1} {
    308308                set ditem [$selector $dlist statusdict]
    309                
     309
    310310                if {$ditem == {}} {
     311                    if {[llength $dlist] > 0} {
     312                        ui_debug "dlist_eval: all entries in dependency list have unsatisfied dependencies; can't process"
     313                    }
    311314                        break
    312315                } else {
  • branches/gsoc11-statistics/base/src/macports1.0/macports_index.tcl

    r79672 r105085  
    279279# from the specified URL.  The port is extracted into the current working
    280280# directory along with a .mports_source file containing the url of the
    281 # source the port came from.  (This can be later used as a default for
    282 # "port submit")
     281# source the port came from.
    283282#
    284283# The cached portfiles are in the same directory as the cached remote index.
  • branches/gsoc11-statistics/base/src/package1.0/Makefile

    r77511 r105085  
    11INSTALLDIR=     ${DESTDIR}${datadir}/macports/Tcl/package1.0
    22
    3 SRCS=   package.tcl portdmg.tcl portmdmg.tcl portmpkg.tcl portpkg.tcl portportpkg.tcl \
     3SRCS=   package.tcl portdmg.tcl portmdmg.tcl portmpkg.tcl portpkg.tcl \
    44        portrpm.tcl portsrpm.tcl portdpkg.tcl portunarchive.tcl \
    55        portarchivefetch.tcl
  • branches/gsoc11-statistics/base/src/package1.0/package.tcl

    r79672 r105085  
    1818#    may be used to endorse or promote products derived from this software
    1919#    without specific prior written permission.
    20 # 
     20#
    2121# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    2222# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     
    4141package require portmdmg 1.0
    4242package require portdpkg 1.0
    43 package require portportpkg 1.0
    4443package require portarchivefetch 1.0
    4544package require portunarchive 1.0
  • branches/gsoc11-statistics/base/src/package1.0/portarchivefetch.tcl

    r82923 r105085  
    33#
    44# Copyright (c) 2002 - 2003 Apple Inc.
    5 # Copyright (c) 2004 - 2011 The MacPorts Project
     5# Copyright (c) 2004 - 2012 The MacPorts Project
    66# All rights reserved.
    77#
     
    3737
    3838set org.macports.archivefetch [target_new org.macports.archivefetch portarchivefetch::archivefetch_main]
    39 target_init ${org.macports.archivefetch} portarchivefetch::archivefetch_init
     39#target_init ${org.macports.archivefetch} portarchivefetch::archivefetch_init
    4040target_provides ${org.macports.archivefetch} archivefetch
    4141target_requires ${org.macports.archivefetch} main
     
    6666
    6767proc portarchivefetch::filter_sites {} {
    68     global prefix porturl
     68    global prefix frameworks_dir applications_dir porturl \
     69        portfetch::mirror_sites::sites portfetch::mirror_sites::archive_type \
     70        portfetch::mirror_sites::archive_prefix \
     71        portfetch::mirror_sites::archive_frameworks_dir \
     72        portfetch::mirror_sites::archive_applications_dir
     73
     74    # get defaults from ports tree resources
    6975    set mirrorfile [get_full_archive_sites_path]
    7076    if {[file exists $mirrorfile]} {
    7177        source $mirrorfile
    7278    }
     79    # get archive_sites.conf values
     80    foreach {key val} [get_archive_sites_conf_values] {
     81        set $key $val
     82    }
     83
    7384    set ret {}
    7485    foreach site [array names portfetch::mirror_sites::archive_prefix] {
    75         if {$portfetch::mirror_sites::archive_prefix($site) == $prefix} {
    76             lappend ret $site
    77         }
    78     }
    79     if {[file rootname [file tail $porturl]] == [file rootname [file tail [get_portimage_path]]]} {
    80         lappend ret [string range $porturl 0 end-[string length [file tail $porturl]]]
     86        set missing 0
     87        foreach var {archive_frameworks_dir archive_applications_dir archive_type} {
     88            if {![info exists portfetch::mirror_sites::${var}($site)]} {
     89                ui_warn "no $var configured for site '$site'"
     90                set missing 1
     91            }
     92        }
     93        if {$missing} {
     94            continue
     95        }
     96        if {$portfetch::mirror_sites::archive_prefix($site) == $prefix &&
     97            $portfetch::mirror_sites::archive_frameworks_dir($site) == $frameworks_dir &&
     98            $portfetch::mirror_sites::archive_applications_dir($site) == $applications_dir &&
     99            ![catch {archiveTypeIsSupported $portfetch::mirror_sites::archive_type($site)}]} {
     100            # using the archive type as a tag
     101            lappend ret ${site}::$portfetch::mirror_sites::archive_type($site)
     102        }
     103    }
     104
     105    # check if porturl itself points to an archive
     106    if {[file rootname [file tail $porturl]] == [file rootname [get_portimage_name]] && [file extension $porturl] != ""} {
     107        lappend ret [string range $porturl 0 end-[string length [file tail $porturl]]]:[string range [file extension $porturl] 1 end]
    81108        archive.subdir
    82109    }
     
    88115# Checks possible archive files to assemble url lists for later fetching
    89116proc portarchivefetch::checkarchivefiles {urls} {
    90     global all_archive_files archivefetch.fulldestpath portarchivetype \
    91            version revision portvariants archive_sites
     117    global all_archive_files archivefetch.fulldestpath archive_sites
    92118    upvar $urls fetch_urls
    93119
    94120    # Define archive directory path
    95     set archive.path [get_portimage_path]
    96     set archivefetch.fulldestpath [file dirname ${archive.path}]
    97 
    98     # throws an error if unsupported
    99     archiveTypeIsSupported $portarchivetype
    100 
    101     set archive.file [file tail ${archive.path}]
    102     lappend all_archive_files ${archive.file}
    103     if {[info exists archive_sites]} {
    104         lappend fetch_urls archive_sites ${archive.file}
     121    set archivefetch.fulldestpath [file join [option portdbpath] incoming/verified]
     122    set archive.rootname [file rootname [get_portimage_name]]
     123
     124    foreach entry [option archive_sites] {
     125        # the archive type is used as a tag
     126        set type [lindex [split $entry :] end]
     127        if {![info exists seen($type)]} {
     128            set archive.file "${archive.rootname}.${type}"
     129            lappend all_archive_files ${archive.file}
     130            lappend fetch_urls $type ${archive.file}
     131            set seen($type) 1
     132        }
    105133    }
    106134}
     
    142170    }
    143171    set incoming_path [file join [option portdbpath] incoming]
    144     if {![file isdirectory $incoming_path]} {
    145         if {[catch {file mkdir $incoming_path} result]} {
    146             elevateToRoot "archivefetch"
    147             set elevated yes
    148             if {[catch {file mkdir $incoming_path} result]} {
    149                 return -code error [format [msgcat::mc "Unable to create archive fetch path: %s"] $result]
    150             }
    151         }
    152     }
    153     chownAsRoot ${archivefetch.fulldestpath}
    154172    chownAsRoot $incoming_path
    155173    if {[info exists elevated] && $elevated == yes} {
     
    173191    set sorted no
    174192
     193    set existing_archive [find_portarchive_path]
     194
    175195    foreach {url_var archive} $archivefetch_urls {
    176         if {![file isfile ${archivefetch.fulldestpath}/${archive}]} {
     196        if {![file isfile ${archivefetch.fulldestpath}/${archive}] && $existing_archive == ""} {
    177197            ui_info "$UI_PREFIX [format [msgcat::mc "%s doesn't seem to exist in %s"] $archive ${archivefetch.fulldestpath}]"
    178198            if {![file writable ${archivefetch.fulldestpath}]} {
     
    190210                set urlmap($url_var) $urlmap(archive_sites)
    191211            }
     212            set failed_sites 0
    192213            unset -nocomplain fetched
    193214            foreach site $urlmap($url_var) {
     
    207228                    ui_debug "[msgcat::mc "Fetching archive failed:"]: $result"
    208229                    file delete -force "${incoming_path}/${archive}.TMP"
     230                    incr failed_sites
     231                    if {$failed_sites > 2 && ![tbool ports_binary_only] && ![_archive_available]} {
     232                        break
     233                    }
    209234                }
    210235            }
     
    229254                    }
    230255                }
     256                file delete -force $signature
    231257                if {!$verified} {
    232                     return -code error "Failed to verify signature for archive!"
    233                 }
    234                 if {[catch {file rename -force "${incoming_path}/${archive}.TMP" "${archivefetch.fulldestpath}/${archive}"} result]} {
     258                    # fall back to building from source (or error out later if binary only mode)
     259                    ui_warn "Failed to verify signature for archive!"
     260                    file delete -force "${incoming_path}/${archive}.TMP"
     261                    break
     262                } elseif {[catch {file rename -force "${incoming_path}/${archive}.TMP" "${archivefetch.fulldestpath}/${archive}"} result]} {
    235263                    ui_debug "$::errorInfo"
    236264                    return -code error "Failed to move downloaded archive into place: $result"
    237265                }
    238                 file delete -force $signature
    239266                set archive_exists 1
     267                break
    240268            }
    241269        } else {
    242270            set archive_exists 1
     271            break
    243272        }
    244273    }
     
    259288
    260289# Initialize archivefetch target and call checkfiles.
    261 proc portarchivefetch::archivefetch_init {args} {
    262     global porturl portarchivetype
    263     # installing straight from a binary archive
    264     if {[file rootname [file tail $porturl]] == [file rootname [file tail [get_portimage_path]]] && [file extension $porturl] != ""} {
    265         set portarchivetype [string range [file extension $porturl] 1 end]
    266     }
    267     return 0
    268 }
     290#proc portarchivefetch::archivefetch_init {args} {
     291#    return 0
     292#}
    269293
    270294proc portarchivefetch::archivefetch_start {args} {
    271295    variable archivefetch_urls
    272     global UI_PREFIX subport all_archive_files ports_source_only
    273     if {![tbool ports_source_only]} {
     296    global UI_PREFIX subport all_archive_files destroot target_state_fd \
     297           ports_source_only ports_binary_only
     298    if {![tbool ports_source_only] && ([tbool ports_binary_only] ||
     299            !([check_statefile target org.macports.destroot $target_state_fd] && [file isdirectory $destroot]))} {
    274300        portarchivefetch::checkfiles archivefetch_urls
    275301    }
     
    277303        ui_msg "$UI_PREFIX [format [msgcat::mc "Fetching archive for %s"] $subport]"
    278304    }
     305    portfetch::check_dns
    279306}
    280307
  • branches/gsoc11-statistics/base/src/package1.0/portdmg.tcl

    r79672 r105085  
    1818#    may be used to endorse or promote products derived from this software
    1919#    without specific prior written permission.
    20 # 
     20#
    2121# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    2222# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     
    3737set org.macports.dmg [target_new org.macports.dmg portdmg::dmg_main]
    3838target_runtype ${org.macports.dmg} always
    39 target_provides ${org.macports.dmg} dmg 
     39target_provides ${org.macports.dmg} dmg
    4040target_requires ${org.macports.dmg} pkg
    4141
     
    5151
    5252    if {[getuid] == 0 && [geteuid] != 0} {
    53                 setegid 0; seteuid 0
     53                seteuid 0; setegid 0
    5454        }
    5555
     
    6060    global UI_PREFIX package.destpath portpath
    6161    global os.platform os.arch os.version os.major
    62    
     62
    6363    if {[expr (${portrevision} > 0)]} {
    6464        set imagename "${portname}-${portversion}-${portrevision}"
     
    6666        set imagename "${portname}-${portversion}"
    6767    }
    68    
     68
    6969    set tmp_image ${package.destpath}/${imagename}.tmp.dmg
    7070    set final_image ${package.destpath}/${imagename}.dmg
    7171    set pkgpath ${package.destpath}/${portname}-${portversion}.pkg
    72    
     72
    7373    if {[file readable $final_image] && ([file mtime ${final_image}] >= [file mtime ${portpath}/Portfile])} {
    7474        ui_msg "$UI_PREFIX [format [msgcat::mc "Disk Image for %s-%s is up-to-date"] ${portname} ${portversion}]"
     
    8484        set subdev 2
    8585    }
    86    
     86
     87    if {![file isdirectory $pkgpath]} {
     88        file mkdir ${package.destpath}/${imagename}
     89        file copy $pkgpath ${package.destpath}/${imagename}
     90        set pkgpath ${package.destpath}/${imagename}
     91    }
     92
    8793    set hdiutil [findBinary hdiutil $portutil::autoconf::hdiutil_path]
    8894    if {[system "$hdiutil create -quiet -fs HFS+ -volname ${imagename} -srcfolder ${pkgpath} ${tmp_image}"] != ""} {
     
    96102    }
    97103    file delete -force "${tmp_image}"
    98    
     104
    99105    return 0
    100106}
  • branches/gsoc11-statistics/base/src/package1.0/portdpkg.tcl

    r82923 r105085  
    1919#    may be used to endorse or promote products derived from this software
    2020#    without specific prior written permission.
    21 # 
     21#
    2222# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    2323# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     
    5555proc portdpkg::main {args} {
    5656        global UI_PREFIX destpath os.arch os.platform supported_archs configure.build_arch
    57    
     57
    5858        ui_msg "$UI_PREFIX [format [msgcat::mc "Creating dpkg for %s-%s"] [option subport] [option version]]"
    5959
     
    9696                }
    9797        }
    98        
     98
    9999        # Create dpkg version number
    100100        if {[expr [option epoch] != 0]} {
     
    126126        # Discern correct architecture
    127127        # From http://www.debian.org/doc/debian-policy/ch-customized-programs.html#fr55:
    128         # The following architectures and operating systems are currently recognised   
    129         # by dpkg-archictecture. The architecture, arch, is one of the following:     
    130         # alpha, arm, hppa, i386, ia64, m68k, mips, mipsel, powerpc, s390, sh, sheb,   
    131         # sparc and sparc64. The operating system, os, is one of: linux, gnu,         
    132         # freebsd and openbsd. Use of gnu in this string is reserved for the           
     128        # The following architectures and operating systems are currently recognised
     129        # by dpkg-archictecture. The architecture, arch, is one of the following:
     130        # alpha, arm, hppa, i386, ia64, m68k, mips, mipsel, powerpc, s390, sh, sheb,
     131        # sparc and sparc64. The operating system, os, is one of: linux, gnu,
     132        # freebsd and openbsd. Use of gnu in this string is reserved for the
    133133        # GNU/Hurd operating system.
    134134        switch -regex ${configure.build_arch} {
     
    145145                set pkg_arch "amd64"
    146146        }
    147        
     147
    148148        # An architecture-independent package
    149149        if {$supported_archs == "noarch"} {
     
    183183        foreach {name array} $res {
    184184                array set portinfo $array
    185        
     185
    186186                if {[info exists portinfo(depends_run)] || [info exists portinfo(depends_lib)]} {
    187187                        # get the union of depends_run and depends_lib
  • branches/gsoc11-statistics/base/src/package1.0/portmdmg.tcl

    r79672 r105085  
    1818#    may be used to endorse or promote products derived from this software
    1919#    without specific prior written permission.
    20 # 
     20#
    2121# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    2222# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     
    3737set org.macports.mdmg [target_new org.macports.mdmg portmdmg::mdmg_main]
    3838target_runtype ${org.macports.mdmg} always
    39 target_provides ${org.macports.mdmg} mdmg 
     39target_provides ${org.macports.mdmg} mdmg
    4040target_requires ${org.macports.mdmg} mpkg
    4141
     
    4646
    4747proc portmdmg::mdmg_main {args} {
    48     global subport version revision package.destpath UI_PREFIX
     48    global subport epoch version revision package.destpath UI_PREFIX
    4949
    5050    ui_msg "$UI_PREFIX [format [msgcat::mc "Creating disk image for %s-%s"] ${subport} ${version}]"
    5151
    5252    if {[getuid] == 0 && [geteuid] != 0} {
    53                 setegid 0; seteuid 0
     53                seteuid 0; setegid 0
    5454        }
    5555
    56     return [package_mdmg $subport $version $revision]
     56    return [package_mdmg $subport $epoch $version $revision]
    5757}
    5858
    59 proc portmdmg::package_mdmg {portname portversion portrevision} {
     59proc portmdmg::package_mdmg {portname portepoch portversion portrevision} {
    6060    global UI_PREFIX package.destpath portpath
    6161    global os.platform os.arch os.version os.major
    62    
     62
    6363    if {[expr (${portrevision} > 0)]} {
    6464        set imagename "${portname}-${portversion}-${portrevision}"
     
    6666        set imagename "${portname}-${portversion}"
    6767    }
    68    
     68
    6969    set tmp_image ${package.destpath}/${imagename}.tmp.dmg
    7070    set final_image ${package.destpath}/${imagename}.dmg
    71     set mpkgpath ${package.destpath}/${portname}-${portversion}.mpkg
    72    
     71    set mpkgpath [portmpkg::mpkg_path $portname $portepoch $portversion $portrevision]
     72
    7373    if {[file readable $final_image] && ([file mtime ${final_image}] >= [file mtime ${portpath}/Portfile])} {
    7474        ui_msg "$UI_PREFIX [format [msgcat::mc "Disk Image for %s-%s is up-to-date"] ${portname} ${portversion}]"
     
    8585    }
    8686
     87    if {![file isdirectory $mpkgpath]} {
     88        file mkdir ${package.destpath}/${imagename}
     89        file copy $mpkgpath ${package.destpath}/${imagename}
     90        set mpkgpath ${package.destpath}/${imagename}
     91    }
     92
    8793    set hdiutil [findBinary hdiutil $portutil::autoconf::hdiutil_path]
    8894    if {[system "$hdiutil create -quiet -fs HFS+ -volname ${imagename} -srcfolder ${mpkgpath} ${tmp_image}"] != ""} {
     
    96102    }
    97103    file delete -force "${tmp_image}"
    98    
     104
    99105    return 0
    100106}
  • branches/gsoc11-statistics/base/src/package1.0/portmpkg.tcl

    r84763 r105085  
    33# $Id$
    44#
    5 # Copyright (c) 2005, 2007 - 2011 The MacPorts Project
     5# Copyright (c) 2005, 2007 - 2012 The MacPorts Project
    66# Copyright (c) 2002 - 2004 Apple Inc.
    77# All rights reserved.
     
    1818#    may be used to endorse or promote products derived from this software
    1919#    without specific prior written permission.
    20 # 
     20#
    2121# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    2222# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     
    4949
    5050proc portmpkg::mpkg_main {args} {
    51     global subport version revision package.destpath package.flat UI_PREFIX
    52 
    53     # Make sure the destination path exists.
    54     file mkdir ${package.destpath}
    55 
    56     return [package_mpkg $subport $version $revision]
     51    global subport epoch version revision os.major package.destpath package.flat UI_PREFIX
     52
     53    if {!${package.flat} || ${os.major} < 10} {
     54        # Make sure the destination path exists.
     55        file mkdir ${package.destpath}
     56    }
     57
     58    return [package_mpkg $subport $epoch $version $revision]
    5759}
    5860
    5961proc portmpkg::make_dependency_list {portname destination} {
    60     global variations prefix package.destpath package.flat
    61         set result {}
    62         if {[catch {set res [mport_lookup $portname]} error]} {
    63                 global errorInfo
    64                 ui_debug "$errorInfo"
    65                 return -code error "port lookup failed: $error"
    66         }
    67         array set portinfo [lindex $res 1]
    68 
    69         if {[getuid] == 0 && [geteuid] != 0} {
    70                 setegid 0; seteuid 0
    71                 set deprivileged 1
    72         }
    73 
    74         set mport [mport_open $portinfo(porturl) [list prefix $prefix package.destpath ${destination} package.flat ${package.flat} subport $portinfo(name)] [array get variations]]
     62    global requested_variations prefix package.destpath package.flat
     63    set result {}
     64    if {[catch {set res [mport_lookup $portname]} error]} {
     65        global errorInfo
     66        ui_debug "$errorInfo"
     67        return -code error "port lookup failed: $error"
     68    }
     69    array set portinfo [lindex $res 1]
     70
     71    if {[getuid] == 0 && [geteuid] != 0} {
     72        seteuid 0; setegid 0
     73        set deprivileged 1
     74    }
     75
     76    set mport [mport_open $portinfo(porturl) [list prefix $prefix package.destpath ${destination} package.flat ${package.flat} subport $portinfo(name)] [array get requested_variations]]
    7577
    7678    if {[info exists deprivileged]} {
    77             global macportsuser
    78                 setegid [uname_to_gid "$macportsuser"]
    79                 seteuid [name_to_uid "$macportsuser"]
    80         }
     79        global macportsuser
     80        setegid [uname_to_gid "$macportsuser"]
     81        seteuid [name_to_uid "$macportsuser"]
     82    }
    8183
    8284    unset portinfo
     
    9597    }
    9698
    97     lappend result [list $portinfo(name) $portinfo(version) $mport]
    98         ui_debug "dependencies for ${portname}: $result"
    99         return $result
    100 }
    101 
    102 proc portmpkg::make_one_package {portname portversion mport} {
    103         if {[getuid] == 0 && [geteuid] != 0} {
    104                 setegid 0; seteuid 0
    105                 set deprivileged 1
    106         }
     99    lappend result [list $portinfo(name) $portinfo(epoch) $portinfo(version) $portinfo(revision) $mport]
     100    return $result
     101}
     102
     103proc portmpkg::make_one_package {portname mport} {
     104    if {[getuid] == 0 && [geteuid] != 0} {
     105        seteuid 0; setegid 0
     106        set deprivileged 1
     107    }
    107108
    108109    ui_debug "building dependency package: $portname"
    109     mport_exec $mport pkg
     110    set result [mport_exec $mport pkg]
    110111    mport_close $mport
    111 
    112         if {[info exists deprivileged]} {
    113             global macportsuser
    114                 setegid [uname_to_gid "$macportsuser"]
    115                 seteuid [name_to_uid "$macportsuser"]
    116         }
    117 }
    118 
    119 proc portmpkg::package_mpkg {portname portversion portrevision} {
    120     global portdbpath destpath workpath prefix porturl description package.destpath package.flat long_description homepage depends_run depends_lib
    121 
    122         set pkgpath ${package.destpath}/${portname}-${portversion}.pkg
    123         set mpkgpath ${package.destpath}/${portname}-${portversion}.mpkg
    124         system "mkdir -p -m 0755 ${mpkgpath}/Contents/Resources"
    125         system "mkdir -p -m 0755 ${mpkgpath}/Contents/Packages"
    126 
    127         set dependencies {}
    128         # get deplist
    129         set deps [make_dependency_list $portname ${mpkgpath}/Contents/Packages]
    130         set deps [lsort -unique $deps]
    131         foreach dep $deps {
    132                 set name [lindex $dep 0]
    133                 set vers [lindex $dep 1]
    134                 set mport [lindex $dep 2]
    135                 # don't re-package ourself
    136                 if {$name != $portname} {
    137                         make_one_package $name $vers $mport
    138                         lappend dependencies ${name}-${vers}.pkg
    139                 }
    140         }
    141 
    142         # copy our own pkg into the mpkg
    143         system "cp -PR ${pkgpath} ${mpkgpath}/Contents/Packages/"
    144         lappend dependencies ${portname}-${portversion}.pkg
    145        
    146     portpkg::write_PkgInfo ${mpkgpath}/Contents/PkgInfo
    147     mpkg_write_info_plist ${mpkgpath}/Contents/Info.plist $portname $portversion $portrevision $prefix $dependencies
    148     portpkg::write_description_plist ${mpkgpath}/Contents/Resources/Description.plist $portname $portversion $description
     112    if {$result} {
     113        error "Processing of port $portname failed"
     114    }
     115
     116    if {[info exists deprivileged]} {
     117        global macportsuser
     118        setegid [uname_to_gid "$macportsuser"]
     119        seteuid [name_to_uid "$macportsuser"]
     120    }
     121}
     122
     123proc portmpkg::epoch_namestr {portepoch} {
     124    set portepoch_namestr ""
     125    if {${portepoch} != "0"} {
     126        set portepoch_namestr "${portepoch}_"
     127    }
     128    return ${portepoch_namestr}
     129}
     130
     131proc portmpkg::revision_namestr {portrevision} {
     132    set portrevision_namestr ""
     133    if {${portrevision} != "0"} {
     134        set portrevision_namestr "_${portrevision}"
     135    }
     136    return ${portrevision_namestr}
     137}
     138
     139proc portmpkg::mpkg_path {portname portepoch portversion portrevision} {
     140    global package.destpath
     141    set portepoch_namestr [portmpkg::epoch_namestr ${portepoch}]
     142    set portrevision_namestr [portmpkg::revision_namestr ${portrevision}]
     143    set mpkgpath ${package.destpath}/${portname}-${portepoch_namestr}${portversion}${portrevision_namestr}.mpkg
     144    return $mpkgpath
     145}
     146
     147proc portmpkg::package_mpkg {portname portepoch portversion portrevision} {
     148    global portdbpath os.major destpath workpath prefix porturl description package.destpath package.flat long_description homepage depends_run depends_lib
     149
     150    set mpkgpath [portmpkg::mpkg_path $portname $portepoch $portversion $portrevision]
     151
     152    set portepoch_namestr [portmpkg::epoch_namestr ${portepoch}]
     153    set portrevision_namestr [portmpkg::revision_namestr ${portrevision}]
     154    if {${package.flat} && ${os.major} >= 10} {
     155        set pkgpath ${package.destpath}/${portname}-${portepoch_namestr}${portversion}${portrevision_namestr}-component.pkg
     156        set packages_path ${workpath}/mpkg_packages
     157        set resources_path ${workpath}/mpkg_resources
     158    } else {
     159        set pkgpath ${package.destpath}/${portname}-${portepoch_namestr}${portversion}${portrevision_namestr}.pkg
     160        set packages_path ${mpkgpath}/Contents/Packages
     161        set resources_path ${mpkgpath}/Contents/Resources
     162    }
     163    system "mkdir -p -m 0755 ${packages_path}"
     164    system "mkdir -p -m 0755 ${resources_path}"
     165
     166    set dependencies {}
     167    # get deplist
     168    set deps [make_dependency_list $portname $packages_path]
     169    set deps [lsort -unique $deps]
     170    foreach dep $deps {
     171        set name [lindex $dep 0]
     172        set epoch [lindex $dep 1]
     173        set epoch_namestr ""
     174        if {$epoch != "0"} {
     175            set epoch_namestr "${epoch}_"
     176        }
     177        set vers [lindex $dep 2]
     178        set rev [lindex $dep 3]
     179        set rev_namestr ""
     180        if {$rev != "0"} {
     181            set rev_namestr "_${rev}"
     182        }
     183        set mport [lindex $dep 4]
     184        # don't re-package ourself
     185        if {$name != $portname} {
     186            make_one_package $name $mport
     187            if {${package.flat} && ${os.major} >= 10} {
     188                lappend dependencies org.macports.${name} ${name}-${epoch_namestr}${vers}${rev_namestr}-component.pkg
     189            } else {
     190                lappend dependencies ${name}-${epoch_namestr}${vers}${rev_namestr}.pkg
     191            }
     192        }
     193    }
     194    if {${package.flat} && ${os.major} >= 10} {
     195        lappend dependencies org.macports.${portname} ${portname}-${portepoch_namestr}${portversion}${portrevision_namestr}-component.pkg
     196    } else {
     197        lappend dependencies ${portname}-${portepoch_namestr}${portversion}${portrevision_namestr}.pkg
     198    }
     199
     200    # copy our own pkg into the mpkg
     201    system "cp -PR ${pkgpath} ${packages_path}"
     202
     203    if {!${package.flat} || ${os.major} < 10} {
     204        portpkg::write_PkgInfo ${mpkgpath}/Contents/PkgInfo
     205        mpkg_write_info_plist ${mpkgpath}/Contents/Info.plist $portname $portversion $portrevision $prefix $dependencies
     206        portpkg::write_description_plist ${mpkgpath}/Contents/Resources/Description.plist $portname $portversion $description
     207        set resources_path ${mpkgpath}/Contents/Resources
     208    }
    149209    # long_description, description, or homepage may not exist
    150210    foreach variable {long_description description homepage} {
     
    155215        }
    156216    }
    157     portpkg::write_welcome_html ${mpkgpath}/Contents/Resources/Welcome.html $portname $portversion $pkg_long_description $pkg_description $pkg_homepage
    158     file copy -force -- [getportresourcepath $porturl "port1.0/package/background.tiff"] ${mpkgpath}/Contents/Resources/background.tiff
    159 
    160         return 0
     217    portpkg::write_welcome_html ${resources_path}/Welcome.html $portname $portepoch $portversion $portrevision $pkg_long_description $pkg_description $pkg_homepage
     218    file copy -force -- [getportresourcepath $porturl "port1.0/package/background.tiff"] ${resources_path}/background.tiff
     219
     220    if {${package.flat} && ${os.major} >= 10} {
     221        write_distribution ${workpath}/Distribution $portname $dependencies
     222        set productbuild [findBinary productbuild]
     223        set v [portpkg::mp_version_to_apple_version $portepoch $portversion $portrevision]
     224        set cmdline "$productbuild --resources ${resources_path} --identifier org.macports.mpkg.${portname} --distribution ${workpath}/Distribution --package-path ${packages_path} --version ${v} ${mpkgpath}"
     225        ui_debug "Running command line: $cmdline"
     226        system $cmdline
     227    }
     228
     229    return 0
     230}
     231
     232proc portmpkg::write_distribution {dfile portname dependencies} {
     233    global macosx_deployment_target
     234    set portname [xml_escape $portname]
     235    set dfd [open $dfile w+]
     236    puts $dfd "<?xml version=\"1.0\" encoding=\"utf-8\"?>
     237<installer-gui-script minSpecVersion=\"1\">
     238    <title>${portname}</title>
     239    <options customize=\"never\"/>
     240    <allowed-os-versions><os-version min=\"${macosx_deployment_target}\"/></allowed-os-versions>
     241    <background file=\"background.tiff\" mime-type=\"image/tiff\" alignment=\"bottomleft\" scaling=\"none\"/>
     242    <welcome mime-type=\"text/html\" file=\"Welcome.html\"/>
     243    <choices-outline>
     244    <line choice=\"default\">
     245        <line choice=\"org.macports.mpkg.${portname}\"/>
     246    </line>
     247    </choices-outline>
     248    <choice id=\"default\"/>
     249    <choice id=\"org.macports.mpkg.${portname}\" visible=\"false\">
     250"
     251    foreach {identifier package} $dependencies {
     252        set id [xml_escape $identifier]
     253        set pkg [xml_escape $package]
     254        puts $dfd "        <pkg-ref id=\"${id}\"/>"
     255        lappend pkgrefs "<pkg-ref id=\"${id}\">${pkg}</pkg-ref>"
     256    }
     257    puts $dfd "    </choice>"
     258    foreach pkgref $pkgrefs {
     259        puts $dfd "    $pkgref"
     260    }
     261    puts $dfd "</installer-gui-script>"
     262    close $dfd
    161263}
    162264
    163265proc portmpkg::xml_escape {s} {
    164         regsub -all {&} $s {\&amp;} s
    165         regsub -all {<} $s {\&lt;} s
    166         regsub -all {>} $s {\&gt;} s
    167         return $s
     266    regsub -all {&} $s {\&amp;} s
     267    regsub -all {<} $s {\&lt;} s
     268    regsub -all {>} $s {\&gt;} s
     269    return $s
    168270}
    169271
    170272proc portmpkg::mpkg_write_info_plist {infofile portname portversion portrevision destination dependencies} {
    171         set vers [split $portversion "."]
    172        
    173         if {[string index $destination end] != "/"} {
    174                 append destination /
    175         }
    176        
    177         set depxml ""
    178         foreach dep $dependencies {
    179                 set dep [xml_escape $dep]
    180                 append depxml "<dict>
    181                         <key>IFPkgFlagPackageLocation</key>
    182                         <string>${dep}</string>
    183                         <key>IFPkgFlagPackageSelection</key>
    184                         <string>selected</string>
    185                 </dict>
    186                 "
    187         }
    188 
    189         set portname [xml_escape $portname]
    190         set portversion [xml_escape $portversion]
    191         set portrevision [xml_escape $portrevision]
    192 
    193         set infofd [open ${infofile} w+]
    194         puts $infofd {<?xml version="1.0" encoding="UTF-8"?>
     273    set vers [split $portversion "."]
     274
     275    if {[string index $destination end] != "/"} {
     276        append destination /
     277    }
     278
     279    set depxml ""
     280    foreach dep $dependencies {
     281        set dep [xml_escape $dep]
     282        append depxml "<dict>
     283            <key>IFPkgFlagPackageLocation</key>
     284            <string>${dep}</string>
     285            <key>IFPkgFlagPackageSelection</key>
     286            <string>selected</string>
     287        </dict>
     288        "
     289    }
     290
     291    set portname [xml_escape $portname]
     292    set portversion [xml_escape $portversion]
     293    set portrevision [xml_escape $portrevision]
     294
     295    set infofd [open ${infofile} w+]
     296    puts $infofd {<?xml version="1.0" encoding="UTF-8"?>
    195297<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    196298<plist version="1.0">
    197299}
    198         puts $infofd "<dict>
    199         <key>CFBundleGetInfoString</key>
    200         <string>${portname} ${portversion}</string>
    201         <key>CFBundleIdentifier</key>
    202         <string>org.macports.mpkg.${portname}</string>
    203         <key>CFBundleName</key>
    204         <string>${portname}</string>
    205         <key>CFBundleShortVersionString</key>
    206         <string>${portversion}</string>
    207         <key>IFMajorVersion</key>
    208         <integer>${portrevision}</integer>
    209         <key>IFMinorVersion</key>
    210         <integer>0</integer>
    211         <key>IFPkgFlagComponentDirectory</key>
    212         <string>./Contents/Packages</string>
    213         <key>IFPkgFlagPackageList</key>
    214         <array>
    215                 ${depxml}</array>
    216         <key>IFPkgFormatVersion</key>
    217         <real>0.10000000149011612</real>
     300    puts $infofd "<dict>
     301    <key>CFBundleGetInfoString</key>
     302    <string>${portname} ${portversion}</string>
     303    <key>CFBundleIdentifier</key>
     304    <string>org.macports.mpkg.${portname}</string>
     305    <key>CFBundleName</key>
     306    <string>${portname}</string>
     307    <key>CFBundleShortVersionString</key>
     308    <string>${portversion}</string>
     309    <key>IFMajorVersion</key>
     310    <integer>${portrevision}</integer>
     311    <key>IFMinorVersion</key>
     312    <integer>0</integer>
     313    <key>IFPkgFlagComponentDirectory</key>
     314    <string>./Contents/Packages</string>
     315    <key>IFPkgFlagPackageList</key>
     316    <array>
     317        ${depxml}</array>
     318    <key>IFPkgFormatVersion</key>
     319    <real>0.10000000149011612</real>
    218320</dict>
    219321</plist>"
    220         close $infofd
    221 }
     322    close $infofd
     323}
  • branches/gsoc11-statistics/base/src/package1.0/portpkg.tcl

    r84763 r105085  
    33# $Id$
    44#
    5 # Copyright (c) 2005, 2007 - 2011 The MacPorts Project
     5# Copyright (c) 2005, 2007 - 2012 The MacPorts Project
    66# Copyright (c) 2002 - 2003 Apple Inc.
    77# All rights reserved.
     
    1818#    may be used to endorse or promote products derived from this software
    1919#    without specific prior written permission.
    20 # 
     20#
    2121# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    2222# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     
    3939target_provides ${org.macports.pkg} pkg
    4040target_requires ${org.macports.pkg} archivefetch unarchive destroot
     41target_prerun ${org.macports.pkg} portpkg::pkg_start
    4142
    4243namespace eval portpkg {
     
    4445
    4546# define options
    46 options package.type package.destpath package.flat
     47options package.type package.destpath package.flat package.resources package.scripts
    4748
    4849# Set defaults
    4950default package.destpath {${workpath}}
    50 default package.flat     false
     51default package.resources {${workpath}/pkg_resources}
     52default package.scripts  {${workpath}/pkg_scripts}
     53# Need productbuild to make flat packages really work
     54default package.flat     {[expr [vercmp $macosx_deployment_target 10.6] >= 0]}
    5155
    5256set_ui_prefix
    5357
    54 proc portpkg::pkg_main {args} {
    55     global subport version revision package.type package.destpath package.flat UI_PREFIX
    56 
    57     ui_msg "$UI_PREFIX [format [msgcat::mc "Creating pkg for %s-%s"] ${subport} ${version}]"
    58 
    59     if {[getuid] == 0 && [geteuid] != 0} {
    60         elevateToRoot "pkg"
    61     }
    62 
    63     return [package_pkg $subport $version $revision]
    64 }
    65 
    66 proc portpkg::package_pkg {portname portversion portrevision} {
    67     global UI_PREFIX portdbpath destpath workpath prefix description package.destpath package.flat long_description homepage portpath porturl
    68     global os.version os.major
    69 
    70     set pkgpath ${package.destpath}/${portname}-${portversion}.pkg
    71 
    72     if {[file readable $pkgpath] && ([file mtime ${pkgpath}] >= [file mtime ${portpath}/Portfile])} {
    73         ui_msg "$UI_PREFIX [format [msgcat::mc "Package for %s-%s is up-to-date"] ${portname} ${portversion}]"
    74         return 0
    75     }
    76 
    77     set packagemaker "[option developer_dir]/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker"
    78     if ([file exists "$packagemaker"]) {
    79         set resourcepath ${workpath}/pkg_resources
    80     } else {
    81         set resourcepath "${pkgpath}/Contents/Resources"
    82     }
     58proc portpkg::pkg_start {args} {
     59    global packagemaker_path portpkg::packagemaker \
     60           portpkg::language xcodeversion portpath porturl \
     61           package.resources package.scripts package.flat \
     62           subport epoch version revision description long_description \
     63           homepage workpath os.major
     64
     65    if {![info exists packagemaker_path]} {
     66        if {[vercmp $xcodeversion 4.3] >= 0} {
     67            set packagemaker_path /Applications/PackageMaker.app
     68            if {![file exists $packagemaker_path]} {
     69                ui_warn "PackageMaker.app not found; you may need to install it or set packagemaker_path in macports.conf"
     70            }
     71        } else {
     72            set packagemaker_path "[option developer_dir]/Applications/Utilities/PackageMaker.app"
     73        }
     74    }
     75    set packagemaker "${packagemaker_path}/Contents/MacOS/PackageMaker"
    8376
    8477    set language "English"
    85     file mkdir "${resourcepath}/${language}.lproj"
    86     file attributes "${resourcepath}/${language}.lproj" -permissions 0755
    87        
     78    file mkdir "${package.resources}/${language}.lproj"
     79    file attributes "${package.resources}/${language}.lproj" -permissions 0755
     80    file mkdir ${package.scripts}
     81    file attributes ${package.scripts} -permissions 0755
     82
    8883    # long_description, description, or homepage may not exist
    8984    foreach variable {long_description description homepage} {
     
    9489        }
    9590    }
    96     write_welcome_html ${resourcepath}/${language}.lproj/Welcome.html $portname $portversion $pkg_long_description $pkg_description $pkg_homepage
    97     file copy -force -- [getportresourcepath $porturl "port1.0/package/background.tiff"] ${resourcepath}/${language}.lproj/background.tiff
     91    write_welcome_html ${package.resources}/${language}.lproj/Welcome.html $subport $epoch $version $revision $pkg_long_description $pkg_description $pkg_homepage
     92    file copy -force -- [getportresourcepath $porturl "port1.0/package/background.tiff"] ${package.resources}/${language}.lproj/background.tiff
     93
     94    if {${package.flat} && ${os.major} >= 9} {
     95        write_distribution "${workpath}/Distribution" $subport $epoch $version $revision
     96    }
     97}
     98
     99proc portpkg::pkg_main {args} {
     100    global subport epoch version revision UI_PREFIX
     101
     102    ui_msg "$UI_PREFIX [format [msgcat::mc "Creating pkg for %s-%s_%s_%s"] ${subport} ${epoch} ${version} ${revision}]"
     103
     104    if {[getuid] == 0 && [geteuid] != 0} {
     105        elevateToRoot "pkg"
     106    }
     107
     108    return [package_pkg $subport $epoch $version $revision]
     109}
     110
     111proc portpkg::package_pkg {portname portepoch portversion portrevision} {
     112    global UI_PREFIX portdbpath destpath workpath prefix description \
     113    package.flat package.destpath portpath os.version os.major \
     114    package.resources package.scripts portpkg::packagemaker portpkg::language
     115
     116    set portepoch_namestr ""
     117    if {${portepoch} != "0"} {
     118        set portepoch_namestr "${portepoch}_"
     119    }
     120    set portrevision_namestr ""
     121    if {${portrevision} != "0"} {
     122        set portrevision_namestr "_${portrevision}"
     123    }
     124
     125    set pkgpath "${package.destpath}/${portname}-${portepoch_namestr}${portversion}${portrevision_namestr}.pkg"
     126    if {[file readable $pkgpath] && ([file mtime ${pkgpath}] >= [file mtime ${portpath}/Portfile])} {
     127        ui_msg "$UI_PREFIX [format [msgcat::mc "Package for %s-%s_%s_%s is up-to-date"] ${portname} ${portepoch} ${portversion} ${portrevision}]"
     128        return 0
     129    }
    98130
    99131    foreach dir {etc var tmp} {
     
    112144            if {${package.flat}} {
    113145                set pkgtarget "10.5"
    114                 set pkgresources ""
     146                set pkgresources " --scripts ${package.scripts}"
    115147                set infofile "${workpath}/PackageInfo"
    116                 write_package_info ${workpath}/PackageInfo $portname $portversion $portrevision
     148                write_package_info $infofile
    117149            } else {
    118150                set pkgtarget "10.3"
    119                 set pkgresources " --resources ${resourcepath} --title \"$portname-$portversion\""
     151                set pkgresources " --resources ${package.resources} --title \"$portname-$portversion\""
    120152                set infofile "${workpath}/Info.plist"
    121                 write_info_plist ${workpath}/Info.plist $portname $portversion $portrevision
     153                write_info_plist $infofile $portname $portversion $portrevision
    122154            }
    123             set cmdline "PMResourceLocale=${language} $packagemaker -AppleLanguages \"(${language})\" --root ${destpath} --out ${pkgpath} ${pkgresources} --info $infofile --target $pkgtarget --domain system --id org.macports.$portname"
     155            set cmdline "PMResourceLocale=${language} $packagemaker --root ${destpath} --out ${pkgpath} ${pkgresources} --info $infofile --target $pkgtarget --domain system --id org.macports.$portname"
    124156            if {${os.major} >= 10} {
     157                set v [mp_version_to_apple_version $portepoch $portversion $portrevision]
     158                append cmdline " --version $v"
    125159                append cmdline " --no-relocate"
     160            } else {
     161                # 10.5 Leopard does not use current language, manually specify
     162                append cmdline " -AppleLanguages \"(${language})\""
    126163            }
    127164            ui_debug "Running command line: $cmdline"
    128165            system $cmdline
     166
     167            if {${package.flat} && ${os.major} >= 10} {
     168                # the package we just built is just a component
     169                set componentpath "[file rootname ${pkgpath}]-component.pkg"
     170                file rename -force ${pkgpath} ${componentpath}
     171                # Generate a distribution
     172                set productbuild [findBinary productbuild]
     173                set cmdline "$productbuild --resources ${package.resources} --identifier org.macports.${portname} --distribution ${workpath}/Distribution --package-path ${package.destpath} ${pkgpath}"
     174                ui_debug "Running command line: $cmdline"
     175                system $cmdline
     176            }
    129177        } else {
    130178            write_info_plist ${workpath}/Info.plist $portname $portversion $portrevision
    131179            write_description_plist ${workpath}/Description.plist $portname $portversion $description
    132             system "$packagemaker -build -f ${destpath} -p ${pkgpath} -r ${resourcepath} -i ${workpath}/Info.plist -d ${workpath}/Description.plist"
    133         }
    134 
    135         file delete ${workpath}/Info.plist
    136         file delete ${workpath}/PackageInfo
    137         file delete ${workpath}/Description.plist
    138         file delete -force ${workpath}/pkg_resources
     180            system "$packagemaker -build -f ${destpath} -p ${pkgpath} -r ${package.resources} -i ${workpath}/Info.plist -d ${workpath}/Description.plist"
     181        }
     182
     183        file delete ${workpath}/Info.plist \
     184                    ${workpath}/PackageInfo \
     185                    ${workpath}/Distribution \
     186                    ${workpath}/Description.plist
     187        file delete -force ${package.resources} \
     188                           ${package.scripts}
    139189
    140190    } else {
     191
     192        file mkdir ${pkgpath}/Contents/Resources
     193        foreach f [glob -directory ${package.resources} *] {
     194            file copy -force -- $f ${pkgpath}/Contents/Resources
     195        }
    141196
    142197        write_PkgInfo ${pkgpath}/Contents/PkgInfo
     
    144199
    145200        system "[findBinary mkbom $portutil::autoconf::mkbom_path] ${destpath} ${pkgpath}/Contents/Archive.bom"
    146         system "cd ${destpath} && [findBinary pax $portutil::autoconf::pax_path] -x [findBinary cpio $portutil::autoconf::cpio_path] -w -z . > ${pkgpath}/Contents/Archive.pax.gz"
    147 
    148         write_description_plist ${resourcepath}/Description.plist $portname $portversion $description
    149         write_sizes_file ${resourcepath}/Archive.sizes ${portname} ${portversion} ${pkgpath} ${destpath}
     201        system "cd ${destpath} && [findBinary pax $portutil::autoconf::pax_path] -x cpio -w -z . > ${pkgpath}/Contents/Archive.pax.gz"
     202
     203        write_description_plist ${pkgpath}/Contents/Resources/Description.plist $portname $portversion $description
     204        write_sizes_file ${pkgpath}/Contents/Resources/Archive.sizes ${pkgpath} ${destpath}
    150205
    151206    }
     
    247302}
    248303
    249 proc portpkg::write_welcome_html {filename portname portversion long_description description homepage} {
     304proc portpkg::write_welcome_html {filename portname portepoch portversion portrevision long_description description homepage} {
    250305    set fd [open ${filename} w+]
    251306    if {$long_description == ""} {
     
    254309
    255310    set portname [xml_escape $portname]
     311    if {$portepoch != "0"} {
     312        set portepoch [xml_escape $portepoch]
     313        set portepoch_str "${portepoch}_"
     314    } else {
     315        set portepoch ""
     316        set portepoch_str ""
     317    }
    256318    set portversion [xml_escape $portversion]
     319    if {$portrevision != "0"} {
     320        set portrevision [xml_escape $portrevision]
     321        set portrevision_str "_${portrevision}"
     322    } else {
     323        set portrevision ""
     324        set portrevision_str ""
     325    }
    257326    set long_description [xml_escape $long_description]
    258327    set description [xml_escape $description]
    259328    set homepage [xml_escape $homepage]
    260        
     329
    261330    puts $fd "
    262331<html lang=\"en\">
    263332<head>
    264         <meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">
    265         <title>Install ${portname}</title>
     333    <meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">
     334    <title>Install ${portname}</title>
    266335</head>
    267336<body>
     
    275344    }
    276345
    277     puts $fd "<font face=\"Helvetica\">This installer guides you through the steps necessary to install ${portname} ${portversion} for Mac OS X. To get started, click Continue.</font>
     346    puts $fd "<font face=\"Helvetica\">This installer guides you through the steps necessary to install ${portname} ${portepoch_str}${portversion}${portrevision_str} for Mac OS X. To get started, click Continue.</font>
    278347</body>
    279348</html>"
     
    282351}
    283352
    284 proc portpkg::write_sizes_file {sizesfile portname portversion pkgpath destpath} {
    285    
     353proc portpkg::write_sizes_file {sizesfile pkgpath destpath} {
     354
    286355    if {[catch {set numFiles [llength [split [exec [findBinary lsbom $portutil::autoconf::lsbom_path] -s ${pkgpath}/Contents/Archive.bom] "\n"]]} result]} {
    287356        return -code error [format [msgcat::mc "Reading package bom failed: %s"] $result]
     
    301370    incr installedSize $infoSize
    302371    incr installedSize $bomSize
    303        
     372
    304373    set fd [open ${sizesfile} w+]
    305374    puts $fd "NumFiles $numFiles
     
    309378}
    310379
    311 proc portpkg::write_package_info {infofile portname portversion portrevision} {
    312     set portname [xml_escape $portname]
    313     set portversion [xml_escape $portversion]
    314     set portrevision [xml_escape $portrevision]
    315 
     380proc portpkg::write_package_info {infofile} {
    316381    set infofd [open ${infofile} w+]
    317382    puts $infofd "
     
    320385    close $infofd
    321386}
     387
     388proc portpkg::write_distribution {dfile portname portepoch portversion portrevision} {
     389    global macosx_deployment_target
     390    set portname [xml_escape $portname]
     391    if {$portepoch != "0"} {
     392        set portepoch [xml_escape $portepoch]
     393        set portepoch_str "${portepoch}_"
     394    } else {
     395        set portepoch ""
     396        set portepoch_str ""
     397    }
     398    set portversion [xml_escape $portversion]
     399    if {$portrevision != "0"} {
     400        set portrevision [xml_escape $portrevision]
     401        set portrevision_str "_${portrevision}"
     402    } else {
     403        set portrevision ""
     404        set portrevision_str ""
     405    }
     406    set dfd [open $dfile w+]
     407    puts $dfd "<?xml version=\"1.0\" encoding=\"utf-8\"?>
     408<installer-gui-script minSpecVersion=\"1\">
     409    <title>${portname}</title>
     410    <options customize=\"never\"/>
     411    <allowed-os-versions><os-version min=\"${macosx_deployment_target}\"/></allowed-os-versions>
     412    <background file=\"background.tiff\" mime-type=\"image/tiff\" alignment=\"bottomleft\" scaling=\"none\"/>
     413    <welcome mime-type=\"text/html\" file=\"Welcome.html\"/>
     414    <choices-outline>
     415        <line choice=\"default\">
     416            <line choice=\"org.macports.${portname}\"/>
     417        </line>
     418    </choices-outline>
     419    <choice id=\"default\"/>
     420    <choice id=\"org.macports.${portname}\" visible=\"false\">
     421        <pkg-ref id=\"org.macports.${portname}\"/>
     422    </choice>
     423    <pkg-ref id=\"org.macports.${portname}\">${portname}-${portepoch_str}${portversion}${portrevision_str}-component.pkg</pkg-ref>
     424</installer-gui-script>
     425"
     426    close $dfd
     427}
     428
     429# To create Apple packages, Apple version numbers consist of three
     430# period separated integers [1][2].  Munki supports any number of
     431# integers [3], so incorporate the port epoch, version and revision
     432# numbers in the Apple package version number so that Munki can do
     433# upgrades.  The Apple package number consists of the port epoch
     434# number followed by the port version number followed by the port
     435# revision number.
     436#
     437# Munki also requires that version numbers only consist of integers
     438# and periods.  So replace all non-periods and non-digits in the
     439# version number with periods so that any digits following the
     440# non-digits can properly version the package.
     441#
     442# There is an edge case when upstream releases a new version which
     443# adds an additional integer to its version number and the Portfile's
     444# revision number is reset to 0.  For example, aspell epoch 0,
     445# upstream 0.60.6, revision 4 was updated to epoch 0, upstream
     446# 0.60.6.1, revision 0, which maps to 0.60.6.4 and 0.60.6.1.0
     447# respectively, but the new Apple package version number is less than
     448# the old one.  To handle this, all upstream version numbers are
     449# mapped to seven period separated integers, appending 0 as necessary.
     450# Six was the largest number of integers in all upstream version
     451# numbers as of January 2013 [4], so add one to make space for
     452# trailing [a-zA-Z] in the upstream version number.  This generates a
     453# fixed format version number that will correctly upgrade the package,
     454# e.g. 0.60.6.4.0.0.0.0.4 and 0.60.6.1.0.0.0.1 for aspell.
     455#
     456# [1] https://developer.apple.com/library/mac/#documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/TP40009249-SW1
     457# [2] https://developer.apple.com/library/mac/#documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/TP40009249-SW1
     458# [3] https://groups.google.com/d/msg/munki-dev/-DCERUz6rrM/zMbY6iimIGwJ
     459# [4] http://lists.macosforge.org/pipermail/macports-dev/2013-January/021477.html
     460proc portpkg::mp_version_to_apple_version {portepoch portversion portrevision} {
     461    # Assume that portepoch and portrevision are non-negative integers
     462    # so they do not need to be specially handled like the upstream
     463    # version number.
     464    set v $portversion
     465
     466    # Replace all non-period and non-digit characters with a period.
     467    regsub -all -- {[^.0-9]+} $v . v
     468
     469    # Replace two or more consecutive periods with a single period.
     470    regsub -all -- {[.]+} $v . v
     471
     472    # Trim trailing periods.
     473    regsub -- {[.]+$} $v {} v
     474
     475    # Split the string into a list of integers.
     476    set vs [split $v {.}]
     477
     478    # If the upstream version number ends in [a-zA-Z]+, e.g. openssl's
     479    # 1.0.1c, then treat the trailing characters as a base 26 number,
     480    # mapping 'A' and 'a' to 1, 'B' and 'b' to 2, etc.
     481    if {[regexp -- {\d([a-zA-Z]+)} $portversion ignored chars]} {
     482        # Get the integer ordinals of 'A' and 'a'.
     483        scan "A" %c ord_A
     484        scan "a" %c ord_a
     485
     486        set i 0
     487        foreach char [split $chars ""] {
     488