this repo has no description
at fixPythonPipStalling 367 lines 9.4 kB view raw
1/* 2 * Copyright (c) 2012, 2013, 2015-2018 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23#include <CommonCrypto/CommonDigest.h> 24#include <dirent.h> 25#include <notify.h> 26#include <os/log.h> 27#include <sys/param.h> 28#include <sys/queue.h> 29#include <sys/types.h> 30#include <sys/stat.h> 31 32#ifndef SC_LOG_HANDLE 33#define SC_LOG_HANDLE __log_SCPreferences 34#endif //SC_LOG_HANDLE 35os_log_t SC_LOG_HANDLE(void); 36 37#include <SystemConfiguration/SCPrivate.h> 38#include <SystemConfiguration/scprefs_observer.h> 39 40#define MANAGED_PREFERENCES_PATH "/Library/Managed Preferences" 41#if TARGET_OS_IPHONE 42#define MOBILE_PREFERENCES_PATH "/var/mobile/Library/Preferences" 43#endif // TARGET_OS_IPHONE 44 45#if !TARGET_OS_IPHONE 46#define PREFS_OBSERVER_KEY "com.apple.MCX._managementStatusChangedForDomains" 47#else // !TARGET_OS_IPHONE 48#define PREFS_OBSERVER_KEY "com.apple.ManagedConfiguration.profileListChanged" 49#endif // !TARGET_OS_IPHONE 50 51#pragma mark - 52#pragma mark Utils 53 54static void 55iterate_dir(const char *d_name, const char *f_name, 56 CC_SHA256_CTX *ctxP, Boolean *found) 57{ 58 DIR *dir; 59 struct dirent * dp; 60 61 dir = opendir(d_name); 62 63 if (dir == NULL) { 64 /* if directory path does not exist */ 65 return; 66 } 67 68 while ((dp = readdir(dir)) != NULL) { 69 char full_path[MAXPATHLEN]; 70 struct stat s; 71 72 if ((strcmp(dp->d_name, ".") == 0) || 73 (strcmp(dp->d_name, "..") == 0)) { 74 continue; 75 } 76 77 /* check path */ 78 snprintf(full_path, sizeof(full_path), "%s/%s", d_name, dp->d_name); 79 if (stat(full_path, &s) == 0) { 80 if (S_ISDIR(s.st_mode)) { 81 // if sub-directory, iterate 82 iterate_dir(full_path, f_name, ctxP, found); 83 } else if (strcmp(f_name, dp->d_name) == 0) { 84 /* 85 * if this is the requested file, include 86 * the path and last modification time in 87 * the digest 88 */ 89 CC_SHA256_Update(ctxP, full_path, (CC_LONG)strlen(full_path)); 90 CC_SHA256_Update(ctxP, 91 (void *)&s.st_mtimespec.tv_sec, 92 sizeof(s.st_mtimespec.tv_sec)); 93 *found = TRUE; 94 } 95 } 96 } 97 closedir(dir); 98 return; 99} 100 101static CF_RETURNS_RETAINED CFDataRef 102build_digest(const char *top_dir, const char *file) 103{ 104 unsigned char bytes[CC_SHA256_DIGEST_LENGTH]; 105 CC_SHA256_CTX ctx; 106 CFDataRef digest = NULL; 107 Boolean found = FALSE; 108 109 CC_SHA256_Init(&ctx); 110 iterate_dir(top_dir, file, &ctx, &found); 111 CC_SHA256_Final(bytes, &ctx); 112 if (found) { 113 digest = CFDataCreate(NULL, bytes, sizeof(bytes)); 114 } 115 return (digest); 116} 117 118#pragma mark - 119#pragma mark perfs_observer Private 120 121struct _scprefs_observer_t { 122 _scprefs_observer_type type; 123 dispatch_block_t block; 124 CFDataRef digest; 125 SLIST_ENTRY(_scprefs_observer_t) next; 126 dispatch_queue_t queue; 127 char file[0]; 128}; 129 130static const char * 131prefs_observer_get_prefs_path(scprefs_observer_t observer) 132{ 133 switch (observer->type) { 134#if !TARGET_OS_IPHONE 135 case scprefs_observer_type_mcx: 136 return MANAGED_PREFERENCES_PATH; 137#else // !TARGET_OS_IPHONE 138 case scprefs_observer_type_global: 139 return MANAGED_PREFERENCES_PATH; 140 case scprefs_observer_type_profile: 141 return MOBILE_PREFERENCES_PATH; 142#endif // !TARGET_OS_IPHONE 143 default: 144 return (NULL); 145 } 146} 147 148/* 149 * Iterate through all of the directories and subdirectories. 150 * If the file within those directories has changed, 151 * then generate the notification. 152 */ 153static Boolean 154has_changed(scprefs_observer_t observer) { 155 Boolean changed; 156 CFDataRef digest = NULL; 157 const char * starting_path; 158 159 starting_path = prefs_observer_get_prefs_path(observer); 160 161 digest = build_digest(starting_path, observer->file); 162 163 /* compare old vs. new digest */ 164 changed = _SC_CFEqual(digest, observer->digest)?FALSE:TRUE; 165 166 /* save the digest */ 167 if (observer->digest != NULL) { 168 CFRelease(observer->digest); 169 } 170 171 observer->digest = digest; 172 173 SC_log(changed ? LOG_INFO : LOG_DEBUG, 174 "preferences file: \"%s\" %s", 175 observer->file, 176 changed ? "changed" : "did not change"); 177 return changed; 178} 179 180static dispatch_queue_t 181prefs_observer_queue; 182 183/* This holds the list of the observers */ 184static SLIST_HEAD(mylist, _scprefs_observer_t) head; 185 186static void 187prefs_observer_release(scprefs_observer_t observer) 188{ 189 SLIST_REMOVE(&head, observer, _scprefs_observer_t, next); 190 191 /* Now free the observer */ 192 if (observer->digest != NULL) { 193 CFRelease(observer->digest); 194 } 195 196 free(observer); 197} 198 199static void 200prefs_observer_handle_notifications() 201{ 202 scprefs_observer_t observer; 203 204 SC_log(LOG_DEBUG, "PrefsObserver notification received"); 205 206 SLIST_FOREACH(observer, &head, next) { 207 /* if the preferences plist changed, call the block */ 208 if (has_changed(observer)) { 209 dispatch_async(observer->queue, observer->block); 210 } 211 } 212} 213 214static void 215_prefs_observer_init() 216{ 217 uint32_t status; 218 static int token; 219 220 prefs_observer_queue = dispatch_queue_create("com.apple.SystemConfiguration.SCPreferencesObserver", NULL); 221 222 SLIST_INIT(&head); 223 224 status = notify_register_dispatch(PREFS_OBSERVER_KEY, 225 &token, 226 prefs_observer_queue, 227 ^(int token) { 228#pragma unused(token) 229 prefs_observer_handle_notifications(); 230 }); 231 if (status != NOTIFY_STATUS_OK) { 232 SC_log(LOG_INFO, "notify_register_dispatch() failed: %d", status); 233 } 234} 235 236static scprefs_observer_t 237prefs_observer_priv_create(_scprefs_observer_type type, 238 const char *plist_name, 239 dispatch_queue_t queue, 240 dispatch_block_t block) 241{ 242 scprefs_observer_t observer; 243 size_t path_buflen; 244 245 path_buflen = strlen(plist_name) + 1; 246 247 observer = (scprefs_observer_t)malloc(sizeof(struct _scprefs_observer_t) + path_buflen); 248 memset((void *)observer, 0, sizeof(struct _scprefs_observer_t)); 249 250 /* Create the observer */ 251 observer->type = type; 252 strlcpy(observer->file, plist_name, path_buflen); 253 254 observer->queue = queue; 255 observer->block = Block_copy(block); 256 257 return (observer); 258} 259 260#pragma mark - 261#pragma mark perfs_observer Public SPI 262scprefs_observer_t 263_scprefs_observer_watch(_scprefs_observer_type type, const char *plist_name, 264 dispatch_queue_t queue, dispatch_block_t block) 265{ 266 scprefs_observer_t elem; 267 static dispatch_once_t initialized; 268 269 dispatch_once(&initialized, ^{ 270 _prefs_observer_init(); 271 }); 272 273 elem = prefs_observer_priv_create(type, plist_name, queue, block); 274 SC_log(LOG_INFO, "Created a new element to watch for %s", elem->file); 275 276 dispatch_sync(prefs_observer_queue, ^{ 277 /* Enqueue the request */ 278 SLIST_INSERT_HEAD(&head, elem, next); 279 }); 280 return (elem); 281} 282 283/* This will cancel/deregister the given watcher. This will be synchronized on the 284 * internally created queue. */ 285void 286_scprefs_observer_cancel(scprefs_observer_t observer) 287{ 288 dispatch_sync(prefs_observer_queue, ^{ 289 prefs_observer_release((scprefs_observer_t)observer); 290 }); 291} 292 293#pragma mark - 294 295#ifdef TEST_MAIN 296int main() 297{ 298 int random = 1; 299 300 _sc_verbose = 1; 301 302 dispatch_queue_t q = dispatch_queue_create("com.apple.SystemConfiguration.PrefsObserver.mainQ", NULL); 303 304 dispatch_queue_t q1 = dispatch_queue_create("com.apple.SystemConfiguration.PrefsObserver.testQ1", NULL); 305 306 dispatch_block_t b1 = ^{ 307 printf("Block 1 executed\n"); 308 }; 309 310 dispatch_queue_t q2 = dispatch_queue_create("com.apple.SystemConfiguration.PrefsObserver.testQ2", NULL); 311 dispatch_block_t b2 = ^{ 312 printf("Block 2 executed\n"); 313 }; 314 315 dispatch_queue_t q3 = dispatch_queue_create("com.apple.SystemConfiguration.PrefsObserver.testQ2", NULL); 316 317 dispatch_block_t b3 = ^{ 318 printf("Block 3 executed\n"); 319 }; 320 321 __block scprefs_observer_t observer1 = _scprefs_observer_watch(scprefs_observer_type_mcx, "com.apple.SystemConfiguration", q1, b1); 322 323 __block scprefs_observer_t observer2 = _scprefs_observer_watch(scprefs_observer_type_mcx, "foo", q2, b2); 324 325 __block scprefs_observer_t observer3 = _scprefs_observer_watch(scprefs_observer_type_mcx, "bar", q3, b3); 326 327 __block scprefs_observer_t observer = NULL; 328 329 while (1) { 330 switch (random % 3) 331 { 332 case 0: 333 dispatch_async(q, ^{ 334 _SC_prefs_observer_cancel(observer1); 335 observer1 = NULL; 336 }); 337 dispatch_async(q, ^{ 338 if (observer != NULL) _SC_prefs_observer_cancel(observer); 339 observer = _SC_prefs_observer_watch(SC_prefs_observer_type_mcx, "test", q2, b2); 340 }); 341 dispatch_sync(q, ^{ 342 observer1 = observer; 343 }); 344 sleep(random); 345 break; 346 case 1: 347 dispatch_async(q, ^{ 348 _SC_prefs_observer_cancel(observer2); 349 }); 350 dispatch_async(q, ^{ 351 if (observer != NULL) _SC_prefs_observer_cancel(observer); 352 }); 353 dispatch_sync(q, ^{ 354 observer = _SC_prefs_observer_watch(SC_prefs_observer_type_mcx, "test", q2, b2); 355 }); 356 sleep(random); 357 break; 358 case 2: 359 sleep (random); 360 default: 361 break; 362 } 363 random++; 364 } 365 dispatch_main(); 366} 367#endif