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