]> git.saurik.com Git - apple/configd.git/blob - Plugins/IPMonitor/set-hostname.c
configd-801.1.1.tar.gz
[apple/configd.git] / Plugins / IPMonitor / set-hostname.c
1 /*
2 * Copyright (c) 2004-2015 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 <ctype.h>
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <sys/param.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <sys/time.h>
30 #include <net/if.h>
31 #include <net/if_dl.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <netdb_async.h>
35
36 #include <CoreFoundation/CoreFoundation.h>
37 #include <SystemConfiguration/SystemConfiguration.h>
38 #include <SystemConfiguration/SCDynamicStoreCopyDHCPInfo.h>
39 #include <SystemConfiguration/SCValidation.h>
40 #include <SystemConfiguration/SCPrivate.h>
41
42 #include <notify.h>
43
44 #ifdef MAIN
45 #define my_log(__level, fmt, ...) SCPrint(TRUE, stdout, CFSTR(fmt "\n"), ## __VA_ARGS__)
46 #else // MAIN
47 #include "ip_plugin.h"
48 #endif // MAIN
49
50 static SCDynamicStoreRef store = NULL;
51 static CFRunLoopRef rl = NULL;
52 static CFRunLoopSourceRef rls = NULL;
53 static dispatch_queue_t queue = NULL;
54
55 static int notify_token = -1;
56
57 static struct timeval ptrQueryStart;
58 static SCNetworkReachabilityRef ptrTarget = NULL;
59
60
61 #define HOSTNAME_NOTIFY_KEY "com.apple.system.hostname"
62 #define SET_HOSTNAME_QUEUE "com.apple.config.set-hostname"
63
64 CFStringRef copy_dhcp_hostname(CFStringRef serviceID);
65
66 static void
67 set_hostname(CFStringRef hostname)
68 {
69 if (hostname != NULL) {
70 char old_name[MAXHOSTNAMELEN];
71 char new_name[MAXHOSTNAMELEN];
72
73 if (gethostname(old_name, sizeof(old_name)) == -1) {
74 my_log(LOG_ERR, "gethostname() failed: %s", strerror(errno));
75 old_name[0] = '\0';
76 }
77
78 if (_SC_cfstring_to_cstring(hostname,
79 new_name,
80 sizeof(new_name),
81 kCFStringEncodingUTF8) == NULL) {
82 my_log(LOG_NOTICE, "could not convert [new] hostname");
83 new_name[0] = '\0';
84 }
85
86 old_name[sizeof(old_name)-1] = '\0';
87 new_name[sizeof(new_name)-1] = '\0';
88 if (strcmp(old_name, new_name) != 0) {
89 if (sethostname(new_name, (int)strlen(new_name)) == 0) {
90 uint32_t status;
91
92 my_log(LOG_NOTICE,
93 "setting hostname to \"%s\"",
94 new_name);
95
96 status = notify_post(HOSTNAME_NOTIFY_KEY);
97 if (status != NOTIFY_STATUS_OK) {
98 my_log(LOG_ERR,
99 "notify_post(" HOSTNAME_NOTIFY_KEY ") failed: error=%u",
100 status);
101 }
102 } else {
103 my_log(LOG_ERR,
104 "sethostname(%s, %ld) failed: %s",
105 new_name,
106 strlen(new_name),
107 strerror(errno));
108 }
109 }
110 }
111
112 return;
113 }
114
115
116 static CFStringRef
117 copy_prefs_hostname(SCDynamicStoreRef store)
118 {
119 CFDictionaryRef dict;
120 CFStringRef key;
121 CFStringRef name = NULL;
122
123 key = SCDynamicStoreKeyCreateComputerName(NULL);
124 dict = SCDynamicStoreCopyValue(store, key);
125 CFRelease(key);
126 if (dict == NULL) {
127 goto done;
128 }
129 if (!isA_CFDictionary(dict)) {
130 goto done;
131 }
132
133 name = isA_CFString(CFDictionaryGetValue(dict, kSCPropSystemHostName));
134 if (name == NULL) {
135 goto done;
136 }
137 CFRetain(name);
138
139 done :
140
141 if (dict != NULL) CFRelease(dict);
142
143 return name;
144 }
145
146
147 static CFStringRef
148 copy_primary_service(SCDynamicStoreRef store)
149 {
150 CFDictionaryRef dict;
151 CFStringRef key;
152 CFStringRef serviceID = NULL;
153
154 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
155 kSCDynamicStoreDomainState,
156 kSCEntNetIPv4);
157 dict = SCDynamicStoreCopyValue(store, key);
158 CFRelease(key);
159
160 if (dict != NULL) {
161 if (isA_CFDictionary(dict)) {
162 serviceID = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryService);
163 if (isA_CFString(serviceID)) {
164 CFRetain(serviceID);
165 } else {
166 serviceID = NULL;
167 }
168 }
169 CFRelease(dict);
170 }
171
172 return serviceID;
173 }
174
175
176 static CFStringRef
177 copy_primary_ip(SCDynamicStoreRef store, CFStringRef serviceID)
178 {
179 CFDictionaryRef dict;
180 CFStringRef key;
181 CFStringRef address = NULL;
182
183 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
184 kSCDynamicStoreDomainState,
185 serviceID,
186 kSCEntNetIPv4);
187 dict = SCDynamicStoreCopyValue(store, key);
188 CFRelease(key);
189
190 if (dict != NULL) {
191 if (isA_CFDictionary(dict)) {
192 CFArrayRef addresses;
193
194 addresses = CFDictionaryGetValue(dict, kSCPropNetIPv4Addresses);
195 if (isA_CFArray(addresses) && (CFArrayGetCount(addresses) > 0)) {
196 address = CFArrayGetValueAtIndex(addresses, 0);
197 if (isA_CFString(address)) {
198 CFRetain(address);
199 } else {
200 address = NULL;
201 }
202 }
203 }
204 CFRelease(dict);
205 }
206
207 return address;
208 }
209
210
211 static void
212 ptr_query_stop()
213 {
214 if (ptrTarget == NULL) {
215 return;
216 }
217
218 my_log(LOG_INFO, "hostname: ptr query stop");
219
220 SCNetworkReachabilitySetCallback(ptrTarget, NULL, NULL);
221 SCNetworkReachabilityUnscheduleFromRunLoop(ptrTarget, rl, kCFRunLoopDefaultMode);
222 CFRelease(ptrTarget);
223 ptrTarget = NULL;
224
225 return;
226 }
227
228
229 /* Return a ptr record if the sharing pref name is a matching FQDN */
230 static CFStringRef
231 hostname_match_full(CFArrayRef hosts, CFIndex count, CFStringRef nameToMatch)
232 {
233 CFIndex i;
234 CFStringRef matchedHostName = NULL;
235
236 for (i = 0; i < count; i++) {
237 CFStringRef tempHostName;
238
239 tempHostName = CFArrayGetValueAtIndex(hosts, i);
240 if (CFStringCompare(tempHostName, nameToMatch, kCFCompareCaseInsensitive) == 0) {
241 matchedHostName = tempHostName;
242 break;
243 }
244 }
245 return matchedHostName;
246 }
247
248
249 /* Return a ptr record if the sharing pref name matches DNS record's first label */
250 static CFStringRef
251 hostname_match_first_label(CFArrayRef hosts, CFIndex count, CFStringRef nameToMatch)
252 {
253 CFIndex i;
254 CFStringRef matchedHostName = NULL;
255
256 for (i = 0; i < count; i++) {
257 CFArrayRef fqdnSeparated;
258 CFStringRef tempHostName;
259
260 tempHostName = CFArrayGetValueAtIndex(hosts, i);
261 fqdnSeparated = CFStringCreateArrayBySeparatingStrings(NULL, tempHostName, CFSTR("."));
262 if (fqdnSeparated != NULL) {
263 CFStringRef firstLabel;
264 Boolean matchFound;
265
266 firstLabel = CFArrayGetValueAtIndex(fqdnSeparated, 0);
267 matchFound = (CFStringCompare(firstLabel, nameToMatch, kCFCompareCaseInsensitive) == 0);
268 CFRelease(fqdnSeparated);
269 if (matchFound) {
270 matchedHostName = tempHostName;
271 break;
272 }
273 }
274 }
275 return matchedHostName;
276 }
277
278
279 static void
280 ptr_query_callback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info)
281 {
282 CFStringRef hostname = NULL;
283 struct timeval ptrQueryComplete;
284 struct timeval ptrQueryElapsed;
285
286 (void) gettimeofday(&ptrQueryComplete, NULL);
287 timersub(&ptrQueryComplete, &ptrQueryStart, &ptrQueryElapsed);
288
289 // use reverse DNS name, if available
290
291 if (flags & kSCNetworkReachabilityFlagsReachable) {
292 int error_num;
293 CFArrayRef hosts;
294
295 /*
296 * if [reverse] DNS query was successful
297 */
298 hosts = SCNetworkReachabilityCopyResolvedAddress(target, &error_num);
299 if (hosts != NULL) {
300 CFIndex count = CFArrayGetCount(hosts);
301 if (count > 0) {
302 CFStringRef computerName;
303 CFStringRef localHostName;
304
305 my_log(LOG_INFO, "hostname: ptr query complete (query time = %ld.%3.3d)",
306 ptrQueryElapsed.tv_sec,
307 ptrQueryElapsed.tv_usec / 1000);
308
309 // first, check if ComputerName is dns-clean
310 computerName = _SCPreferencesCopyComputerName(NULL, NULL);
311 if (computerName != NULL) {
312 if (_SC_CFStringIsValidDNSName(computerName)) {
313 CFRange dotsCheck;
314
315 dotsCheck = CFStringFind(computerName, CFSTR("."), 0);
316 if (dotsCheck.length == 0) {
317 hostname = hostname_match_first_label(hosts, count, computerName);
318 } else {
319 hostname = hostname_match_full(hosts, count, computerName);
320 }
321 }
322 CFRelease(computerName);
323 }
324
325 // if no match, check LocalHostName against the first label of FQDN
326 localHostName = (hostname == NULL) ? SCDynamicStoreCopyLocalHostName(store) : NULL;
327 if (localHostName != NULL) {
328 hostname = hostname_match_first_label(hosts, count, localHostName);
329 CFRelease(localHostName);
330 }
331
332 // if no match, use the first of the returned names
333 if (hostname == NULL) {
334 hostname = CFArrayGetValueAtIndex(hosts, 0);
335 }
336
337 my_log(LOG_INFO, "hostname (reverse DNS query) = %@", hostname);
338 set_hostname(hostname);
339 } else {
340 my_log(LOG_INFO, "hostname: ptr query complete w/no hosts (query time = %ld.%3.3d)",
341 ptrQueryElapsed.tv_sec,
342 ptrQueryElapsed.tv_usec / 1000);
343 }
344 CFRelease(hosts);
345
346 if (hostname != NULL) {
347 goto done;
348 }
349 } else {
350 // if kSCNetworkReachabilityFlagsReachable and hosts == NULL
351 // it means the PTR request has not come back yet
352 // we must wait for this callback to be called again
353 my_log(LOG_INFO, "hostname: ptr query reply w/no hosts (query time = %ld.%3.3d)",
354 ptrQueryElapsed.tv_sec,
355 ptrQueryElapsed.tv_usec / 1000);
356 return;
357 }
358 } else {
359 my_log(LOG_INFO, "hostname: ptr query complete, host not found (query time = %ld.%3.3d)",
360 ptrQueryElapsed.tv_sec,
361 ptrQueryElapsed.tv_usec / 1000);
362 }
363
364 // get local (multicast DNS) name, if available
365
366 hostname = SCDynamicStoreCopyLocalHostName(store);
367 if (hostname != NULL) {
368 CFMutableStringRef localHostName;
369
370 my_log(LOG_INFO, "hostname (multicast DNS) = %@", hostname);
371 localHostName = CFStringCreateMutableCopy(NULL, 0, hostname);
372 assert(localHostName != NULL);
373 CFStringAppend(localHostName, CFSTR(".local"));
374 set_hostname(localHostName);
375 CFRelease(localHostName);
376 CFRelease(hostname);
377 goto done;
378 }
379
380 // use "localhost" if not other name is available
381
382 my_log(LOG_INFO, "hostname (localhost)");
383 set_hostname(CFSTR("localhost"));
384
385 done :
386
387 ptr_query_stop();
388
389 #ifdef MAIN
390 CFRunLoopStop(rl);
391 #endif // MAIN
392
393 return;
394 }
395
396
397 static Boolean
398 ptr_query_start(CFStringRef address)
399 {
400 union {
401 struct sockaddr sa;
402 struct sockaddr_in sin;
403 struct sockaddr_in6 sin6;
404 } addr;
405 char buf[64];
406 CFDataRef data;
407 CFMutableDictionaryRef options;
408
409 if (_SC_cfstring_to_cstring(address, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) {
410 my_log(LOG_ERR, "could not convert [primary] address string");
411 return FALSE;
412 }
413
414 if (_SC_string_to_sockaddr(buf, AF_UNSPEC, (void *)&addr, sizeof(addr)) == NULL) {
415 my_log(LOG_ERR, "could not convert [primary] address");
416 return FALSE;
417 }
418
419 options = CFDictionaryCreateMutable(NULL,
420 0,
421 &kCFTypeDictionaryKeyCallBacks,
422 &kCFTypeDictionaryValueCallBacks);
423 data = CFDataCreate(NULL, (const UInt8 *)&addr.sa, addr.sa.sa_len);
424 CFDictionarySetValue(options, kSCNetworkReachabilityOptionPTRAddress, data);
425 CFRelease(data);
426 ptrTarget = SCNetworkReachabilityCreateWithOptions(NULL, options);
427 CFRelease(options);
428 if (ptrTarget == NULL) {
429 my_log(LOG_ERR, "could not resolve [primary] address");
430 return FALSE;
431 }
432
433 my_log(LOG_INFO, "hostname: ptr query start");
434
435 (void) SCNetworkReachabilitySetCallback(ptrTarget, ptr_query_callback, NULL);
436 (void) SCNetworkReachabilityScheduleWithRunLoop(ptrTarget, rl, kCFRunLoopDefaultMode);
437
438 return TRUE;
439 }
440
441
442 static void
443 update_hostname(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
444 {
445 CFStringRef address = NULL;
446 CFStringRef hostname = NULL;
447 CFStringRef serviceID = NULL;
448
449 // if active, cancel any in-progress attempt to resolve the primary IP address
450
451 if (ptrTarget != NULL) {
452 ptr_query_stop();
453 }
454
455 // get [prefs] hostname, if available
456
457 hostname = copy_prefs_hostname(store);
458 if (hostname != NULL) {
459 my_log(LOG_INFO, "hostname (prefs) = %@", hostname);
460 set_hostname(hostname);
461 goto done;
462 }
463
464 // get primary service ID
465
466 serviceID = copy_primary_service(store);
467 if (serviceID == NULL) {
468 goto mDNS;
469 }
470
471 // get DHCP provided name, if available
472
473 hostname = copy_dhcp_hostname(serviceID);
474 if (hostname != NULL) {
475 my_log(LOG_INFO, "hostname (DHCP) = %@", hostname);
476 set_hostname(hostname);
477 goto done;
478 }
479
480 // get DNS name associated with primary IP, if available
481
482 address = copy_primary_ip(store, serviceID);
483 if (address != NULL) {
484 Boolean ok;
485 boolean_t isExpensive = FALSE;
486
487 // start reverse DNS query using primary IP address
488 // if primary service is not expensive
489 isExpensive = check_if_service_expensive(serviceID);
490
491 if (isExpensive == FALSE) {
492 ok = ptr_query_start(address);
493 if (ok) {
494 // if query started
495 goto done;
496 }
497 }
498 }
499
500 mDNS :
501
502 // get local (multicast DNS) name, if available
503
504 hostname = SCDynamicStoreCopyLocalHostName(store);
505 if (hostname != NULL) {
506 CFMutableStringRef localHostName;
507
508 my_log(LOG_INFO, "hostname (multicast DNS) = %@", hostname);
509 localHostName = CFStringCreateMutableCopy(NULL, 0, hostname);
510 assert(localHostName != NULL);
511 CFStringAppend(localHostName, CFSTR(".local"));
512 set_hostname(localHostName);
513 CFRelease(localHostName);
514 goto done;
515 }
516
517 // use "localhost" if not other name is available
518
519 set_hostname(CFSTR("localhost"));
520
521 done :
522
523 if (address) CFRelease(address);
524 if (hostname) CFRelease(hostname);
525 if (serviceID) CFRelease(serviceID);
526
527 return;
528 }
529
530
531 __private_extern__
532 void
533 load_hostname(Boolean verbose)
534 {
535 CFStringRef key;
536 CFMutableArrayRef keys = NULL;
537 dispatch_block_t notify_block;
538 Boolean ok;
539 CFMutableArrayRef patterns = NULL;
540 uint32_t status;
541
542 /* initialize a few globals */
543
544 store = SCDynamicStoreCreate(NULL, CFSTR("set-hostname"), update_hostname, NULL);
545 if (store == NULL) {
546 my_log(LOG_ERR,
547 "SCDynamicStoreCreate() failed: %s",
548 SCErrorString(SCError()));
549 goto error;
550 }
551
552 queue = dispatch_queue_create(SET_HOSTNAME_QUEUE, NULL);
553 if (queue == NULL) {
554 my_log(LOG_ERR,
555 "dispatch_queue_create() failed");
556 goto error;
557 }
558
559 /* establish notification keys and patterns */
560
561 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
562 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
563
564 /* ...watch for (per-service) DHCP option changes */
565 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
566 kSCDynamicStoreDomainState,
567 kSCCompAnyRegex,
568 kSCEntNetDHCP);
569 CFArrayAppendValue(patterns, key);
570 CFRelease(key);
571
572 /* ...watch for (BSD) hostname changes */
573 key = SCDynamicStoreKeyCreateComputerName(NULL);
574 CFArrayAppendValue(keys, key);
575 CFRelease(key);
576
577 /* ...watch for local (multicast DNS) hostname changes */
578 key = SCDynamicStoreKeyCreateHostNames(NULL);
579 CFArrayAppendValue(keys, key);
580 CFRelease(key);
581
582 /* register the keys/patterns */
583 ok = SCDynamicStoreSetNotificationKeys(store, keys, patterns);
584 CFRelease(keys);
585 CFRelease(patterns);
586 if (!ok) {
587 my_log(LOG_ERR,
588 "SCDynamicStoreSetNotificationKeys() failed: %s",
589 SCErrorString(SCError()));
590 goto error;
591 }
592
593 rl = CFRunLoopGetCurrent();
594 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
595 if (rls == NULL) {
596 my_log(LOG_ERR,
597 "SCDynamicStoreCreateRunLoopSource() failed: %s",
598 SCErrorString(SCError()));
599 goto error;
600 }
601 CFRunLoopAddSource(rl, rls, kCFRunLoopDefaultMode);
602
603 /* ...watch for primary service/interface and DNS configuration changes */
604 notify_block = ^{
605 CFArrayRef changes;
606 CFStringRef key;
607
608 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
609 kSCDynamicStoreDomainState,
610 kSCEntNetDNS);
611 changes = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks);
612 (*update_hostname)(store, changes, NULL);
613 CFRelease(changes);
614 CFRelease(key);
615
616 return;
617 };
618 status = notify_register_dispatch(_SC_NOTIFY_NETWORK_CHANGE,
619 &notify_token,
620 queue,
621 ^(int token){
622 CFRunLoopPerformBlock(rl,
623 kCFRunLoopDefaultMode,
624 notify_block);
625 CFRunLoopWakeUp(rl);
626 });
627 if (status != NOTIFY_STATUS_OK) {
628 my_log(LOG_ERR, "notify_register_dispatch() failed: %u", status);
629 goto error;
630 }
631
632 return;
633
634 error :
635
636 if (rls != NULL) {
637 CFRunLoopRemoveSource(rl, rls, kCFRunLoopDefaultMode);
638 CFRelease(rls);
639 rls = NULL;
640 }
641 if (store != NULL) {
642 CFRelease(store);
643 store = NULL;
644 }
645 if (queue != NULL) {
646 dispatch_release(queue);
647 queue = NULL;
648 }
649
650 return;
651 }
652
653
654 #ifdef MAIN
655 int
656 main(int argc, char **argv)
657 {
658
659 #ifdef DEBUG
660
661 _sc_log = FALSE;
662 if ((argc > 1) && (strcmp(argv[1], "-d") == 0)) {
663 _sc_verbose = TRUE;
664 argv++;
665 argc--;
666 }
667
668 CFStringRef address;
669 CFStringRef hostname;
670 CFStringRef serviceID;
671 SCDynamicStoreRef store;
672
673 store = SCDynamicStoreCreate(NULL, CFSTR("set-hostname"), NULL, NULL);
674 if (store == NULL) {
675 SCPrint(TRUE, stdout,
676 CFSTR("SCDynamicStoreCreate() failed: %s\n"),
677 SCErrorString(SCError()));
678 exit(1);
679 }
680
681 // get [prefs] hostname, if available
682 hostname = copy_prefs_hostname(store);
683 if (hostname != NULL) {
684 SCPrint(TRUE, stdout, CFSTR("hostname (prefs) = %@\n"), hostname);
685 CFRelease(hostname);
686 }
687
688 // get local (multicast DNS) name, if available
689
690 hostname = SCDynamicStoreCopyLocalHostName(store);
691 if (hostname != NULL) {
692 SCPrint(TRUE, stdout, CFSTR("hostname (multicast DNS) = %@\n"), hostname);
693 CFRelease(hostname);
694 }
695
696 // get primary service
697 serviceID = copy_primary_service(store);
698 if (serviceID != NULL) {
699 SCPrint(TRUE, stdout, CFSTR("primary service ID = %@\n"), serviceID);
700 } else {
701 SCPrint(TRUE, stdout, CFSTR("No primary service\n"));
702 }
703
704 if ((argc == (2+1)) && (argv[1][0] == 's')) {
705 if (serviceID != NULL) CFRelease(serviceID);
706 serviceID = CFStringCreateWithCString(NULL, argv[2], kCFStringEncodingUTF8);
707 SCPrint(TRUE, stdout, CFSTR("alternate service ID = %@\n"), serviceID);
708 }
709
710 if (serviceID != NULL) {
711 // get DHCP provided name
712 hostname = copy_dhcp_hostname(serviceID);
713 if (hostname != NULL) {
714 SCPrint(TRUE, stdout, CFSTR("hostname (DHCP) = %@\n"), hostname);
715 CFRelease(hostname);
716 }
717
718 // get primary IP address
719 address = copy_primary_ip(store, serviceID);
720 if (address != NULL) {
721 SCPrint(TRUE, stdout, CFSTR("primary address = %@\n"), address);
722
723 if ((argc == (2+1)) && (argv[1][0] == 'a')) {
724 if (address != NULL) CFRelease(address);
725 address = CFStringCreateWithCString(NULL, argv[2], kCFStringEncodingUTF8);
726 SCPrint(TRUE, stdout, CFSTR("alternate primary address = %@\n"), address);
727 }
728
729 // start reverse DNS query using primary IP address
730 (void) ptr_query_start(address);
731 CFRelease(address);
732 }
733
734 CFRelease(serviceID);
735 }
736
737 CFRelease(store);
738
739 CFRunLoopRun();
740
741 #else /* DEBUG */
742
743 _sc_log = FALSE;
744 _sc_verbose = (argc > 1) ? TRUE : FALSE;
745
746 load_hostname((argc > 1) ? TRUE : FALSE);
747 CFRunLoopRun();
748 /* not reached */
749
750 #endif /* DEBUG */
751
752 exit(0);
753 return 0;
754 }
755 #endif /* MAIN */