Revision: 842 http://trac.macosforge.org/projects/darwinbuild/changeset/842 Author: wsiegrist@apple.com Date: 2010-06-15 14:36:51 -0700 (Tue, 15 Jun 2010) Log Message: ----------- Merge PR-7872907 Modified Paths: -------------- trunk/darwinup/DB.cpp trunk/darwinup/DB.h trunk/darwinup/Depot.cpp trunk/darwinup/Depot.h trunk/darwinup/Utils.cpp trunk/darwinup/Utils.h trunk/darwinup/darwinup.1 trunk/darwinup/main.cpp trunk/testing/darwinup/run-tests.sh Added Paths: ----------- trunk/testing/darwinup/extension.tar.bz2 Property Changed: ---------------- trunk/ Property changes on: trunk ___________________________________________________________________ Modified: svn:mergeinfo - /branches/PR-4841388:399-419 /branches/PR-6358021:442-443 /branches/PR-6392966:423-427 /branches/PR-6398060:433-434 /branches/PR-6493844:460-461 /branches/PR-6497694:466-468,471 /branches/PR-6634286:632-650 /branches/PR-6688645:479-490 /branches/PR-6722857:495-499 /branches/PR-6729491:655-664 /branches/PR-6973110:804-813 /branches/PR-7250612:635-650 /branches/PR-7341154:682-694 /branches/PR-7431723:660-664 /branches/PR-7461534:650-664 /branches/PR-7482850:670-671 /branches/PR-7489777:676-731 /branches/PR-7529688:692-694 /branches/PR-7593824:739-772 /branches/PR-7598640:703-731 /branches/PR-7748469:777-785 /branches/PR-7765119:790-791 /branches/PR-7798586:796-799 /branches/PR-7935095:819-821 + /branches/PR-4841388:399-419 /branches/PR-6358021:442-443 /branches/PR-6392966:423-427 /branches/PR-6398060:433-434 /branches/PR-6493844:460-461 /branches/PR-6497694:466-468,471 /branches/PR-6634286:632-650 /branches/PR-6688645:479-490 /branches/PR-6722857:495-499 /branches/PR-6729491:655-664 /branches/PR-6973110:804-813 /branches/PR-7250612:635-650 /branches/PR-7341154:682-694 /branches/PR-7431723:660-664 /branches/PR-7461534:650-664 /branches/PR-7482850:670-671 /branches/PR-7489777:676-731 /branches/PR-7529688:692-694 /branches/PR-7593824:739-772 /branches/PR-7598640:703-731 /branches/PR-7748469:777-785 /branches/PR-7765119:790-791 /branches/PR-7798586:796-799 /branches/PR-7872907:830-840 /branches/PR-7935095:819-821 Modified: trunk/darwinup/DB.cpp =================================================================== --- trunk/darwinup/DB.cpp 2010-06-15 21:36:06 UTC (rev 841) +++ trunk/darwinup/DB.cpp 2010-06-15 21:36:51 UTC (rev 842) @@ -105,7 +105,8 @@ } int DarwinupDatabase::update_archive(uint64_t serial, uuid_t uuid, const char* name, - time_t date_added, uint32_t active, uint32_t info) { + time_t date_added, uint32_t active, uint32_t info, + const char* build) { this->clear_last_archive(); return this->update(this->m_archives_table, serial, (uint8_t*)uuid, @@ -113,7 +114,8 @@ name, (uint64_t)date_added, (uint64_t)active, - (uint64_t)info); + (uint64_t)info, + build); } uint64_t DarwinupDatabase::insert_archive(uuid_t uuid, uint32_t info, const char* name, Modified: trunk/darwinup/DB.h =================================================================== --- trunk/darwinup/DB.h 2010-06-15 21:36:06 UTC (rev 841) +++ trunk/darwinup/DB.h 2010-06-15 21:36:51 UTC (rev 842) @@ -73,7 +73,8 @@ int activate_archive(uint64_t serial); int deactivate_archive(uint64_t serial); int update_archive(uint64_t serial, uuid_t uuid, const char* name, - time_t date_added, uint32_t active, uint32_t info); + time_t date_added, uint32_t active, uint32_t info, + const char* build); uint64_t insert_archive(uuid_t uuid, uint32_t info, const char* name, time_t date, const char* build); int delete_empty_archives(); Modified: trunk/darwinup/Depot.cpp =================================================================== --- trunk/darwinup/Depot.cpp 2010-06-15 21:36:06 UTC (rev 841) +++ trunk/darwinup/Depot.cpp 2010-06-15 21:36:51 UTC (rev 842) @@ -61,6 +61,7 @@ m_is_locked = 0; m_depot_mode = 0750; m_is_dirty = false; + m_modified_extensions = false; } Depot::Depot(const char* prefix) { @@ -69,6 +70,7 @@ m_depot_mode = 0750; m_build = NULL; m_is_dirty = false; + m_modified_extensions = false; asprintf(&m_prefix, "%s", prefix); join_path(&m_depot_path, m_prefix, "/.DarwinDepot"); @@ -91,10 +93,11 @@ if (m_downloads_path) free(m_downloads_path); } -const char* Depot::archives_path() { return m_archives_path; } -const char* Depot::downloads_path() { return m_downloads_path; } -const char* Depot::prefix() { return m_prefix; } -bool Depot::is_dirty() { return m_is_dirty; } +const char* Depot::archives_path() { return m_archives_path; } +const char* Depot::downloads_path() { return m_downloads_path; } +const char* Depot::prefix() { return m_prefix; } +bool Depot::is_dirty() { return m_is_dirty; } +bool Depot::has_modified_extensions() { return m_modified_extensions; } int Depot::connect() { m_db = new DarwinupDatabase(m_database_path); @@ -107,8 +110,11 @@ int Depot::create_storage() { uid_t uid = getuid(); + gid_t gid = 0; struct group *gs = getgrnam("admin"); - gid_t gid = gs->gr_gid; + if (gs) { + gid = gs->gr_gid; + } int res = mkdir(m_depot_path, m_depot_mode); res = chmod(m_depot_path, m_depot_mode); @@ -483,7 +489,14 @@ IF_DEBUG("[analyze] needs user data backup\n"); actual->info_set(FILE_INFO_ROLLBACK_DATA); } - } + } + + if (!this->m_modified_extensions && + (strncmp(file->path(), "/System/Library/Extensions", 26) == 0)) { + IF_DEBUG("[analyze] kernel extension detected\n"); + this->m_modified_extensions = true; + } + } // if file == actual, but actual != preceding, then an external @@ -1073,9 +1086,9 @@ archive = NULL; archcnt = 0; // check for special keywords - if (strncasecmp(args[i], "all", 3) == 0) { + if (strncasecmp(args[i], "all", 3) == 0 && strlen(args[i]) == 3) { list = this->get_all_archives(&archcnt); - } else if (strncasecmp(args[i], "superseded", 10) == 0) { + } else if (strncasecmp(args[i], "superseded", 10) == 0 && strlen(args[i]) == 10) { list = this->get_superseded_archives(&archcnt); } if (archcnt) { @@ -1368,26 +1381,26 @@ } // perform a command on an archive specification -int Depot::process_archive(const char* command, const char* arg) { +int Depot::process_archive(const char* command, const char* archspec) { extern uint32_t verbosity; int res = 0; uint32_t count = 0; Archive** list = NULL; - if (strncasecmp(arg, "all", 3) == 0) { + if (strncasecmp(archspec, "all", 3) == 0 && strlen(archspec) == 3) { list = this->get_all_archives(&count); - } else if (strncasecmp(arg, "superseded", 10) == 0) { + } else if (strncasecmp(archspec, "superseded", 10) == 0 && strlen(archspec) == 10) { list = this->get_superseded_archives(&count); } else { // make a list of 1 Archive list = (Archive**)malloc(sizeof(Archive*)); - list[0] = this->get_archive(arg); + list[0] = this->get_archive(archspec); count = 1; } for (size_t i = 0; i < count; i++) { if (!list[i]) { - fprintf(stdout, "Archive not found: %s\n", arg); + fprintf(stdout, "Archive not found: %s\n", archspec); return -1; } if (verbosity & VERBOSE_DEBUG) { @@ -1401,3 +1414,49 @@ free(list); return res; } + +int Depot::rename_archive(const char* archspec, const char* name) { + extern uint32_t verbosity; + int res = 0; + + if ((strncasecmp(archspec, "all", 3) == 0 && strlen(archspec) == 3) || + (strncasecmp(archspec, "superseded", 10) == 0 && strlen(archspec) == 10)) { + fprintf(stderr, "Error: keywords 'all' and 'superseded' cannot be used with the" + " rename command.\n"); + return -2; + } + + Archive* archive = this->get_archive(archspec); + if (!archive) { + fprintf(stdout, "Archive not found: %s\n", archspec); + return -1; + } + + char uuid[37]; + uuid_unparse_upper(archive->uuid(), uuid); + if (verbosity & VERBOSE_DEBUG) { + fprintf(stdout, "Found archive: %s\n", uuid); + } + + if (!name || strlen(name) == 0) { + fprintf(stderr, "Error: invalid name: '%s'\n", name); + return -3; + } + + free(archive->m_name); + archive->m_name = strdup(name); + + res = m_db->update_archive(archive->serial(), + archive->uuid(), + archive->name(), + archive->date_installed(), + 1, + archive->info(), + archive->build()); + + if (res == 0) fprintf(stdout, "Renamed archive %s to '%s'.\n", + uuid, archive->name()); + + delete archive; + return res; +} Modified: trunk/darwinup/Depot.h =================================================================== --- trunk/darwinup/Depot.h 2010-06-15 21:36:06 UTC (rev 841) +++ trunk/darwinup/Depot.h 2010-06-15 21:36:51 UTC (rev 842) @@ -110,8 +110,10 @@ // processes an archive according to command // arg is an archive identifier, such as serial or uuid int dispatch_command(Archive* archive, const char* command); - int process_archive(const char* command, const char* arg); + int process_archive(const char* command, const char* archspec); + int rename_archive(const char* archspec, const char* name); + // test if the depot is currently locked int is_locked(); @@ -120,6 +122,7 @@ void archive_header(); bool is_dirty(); + bool has_modified_extensions(); protected: @@ -168,7 +171,9 @@ char* m_build; int m_lock_fd; int m_is_locked; - bool m_is_dirty; // track if we need to update dyld cache + bool m_is_dirty; // track if we need to update dyld cache + bool m_modified_extensions; // track if we need to touch /S/L/E + }; #endif Modified: trunk/darwinup/Utils.cpp =================================================================== --- trunk/darwinup/Utils.cpp 2010-06-15 21:36:06 UTC (rev 841) +++ trunk/darwinup/Utils.cpp 2010-06-15 21:36:51 UTC (rev 842) @@ -402,6 +402,20 @@ return -1; } + +int tell_finder_to_restart() { + int res = 0; + + const char *args[] = { + "/usr/bin/osascript", "-e", + "tell app \"Finder\" to restart", + NULL, + }; + + res = exec_with_args(args); + + return res; +} #endif void __data_hex(FILE* f, uint8_t* data, uint32_t size) { @@ -425,4 +439,3 @@ fprintf(stdout, "==============================================" "=======================================\n"); } - Modified: trunk/darwinup/Utils.h =================================================================== --- trunk/darwinup/Utils.h 2010-06-15 21:36:06 UTC (rev 841) +++ trunk/darwinup/Utils.h 2010-06-15 21:36:51 UTC (rev 842) @@ -82,6 +82,7 @@ #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 int build_number_for_path(char** build, const char* path); +int tell_finder_to_restart(); #endif void __data_hex(FILE* f, uint8_t* data, uint32_t size); Modified: trunk/darwinup/darwinup.1 =================================================================== --- trunk/darwinup/darwinup.1 2010-06-15 21:36:06 UTC (rev 841) +++ trunk/darwinup/darwinup.1 2010-06-15 21:36:51 UTC (rev 842) @@ -46,9 +46,7 @@ .Sh OPTIONS .Bl -tag -width -indent .It \-d -Do not update dyld cache. Darwinup normally runs update_dyld_shared_cache -if the operation actually changes files on disk. To ensure this does not -happen, you can provide this option. +Do not run helpful automation. See HELPFUL AUTOMATION below. .It \-f Force. Some operations will fail gracefully due to potentially unsafe situations, such as a root that installs a file where a directory is. @@ -58,10 +56,14 @@ Dry run. Darwinup will go through an operation, including analyzing the root(s) and printing the state/change symbol, but no files will be modified on your system and no records will be added to the depot. +This option implies -d. .It \-p Op Ar path Prefix path. Normally, darwinup will operate on the boot partition. You can use the -p option to have darwinup work on another partition. You can provide any arbitrary path, it does not need to be a mount point. +.It \-r +Restart. Gracefully restart after all operations are complete by telling +Finder to restart. .It \-v Verbose. This option causes darwinup to print extra information. You can pass 2 or 3 v's for even more information, but that is usually only needed @@ -75,22 +77,24 @@ options listed below support globbing and multiple items. See the EXAMPLES section below for more details. .Bl -tag -width -indent -.It Ar files Ar archives +.It files Ar archives List the files and directories in the .Ar archive . -.It Ar install Ar path +.It install Ar path Install the root at .Ar path . -.It Ar list Op Ar archive +.It list Op Ar archive List archives that are installed. You may optionally provide an archive specification to limit which archives get listed. -.It Ar uninstall Ar archives +.It rename Ar archive Ar name +Rename an archive. +.It uninstall Ar archives Uninstall the specified archive. -.It Ar upgrade Ar path +.It upgrade Ar path Find the last archive that was installed with the same name (basename of path), and replace it with the root at .Ar path . -.It Ar verify Ar archive +.It verify Ar archive List all of the information about .Ar archive . This includes status letters @@ -208,6 +212,20 @@ superseded, then you should not get this error as the backup copies will not be used anyway. .El +.Sh HELPFUL AUTOMATION +Darwinup tries to detect common situations and run external tools that you +would otherwise have to remember to run yourself. The "dry run" (-n) and +"disable automation" (-d) options prevent any of the following from +happening. +.Bl -tag -width -indent +.It Dyld Cache +If a root modifies any file, then darwinup will run +update_dyld_shared_cache unless the -d option is specified. +.It Kernel Extensions +If a root modifies a file under /System/Library/Extensions, then darwinup +will update the mtime of /System/Library/Extensions to ensure that the +kext cache is updated during the next boot. +.El .Sh EXAMPLES .Bl -tag -width -indent .It Install files from a tarball @@ -229,4 +247,5 @@ .Xr curl 1 , .Xr tar 1 , .Xr gzip 1 , -.Xr ditto 1 \ No newline at end of file +.Xr ditto 1 , +.Xr update_dyld_shared_cache 1 \ No newline at end of file Modified: trunk/darwinup/main.cpp =================================================================== --- trunk/darwinup/main.cpp 2010-06-15 21:36:06 UTC (rev 841) +++ trunk/darwinup/main.cpp 2010-06-15 21:36:51 UTC (rev 842) @@ -35,6 +35,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/time.h> #include <unistd.h> #include <limits.h> @@ -50,17 +51,21 @@ fprintf(stderr, " \n"); fprintf(stderr, "options: \n"); #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 - fprintf(stderr, " -d do not update dyld cache \n"); + fprintf(stderr, " -d disable helpful automation \n"); #endif fprintf(stderr, " -f force operation to succeed at all costs \n"); fprintf(stderr, " -n dry run \n"); fprintf(stderr, " -p DIR operate on roots under DIR (default: /) \n"); +#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 + fprintf(stderr, " -r gracefully restart when finished \n"); +#endif fprintf(stderr, " -v verbose (use -vv for extra verbosity) \n"); fprintf(stderr, " \n"); fprintf(stderr, "commands: \n"); fprintf(stderr, " files <archive> \n"); fprintf(stderr, " install <path> \n"); fprintf(stderr, " list [archive] \n"); + fprintf(stderr, " rename <archive> <name> \n"); fprintf(stderr, " uninstall <archive> \n"); fprintf(stderr, " upgrade <path> \n"); fprintf(stderr, " verify <archive> \n"); @@ -103,19 +108,20 @@ char* progname = strdup(basename(argv[0])); char* path = NULL; #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 - bool update_dyld = true; + bool disable_automation = false; + bool restart = false; #endif int ch; #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 - while ((ch = getopt(argc, argv, "dfnp:vh")) != -1) { + while ((ch = getopt(argc, argv, "dfnp:rvh")) != -1) { #else while ((ch = getopt(argc, argv, "fnp:vh")) != -1) { #endif switch (ch) { #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 case 'd': - update_dyld = false; + disable_automation = true; break; #endif case 'f': @@ -124,7 +130,7 @@ case 'n': dryrun = 1; #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 - update_dyld = false; + disable_automation = true; #endif break; case 'p': @@ -138,6 +144,11 @@ } join_path(&path, optarg, "/"); break; +#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 + case 'r': + restart = true; + break; +#endif case 'v': verbosity <<= 1; verbosity |= VERBOSE; @@ -149,7 +160,7 @@ } } argc -= optind; - argv += optind; + argv += optind; if (argc == 0) usage(progname); int res = 0; @@ -157,7 +168,8 @@ if (dryrun) IF_DEBUG("option: dry run\n"); if (force) IF_DEBUG("option: forcing operations\n"); #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 - if (!update_dyld) IF_DEBUG("option: not updating dyld cache\n"); + if (disable_automation) IF_DEBUG("option: helpful automation disabled\n"); + if (restart) IF_DEBUG("option: restart when finished\n"); #endif if (!path) { @@ -191,11 +203,12 @@ if (depot->initialize(false)) exit(11); depot->dump(); } else { + fprintf(stderr, "Error: unknown command: '%s' \n", argv[0]); usage(progname); } } else { // loop over arguments - for (int i = 1; i < argc; i++) { + for (int i = 1; i < argc && res == 0; i++) { if (strcmp(argv[0], "install") == 0) { if (i==1 && depot->initialize(true)) exit(13); res = depot->install(argv[i]); @@ -220,16 +233,43 @@ } else if (strcmp(argv[0], "verify") == 0) { if (i==1 && depot->initialize(true)) exit(16); res = depot->process_archive(argv[0], argv[i]); + } else if (strcmp(argv[0], "rename") == 0) { + if (i==1 && depot->initialize(true)) exit(17); + if ((i+1) >= argc) { + fprintf(stderr, + "Error: rename command for '%s' takes 2 arguments.\n", + argv[i]); + exit(18); + } + res = depot->rename_archive(argv[i], argv[i+1]); + i++; } else { + fprintf(stderr, "Error: unknown command: '%s' \n", argv[0]); usage(progname); } } #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 - if (update_dyld && depot->is_dirty() && res == 0) { + if (!disable_automation && depot->is_dirty() && res == 0) { res = update_dyld_shared_cache(path); if (res) fprintf(stderr, "Warning: could not update dyld cache.\n"); res = 0; - } + } + if (!disable_automation && depot->has_modified_extensions() && res == 0) { + char *sle_path; + res = join_path(&sle_path, depot->prefix(), "/System/Library/Extensions"); + if (res == 0) res = utimes(sle_path, NULL); + if (res) { + fprintf(stderr, "Warning: unable to touch %s \n", sle_path); + res = 0; + } + free(sle_path); + } + if (restart && res == 0) { + res = tell_finder_to_restart(); + if (res) fprintf(stderr, "Warning: tried to tell Finder to restart" + "but failed.\n"); + res = 0; + } #endif } Copied: trunk/testing/darwinup/extension.tar.bz2 (from rev 840, branches/PR-7872907/testing/darwinup/extension.tar.bz2) =================================================================== (Binary files differ) Modified: trunk/testing/darwinup/run-tests.sh =================================================================== --- trunk/testing/darwinup/run-tests.sh 2010-06-15 21:36:06 UTC (rev 841) +++ trunk/testing/darwinup/run-tests.sh 2010-06-15 21:36:51 UTC (rev 842) @@ -1,11 +1,11 @@ #!/bin/bash set -e set -x +pushd $(dirname $0) >> /dev/null # # Run tests on darwinup # - PREFIX=/tmp/testing/darwinup ORIG=$PREFIX/orig DEST=$PREFIX/dest @@ -37,7 +37,7 @@ tar zxvf $R.tar.gz -C $PREFIX done; -for R in 300dirs.tbz2 300files.tbz2 deep-rollback.cpgz deep-rollback-2.xar; +for R in 300dirs.tbz2 300files.tbz2 deep-rollback.cpgz deep-rollback-2.xar extension.tar.bz2; do cp $R $PREFIX/ done; @@ -272,6 +272,47 @@ $DIFF $ORIG $DEST 2>&1 +echo "========== TEST: Archive Rename =============" +$DARWINUP install $PREFIX/root2 +$DARWINUP install $PREFIX/root +$DARWINUP install $PREFIX/root6 +$DARWINUP rename root "RENAME1" +C=$($DARWINUP list | grep "RENAME1" | wc -l | xargs) +test "$C" == "1" +$DARWINUP rename oldest "RENAME2" +C=$($DARWINUP list | grep "RENAME2" | wc -l | xargs) +test "$C" == "1" +$DARWINUP uninstall "RENAME1" +C=$($DARWINUP list | grep "RENAME1" | wc -l | xargs) +test "$C" == "0" +C=$($DARWINUP files "RENAME2" | wc -l | xargs) +test "$C" == "17" +C=$($DARWINUP verify "RENAME2" | wc -l | xargs) +test "$C" == "17" +$DARWINUP rename root6 RENAME3 RENAME3 RENAME4 RENAME4 RENAME5 RENAME5 RENAME6 +C=$($DARWINUP list | grep "root6" | wc -l | xargs) +test "$C" == "0" +C=$($DARWINUP list | grep "RENAME6" | wc -l | xargs) +test "$C" == "1" +C=$($DARWINUP files "RENAME6" | wc -l | xargs) +test "$C" == "8" +$DARWINUP uninstall all +echo "DIFF: diffing original test files to dest (should be no diffs) ..." +$DIFF $ORIG $DEST 2>&1 + +echo "========== TEST: Modify /System/Library/Extensions ==========" +mkdir -p $DEST/System/Library/Extensions/Foo.kext +BEFORE=$(ls -Tld $DEST/System/Library/Extensions/ | awk '{print $6$7$8$9}'); +sleep 2; +$DARWINUP install extension.tar.bz2 +AFTER=$(ls -Tld $DEST/System/Library/Extensions/ | awk '{print $6$7$8$9}'); +test $BEFORE != $AFTER +$DARWINUP uninstall newest +rm -rf $DEST/System +echo "DIFF: diffing original test files to dest (should be no diffs) ..." +$DIFF $ORIG $DEST 2>&1 + + # # The following are expected failures # @@ -282,5 +323,6 @@ echo "DIFF: diffing original test files to dest (should be no diffs) ..." $DIFF $ORIG $DEST 2>&1 +popd >> /dev/null echo "INFO: Done testing!"