]> git.saurik.com Git - apple/configd.git/blob - Plugins/IPMonitor/set-hostname.c
configd-596.15.tar.gz
[apple/configd.git] / Plugins / IPMonitor / set-hostname.c
1 /*
2 * Copyright (c) 2004-2012 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 #include "ip_plugin.h"
44
45 static SCDynamicStoreRef store = NULL;
46 static CFRunLoopSourceRef rls = NULL;
47
48 static Boolean dnsActive = FALSE;
49 static CFMachPortRef dnsPort = NULL;
50 static struct timeval dnsQueryStart;
51
52 static Boolean _verbose = FALSE;
53
54
55 #define HOSTNAME_NOTIFY_KEY "com.apple.system.hostname"
56
57 CFStringRef copy_dhcp_hostname(CFStringRef serviceID);
58
59 static void
60 set_hostname(CFStringRef hostname)
61 {
62 if (hostname != NULL) {
63 char old_name[MAXHOSTNAMELEN];
64 char new_name[MAXHOSTNAMELEN];
65
66 if (gethostname(old_name, sizeof(old_name)) == -1) {
67 my_log(LOG_ERR, "gethostname() failed: %s", strerror(errno));
68 old_name[0] = '\0';
69 }
70
71 if (_SC_cfstring_to_cstring(hostname,
72 new_name,
73 sizeof(new_name),
74 kCFStringEncodingUTF8) == NULL) {
75 my_log(LOG_ERR, "could not convert [new] hostname");
76 new_name[0] = '\0';
77 }
78
79 old_name[sizeof(old_name)-1] = '\0';
80 new_name[sizeof(new_name)-1] = '\0';
81 if (strcmp(old_name, new_name) != 0) {
82 if (sethostname(new_name, strlen(new_name)) == 0) {
83 uint32_t status;
84
85 my_log(LOG_NOTICE,
86 "setting hostname to \"%s\"",
87 new_name);
88
89 status = notify_post(HOSTNAME_NOTIFY_KEY);
90 if (status != NOTIFY_STATUS_OK) {
91 my_log(LOG_ERR,
92 "notify_post(" HOSTNAME_NOTIFY_KEY ") failed: error=%lu",
93 status);
94 }
95 } else {
96 my_log(LOG_ERR,
97 "sethostname(%s, %d) failed: %s",
98 new_name,
99 strlen(new_name),
100 strerror(errno));
101 }
102 }
103 }
104
105 return;
106 }
107
108
109 #define HOSTCONFIG "/etc/hostconfig"
110 #define HOSTNAME_KEY "HOSTNAME="
111 #define AUTOMATIC "-AUTOMATIC-"
112
113 #define HOSTNAME_KEY_LEN (sizeof(HOSTNAME_KEY) - 1)
114
115 static CFStringRef
116 copy_static_name()
117 {
118 FILE * f;
119 char buf[256];
120 CFStringRef name = NULL;
121
122 f = fopen(HOSTCONFIG, "r");
123 if (f == NULL) {
124 return NULL;
125 }
126
127 while (fgets(buf, sizeof(buf), f) != NULL) {
128 char * bp;
129 int n;
130 char * np;
131 Boolean str_escape;
132 Boolean str_quote;
133
134 n = strlen(buf);
135 if (buf[n-1] == '\n') {
136 /* the entire line fit in the buffer, remove the newline */
137 buf[n-1] = '\0';
138 } else {
139 /* eat the remainder of the line */
140 do {
141 n = fgetc(f);
142 } while ((n != '\n') && (n != EOF));
143 }
144
145 // skip leading white space
146 bp = &buf[0];
147 while (isspace(*bp)) {
148 bp++;
149 }
150
151 // find "HOSTNAME=" key
152 if (strncmp(bp, HOSTNAME_KEY, HOSTNAME_KEY_LEN) != 0) {
153 continue; // if not
154 }
155
156 // get the hostname string
157 bp += HOSTNAME_KEY_LEN;
158 str_escape = FALSE;
159 str_quote = FALSE;
160
161 np = &buf[0];
162 while (*bp != '\0') {
163 char ch = *bp;
164
165 switch (ch) {
166 case '\\' :
167 if (!str_escape) {
168 str_escape = TRUE;
169 bp++;
170 continue;
171 }
172 break;
173 case '"' :
174 if (!str_escape) {
175 str_quote = !str_quote;
176 bp++;
177 continue;
178 }
179 break;
180 default :
181 break;
182 }
183
184 if (str_escape) {
185 str_escape = FALSE;
186 } else if (!str_quote && (isspace(ch) || (ch == '#'))) {
187 break;
188 }
189
190 *np++ = ch;
191 bp++;
192 }
193
194 *np = '\0';
195
196 if (name != NULL) {
197 CFRelease(name);
198 name = NULL;
199 }
200
201 if (str_quote) {
202 // the shell won't parse this file so neither will we
203 break;
204 }
205
206 if (strcmp(buf, AUTOMATIC) == 0) {
207 // skip "-AUTOMATIC-"
208 continue;
209 }
210
211 name = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
212 }
213
214 (void) fclose(f);
215 return name;
216 }
217
218
219 static CFStringRef
220 copy_prefs_hostname(SCDynamicStoreRef store)
221 {
222 CFDictionaryRef dict;
223 CFStringRef key;
224 CFStringRef name = NULL;
225
226 key = SCDynamicStoreKeyCreateComputerName(NULL);
227 dict = SCDynamicStoreCopyValue(store, key);
228 CFRelease(key);
229 if (dict == NULL) {
230 goto done;
231 }
232 if (!isA_CFDictionary(dict)) {
233 goto done;
234 }
235
236 name = isA_CFString(CFDictionaryGetValue(dict, kSCPropSystemHostName));
237 if (name == NULL) {
238 goto done;
239 }
240 CFRetain(name);
241
242 done :
243
244 if (dict != NULL) CFRelease(dict);
245
246 return name;
247 }
248
249
250 static CFStringRef
251 copy_primary_service(SCDynamicStoreRef store)
252 {
253 CFDictionaryRef dict;
254 CFStringRef key;
255 CFStringRef serviceID = NULL;
256
257 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
258 kSCDynamicStoreDomainState,
259 kSCEntNetIPv4);
260 dict = SCDynamicStoreCopyValue(store, key);
261 CFRelease(key);
262
263 if (dict != NULL) {
264 if (isA_CFDictionary(dict)) {
265 serviceID = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryService);
266 if (isA_CFString(serviceID)) {
267 CFRetain(serviceID);
268 } else {
269 serviceID = NULL;
270 }
271 }
272 CFRelease(dict);
273 }
274
275 return serviceID;
276 }
277
278
279 static CFStringRef
280 copy_primary_ip(SCDynamicStoreRef store, CFStringRef serviceID)
281 {
282 CFDictionaryRef dict;
283 CFStringRef key;
284 CFStringRef address = NULL;
285
286 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
287 kSCDynamicStoreDomainState,
288 serviceID,
289 kSCEntNetIPv4);
290 dict = SCDynamicStoreCopyValue(store, key);
291 CFRelease(key);
292
293 if (dict != NULL) {
294 if (isA_CFDictionary(dict)) {
295 CFArrayRef addresses;
296
297 addresses = CFDictionaryGetValue(dict, kSCPropNetIPv4Addresses);
298 if (isA_CFArray(addresses) && (CFArrayGetCount(addresses) > 0)) {
299 address = CFArrayGetValueAtIndex(addresses, 0);
300 if (isA_CFString(address)) {
301 CFRetain(address);
302 } else {
303 address = NULL;
304 }
305 }
306 }
307 CFRelease(dict);
308 }
309
310 return address;
311 }
312
313 static void
314 reverseDNSComplete(int32_t status, char *host, char *serv, void *context)
315 {
316 struct timeval dnsQueryComplete;
317 struct timeval dnsQueryElapsed;
318 CFStringRef hostname;
319 SCDynamicStoreRef store = (SCDynamicStoreRef)context;
320
321 (void) gettimeofday(&dnsQueryComplete, NULL);
322 timersub(&dnsQueryComplete, &dnsQueryStart, &dnsQueryElapsed);
323 if (_verbose) {
324 my_log(LOG_INFO, "async DNS complete%s (query time = %d.%3.3d)",
325 ((status == 0) && (host != NULL)) ? "" : ", host not found",
326 dnsQueryElapsed.tv_sec,
327 dnsQueryElapsed.tv_usec / 1000);
328 }
329
330 // use reverse DNS name, if available
331
332 switch (status) {
333 case 0 :
334 /*
335 * if [reverse] DNS query was successful
336 */
337 if (host != NULL) {
338 hostname = CFStringCreateWithCString(NULL, host, kCFStringEncodingUTF8);
339 if (hostname != NULL) {
340 my_log(LOG_INFO, "hostname (reverse DNS query) = %@", hostname);
341 set_hostname(hostname);
342 CFRelease(hostname);
343 goto done;
344 }
345 }
346 break;
347
348 case EAI_NONAME :
349 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
350 case EAI_NODATA:
351 #endif
352 /*
353 * if no name available
354 */
355 break;
356
357 default :
358 /*
359 * Hmmmm...
360 */
361 my_log(LOG_ERR, "getnameinfo() failed: %s", gai_strerror(status));
362 }
363
364 // get local (multicast DNS) name, if available
365
366 hostname = SCDynamicStoreCopyLocalHostName(store);
367 if (hostname != NULL) {
368 CFMutableStringRef localName;
369
370 my_log(LOG_INFO, "hostname (multicast DNS) = %@", hostname);
371 localName = CFStringCreateMutableCopy(NULL, 0, hostname);
372 assert(localName != NULL);
373 CFStringAppend(localName, CFSTR(".local"));
374 set_hostname(localName);
375 CFRelease(localName);
376 CFRelease(hostname);
377 goto done;
378 }
379
380 // use "localhost" if not other name is available
381
382 set_hostname(CFSTR("localhost"));
383
384 done :
385
386 if (host != NULL) free(host);
387 if (serv != NULL) free(serv);
388 dnsActive = FALSE;
389 return;
390 }
391
392
393 static CFStringRef
394 replyMPCopyDescription(const void *info)
395 {
396 SCDynamicStoreRef store = (SCDynamicStoreRef)info;
397
398 return CFStringCreateWithFormat(NULL,
399 NULL,
400 CFSTR("<getnameinfo_async_start reply MP> {store = %p}"),
401 store);
402 }
403
404
405 static void
406 getnameinfo_async_handleCFReply(CFMachPortRef port, void *msg, CFIndex size, void *info)
407 {
408 mach_port_t mp = MACH_PORT_NULL;
409 int32_t status;
410
411 if (port != dnsPort) {
412 // we've received a callback on the async DNS port but since the
413 // associated CFMachPort doesn't match than the request must have
414 // already been cancelled.
415 my_log(LOG_ERR, "getnameinfo_async_handleCFReply(): port != dnsPort");
416 return;
417 }
418
419 mp = CFMachPortGetPort(port);
420 CFMachPortInvalidate(dnsPort);
421 CFRelease(dnsPort);
422 dnsPort = NULL;
423 __MACH_PORT_DEBUG(mp != MACH_PORT_NULL, "*** set-hostname (after unscheduling)", mp);
424
425 status = getnameinfo_async_handle_reply(msg);
426 __MACH_PORT_DEBUG(mp != MACH_PORT_NULL, "*** set-hostname (after getnameinfo_async_handle_reply)", mp);
427 if ((status == 0) && dnsActive && (mp != MACH_PORT_NULL)) {
428 CFMachPortContext context = { 0
429 , (void *)store
430 , CFRetain
431 , CFRelease
432 , replyMPCopyDescription
433 };
434 CFRunLoopSourceRef rls;
435
436 // if request has been re-queued
437 dnsPort = _SC_CFMachPortCreateWithPort("IPMonitor/set-hostname/re-queue",
438 mp,
439 getnameinfo_async_handleCFReply,
440 &context);
441 rls = CFMachPortCreateRunLoopSource(NULL, dnsPort, 0);
442 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
443 CFRelease(rls);
444 __MACH_PORT_DEBUG(mp != MACH_PORT_NULL, "*** set-hostname (after rescheduling)", mp);
445 }
446
447 return;
448 }
449
450
451 static void
452 start_dns_query(SCDynamicStoreRef store, CFStringRef address)
453 {
454 union {
455 struct sockaddr sa;
456 struct sockaddr_in sin;
457 struct sockaddr_in6 sin6;
458 } addr;
459 char buf[64];
460 SCNetworkReachabilityFlags flags;
461 Boolean haveDNS;
462 Boolean ok;
463
464 if (_SC_cfstring_to_cstring(address, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) {
465 my_log(LOG_ERR, "could not convert [primary] address");
466 return;
467 }
468
469 if (_SC_string_to_sockaddr(buf, AF_UNSPEC, (void *)&addr, sizeof(addr)) == NULL) {
470 /* if not an IP[v6] address */
471 my_log(LOG_ERR, "could not parse [primary] address");
472 return;
473 }
474
475 ok = _SC_checkResolverReachabilityByAddress(&store, &flags, &haveDNS, &addr.sa);
476 if (ok) {
477 if (!(flags & kSCNetworkReachabilityFlagsReachable) ||
478 (flags & kSCNetworkReachabilityFlagsConnectionRequired)) {
479 // if not reachable *OR* connection required
480 ok = FALSE;
481 }
482 }
483
484 if (ok) {
485 CFMachPortContext context = { 0
486 , (void *)store
487 , CFRetain
488 , CFRelease
489 , replyMPCopyDescription
490 };
491 int32_t error;
492 mach_port_t mp;
493 CFRunLoopSourceRef rls;
494
495 (void) gettimeofday(&dnsQueryStart, NULL);
496
497 error = getnameinfo_async_start(&mp,
498 &addr.sa,
499 addr.sa.sa_len,
500 NI_NAMEREQD, // flags
501 reverseDNSComplete,
502 NULL);
503 if (error != 0) {
504 goto done;
505 }
506 __MACH_PORT_DEBUG(TRUE, "*** set-hostname (after getnameinfo_async_start)", mp);
507
508 dnsActive = TRUE;
509 dnsPort = _SC_CFMachPortCreateWithPort("IPMonitor/set-hostname",
510 mp,
511 getnameinfo_async_handleCFReply,
512 &context);
513 rls = CFMachPortCreateRunLoopSource(NULL, dnsPort, 0);
514 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
515 CFRelease(rls);
516 __MACH_PORT_DEBUG(TRUE, "*** set-hostname (after scheduling)", mp);
517 }
518
519 done :
520
521 return;
522 }
523
524
525 static void
526 update_hostname(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
527 {
528 CFStringRef address = NULL;
529 CFStringRef hostname = NULL;
530 CFStringRef serviceID = NULL;
531
532 // if active, cancel any in-progress attempt to resolve the primary IP address
533
534 if (dnsPort != NULL) {
535 mach_port_t mp = CFMachPortGetPort(dnsPort);
536
537 /* cancel the outstanding DNS query */
538 CFMachPortInvalidate(dnsPort);
539 CFRelease(dnsPort);
540 dnsPort = NULL;
541
542 getnameinfo_async_cancel(mp);
543 }
544
545 // get static hostname, if available
546
547 hostname = copy_static_name();
548 if (hostname != NULL) {
549 my_log(LOG_INFO, "hostname (static) = %@", hostname);
550 set_hostname(hostname);
551 goto done;
552 }
553
554 // get [prefs] hostname, if available
555
556 hostname = copy_prefs_hostname(store);
557 if (hostname != NULL) {
558 my_log(LOG_INFO, "hostname (prefs) = %@", hostname);
559 set_hostname(hostname);
560 goto done;
561 }
562
563 // get primary service ID
564
565 serviceID = copy_primary_service(store);
566 if (serviceID == NULL) {
567 goto mDNS;
568 }
569
570 // get DHCP provided name, if available
571
572 hostname = copy_dhcp_hostname(serviceID);
573 if (hostname != NULL) {
574 my_log(LOG_INFO, "hostname (DHCP) = %@", hostname);
575 set_hostname(hostname);
576 goto done;
577 }
578
579 // get DNS name associated with primary IP, if available
580
581 address = copy_primary_ip(store, serviceID);
582 if (address != NULL) {
583 // start reverse DNS query using primary IP address
584 (void) start_dns_query(store, address);
585 goto done;
586 }
587
588 mDNS :
589
590 // get local (multicast DNS) name, if available
591
592 hostname = SCDynamicStoreCopyLocalHostName(store);
593 if (hostname != NULL) {
594 CFMutableStringRef localName;
595
596 my_log(LOG_INFO, "hostname (multicast DNS) = %@", hostname);
597 localName = CFStringCreateMutableCopy(NULL, 0, hostname);
598 assert(localName != NULL);
599 CFStringAppend(localName, CFSTR(".local"));
600 set_hostname(localName);
601 CFRelease(localName);
602 goto done;
603 }
604
605 // use "localhost" if not other name is available
606
607 set_hostname(CFSTR("localhost"));
608
609 done :
610
611 if (address) CFRelease(address);
612 if (hostname) CFRelease(hostname);
613 if (serviceID) CFRelease(serviceID);
614
615 return;
616 }
617
618
619 __private_extern__
620 void
621 load_hostname(Boolean verbose)
622 {
623 CFStringRef key;
624 CFMutableArrayRef keys = NULL;
625 CFMutableArrayRef patterns = NULL;
626
627 if (verbose) {
628 _verbose = TRUE;
629 }
630
631 /* initialize a few globals */
632
633 store = SCDynamicStoreCreate(NULL, CFSTR("set-hostname"), update_hostname, NULL);
634 if (store == NULL) {
635 my_log(LOG_ERR,
636 "SCDynamicStoreCreate() failed: %s",
637 SCErrorString(SCError()));
638 goto error;
639 }
640
641 /* establish notification keys and patterns */
642
643 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
644 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
645
646 /* ...watch for primary service / interface changes */
647 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
648 kSCDynamicStoreDomainState,
649 kSCEntNetIPv4);
650 CFArrayAppendValue(keys, key);
651 CFRelease(key);
652
653 /* ...watch for DNS configuration changes */
654 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
655 kSCDynamicStoreDomainState,
656 kSCEntNetDNS);
657 CFArrayAppendValue(keys, key);
658 CFRelease(key);
659
660 /* ...watch for (per-service) DHCP option changes */
661 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
662 kSCDynamicStoreDomainState,
663 kSCCompAnyRegex,
664 kSCEntNetDHCP);
665 CFArrayAppendValue(patterns, key);
666 CFRelease(key);
667
668 /* ...watch for (BSD) hostname changes */
669 key = SCDynamicStoreKeyCreateComputerName(NULL);
670 CFArrayAppendValue(keys, key);
671 CFRelease(key);
672
673 /* ...watch for local (multicast DNS) hostname changes */
674 key = SCDynamicStoreKeyCreateHostNames(NULL);
675 CFArrayAppendValue(keys, key);
676 CFRelease(key);
677
678 /* register the keys/patterns */
679 if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns)) {
680 my_log(LOG_ERR,
681 "SCDynamicStoreSetNotificationKeys() failed: %s",
682 SCErrorString(SCError()));
683 goto error;
684 }
685
686 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
687 if (!rls) {
688 my_log(LOG_ERR,
689 "SCDynamicStoreCreateRunLoopSource() failed: %s",
690 SCErrorString(SCError()));
691 goto error;
692 }
693 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
694
695 CFRelease(keys);
696 CFRelease(patterns);
697 return;
698
699 error :
700
701 if (keys != NULL) CFRelease(keys);
702 if (patterns != NULL) CFRelease(patterns);
703 if (store != NULL) CFRelease(store);
704 return;
705 }
706
707
708 #ifdef MAIN
709 int
710 main(int argc, char **argv)
711 {
712
713 #ifdef DEBUG
714
715 _sc_log = FALSE;
716 if ((argc > 1) && (strcmp(argv[1], "-d") == 0)) {
717 _sc_verbose = TRUE;
718 argv++;
719 argc--;
720 }
721
722 CFStringRef address;
723 CFStringRef hostname;
724 CFStringRef serviceID;
725 SCDynamicStoreRef store;
726
727 store = SCDynamicStoreCreate(NULL, CFSTR("set-hostname"), NULL, NULL);
728 if (store == NULL) {
729 SCPrint(TRUE, stdout,
730 CFSTR("SCDynamicStoreCreate() failed: %s\n"),
731 SCErrorString(SCError()));
732 exit(1);
733 }
734
735 // get static hostname
736 hostname = copy_static_name();
737 if (hostname != NULL) {
738 SCPrint(TRUE, stdout, CFSTR("hostname (static) = %@\n"), hostname);
739 CFRelease(hostname);
740 }
741
742 // get [prefs] hostname, if available
743 hostname = copy_prefs_hostname(store);
744 if (hostname != NULL) {
745 SCPrint(TRUE, stdout, CFSTR("hostname (prefs) = %@\n"), hostname);
746 CFRelease(hostname);
747 }
748
749 // get primary service
750 serviceID = copy_primary_service(store);
751 if (serviceID != NULL) {
752 SCPrint(TRUE, stdout, CFSTR("primary service ID = %@\n"), serviceID);
753 } else {
754 SCPrint(TRUE, stdout, CFSTR("No primary service\n"));
755 goto mDNS;
756 }
757
758 if ((argc == (2+1)) && (argv[1][0] == 's')) {
759 if (serviceID != NULL) CFRelease(serviceID);
760 serviceID = CFStringCreateWithCString(NULL, argv[2], kCFStringEncodingUTF8);
761 SCPrint(TRUE, stdout, CFSTR("alternate service ID = %@\n"), serviceID);
762 }
763
764 // get DHCP provided name
765 hostname = copy_dhcp_name(store, serviceID);
766 if (hostname != NULL) {
767 SCPrint(TRUE, stdout, CFSTR("hostname (DHCP) = %@\n"), hostname);
768 CFRelease(hostname);
769 }
770
771 // get primary IP address
772 address = copy_primary_ip(store, serviceID);
773 if (address != NULL) {
774 SCPrint(TRUE, stdout, CFSTR("primary address = %@\n"), address);
775
776 if ((argc == (2+1)) && (argv[1][0] == 'a')) {
777 if (address != NULL) CFRelease(address);
778 address = CFStringCreateWithCString(NULL, argv[2], kCFStringEncodingUTF8);
779 SCPrint(TRUE, stdout, CFSTR("alternate primary address = %@\n"), address);
780 }
781
782 // start reverse DNS query using primary IP address
783 start_dns_query(store, address);
784 CFRelease(address);
785 }
786
787 CFRelease(serviceID);
788
789 mDNS :
790
791 // get local (multicast DNS) name, if available
792
793 hostname = SCDynamicStoreCopyLocalHostName(store);
794 if (hostname != NULL) {
795 CFMutableStringRef localName;
796
797 SCPrint(TRUE, stdout, CFSTR("hostname (multicast DNS) = %@\n"), hostname);
798 localName = CFStringCreateMutableCopy(NULL, 0, hostname);
799 CFStringAppend(localName, CFSTR(".local"));
800 CFRelease(localName);
801 }
802
803 if (hostname != NULL) CFRelease(hostname);
804
805 update_hostname(store, NULL, NULL);
806
807 CFRelease(store);
808
809 CFRunLoopRun();
810
811 #else /* DEBUG */
812
813 _sc_log = FALSE;
814 _sc_verbose = (argc > 1) ? TRUE : FALSE;
815
816 load_hostname((argc > 1) ? TRUE : FALSE);
817 CFRunLoopRun();
818 /* not reached */
819
820 #endif /* DEBUG */
821
822 exit(0);
823 return 0;
824 }
825 #endif /* MAIN */