]> git.saurik.com Git - apple/configd.git/blob - Plugins/IPMonitor/set-hostname.c
configd-130.tar.gz
[apple/configd.git] / Plugins / IPMonitor / set-hostname.c
1 /*
2 * Copyright (c) 2004-2005 Apple Computer, 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/types.h>
27 #include <sys/socket.h>
28 #include <sys/time.h>
29 #include <net/if.h>
30 #include <net/if_dl.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <netdb_async.h>
34
35 #include <CoreFoundation/CoreFoundation.h>
36 #include <SystemConfiguration/SystemConfiguration.h>
37 #include <SystemConfiguration/SCDynamicStoreCopyDHCPInfo.h>
38 #include <SystemConfiguration/SCValidation.h>
39 #include <SystemConfiguration/SCPrivate.h> // for SCLog(), SCPrint()
40
41 #include <notify.h>
42
43
44 static SCDynamicStoreRef store = NULL;
45 static CFRunLoopSourceRef rls = NULL;
46
47 static CFMachPortRef dnsPort = NULL;
48 static CFRunLoopSourceRef dnsRLS = NULL;
49 static struct timeval dnsQueryStart;
50
51 static Boolean _verbose = FALSE;
52
53
54 /* SPI (from SCNetworkReachability.c) */
55 Boolean
56 _SC_checkResolverReachability(SCDynamicStoreRef *storeP,
57 SCNetworkConnectionFlags *flags,
58 Boolean *haveDNS,
59 const char * nodename);
60
61
62 /*
63 * checkResolverReachabilityByAddress()
64 *
65 * Given an IP address, determine whether a reverse DNS query can be issued
66 * using the current network configuration.
67 */
68 static Boolean
69 checkResolverReachabilityByAddress(SCDynamicStoreRef store, struct sockaddr *sa)
70 {
71 SCNetworkConnectionFlags flags;
72 Boolean haveDNS;
73 int i;
74 Boolean ok = FALSE;
75 char ptr_name[128];
76
77 /*
78 * Ideally, we would have an API that given a local IP
79 * address would return the DNS server(s) that would field
80 * a given PTR query. Fortunately, we do have an SPI which
81 * which will provide this information given a "name" so we
82 * take the address, convert it into the inverse query name,
83 * and find out which servers should be consulted.
84 */
85
86 switch (sa->sa_family) {
87 case AF_INET : {
88 union {
89 in_addr_t s_addr;
90 unsigned char b[4];
91 } rev;
92 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
93
94 /*
95 * build "PTR" query name
96 * NNN.NNN.NNN.NNN.in-addr.arpa.
97 */
98 rev.s_addr = sin->sin_addr.s_addr;
99 (void) snprintf(ptr_name, sizeof(ptr_name), "%u.%u.%u.%u.in-addr.arpa.",
100 rev.b[3],
101 rev.b[2],
102 rev.b[1],
103 rev.b[0]);
104
105 break;
106 }
107
108 case AF_INET6 : {
109 int s = 0;
110 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
111 int x = sizeof(ptr_name);
112 int n;
113
114 #define USE_NIBBLE_QUERY
115 #ifdef USE_NIBBLE_QUERY
116 /*
117 * build IPv6 "nibble" PTR query name (RFC 1886, RFC 3152)
118 * N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.ip6.arpa.
119 */
120 for (i = sizeof(sin6->sin6_addr) - 1; i >= 0; i--) {
121 n = snprintf(&ptr_name[s], x, "%x.%x.",
122 ( sin6->sin6_addr.s6_addr[i] & 0xf),
123 ((sin6->sin6_addr.s6_addr[i] >> 4) & 0xf));
124 if ((n == -1) || (n >= x)) {
125 goto done;
126 }
127
128 s += n;
129 x -= n;
130 }
131
132 n = snprintf(&ptr_name[s], x, "ip6.arpa.");
133 if ((n == -1) || (n >= x)) {
134 goto done;
135 }
136 #else /* USE_NIBBLE_QUERY */
137 /*
138 * build IPv6 "bit-string" PTR query name (RFC 2673)
139 * \[xNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN].ip6.arpa.
140 */
141 n = snprintf(&ptr_name[0], x, "\\[x");
142 if ((n == -1) || (n >= x)) {
143 goto done;
144 }
145
146 s += n;
147 x -= n;
148 for (i = 0; i < 16; i++) {
149 n = snprintf(&ptr_name[s], x, "%2.2x", sin6->sin6_addr.s6_addr[i]);
150 if ((n == -1) || (n >= x)) {
151 goto done;
152 }
153
154 s += n;
155 x -= n;
156 }
157
158 n = snprintf(&ptr_name[s], x, "].ip6.arpa.");
159 if ((n == -1) || (n >= x)) {
160 goto done;
161 }
162 #endif /* USE_NIBBLE_QUERY */
163
164 break;
165 }
166
167 default :
168 goto done;
169 }
170
171 ok = _SC_checkResolverReachability(&store, &flags, &haveDNS, ptr_name);
172 if (ok) {
173 if (!(flags & kSCNetworkFlagsReachable) ||
174 (flags & kSCNetworkFlagsConnectionRequired)) {
175 // if not reachable *OR* connection required
176 ok = FALSE;
177 }
178 }
179
180 done :
181
182 return ok;
183 }
184
185
186 #define HOSTNAME_NOTIFY_KEY "com.apple.system.hostname"
187
188
189 static void
190 set_hostname(CFStringRef hostname)
191 {
192 if (hostname != NULL) {
193 char old_name[MAXHOSTNAMELEN];
194 char new_name[MAXHOSTNAMELEN];
195
196 if (gethostname(old_name, sizeof(old_name)) == -1) {
197 SCLog(TRUE, LOG_ERR, CFSTR("gethostname() failed: %s"), strerror(errno));
198 old_name[0] = '\0';
199 }
200
201 if (_SC_cfstring_to_cstring(hostname,
202 new_name,
203 sizeof(new_name),
204 kCFStringEncodingUTF8) == NULL) {
205 SCLog(TRUE, LOG_ERR, CFSTR("could not convert [new] hostname"));
206 new_name[0] = '\0';
207 }
208
209 old_name[sizeof(old_name)-1] = '\0';
210 new_name[sizeof(new_name)-1] = '\0';
211 if (strcmp(old_name, new_name) != 0) {
212 if (sethostname(new_name, strlen(new_name)) == 0) {
213 uint32_t status;
214
215 SCLog(TRUE, LOG_NOTICE,
216 CFSTR("setting hostname to \"%s\""),
217 new_name);
218
219 status = notify_post(HOSTNAME_NOTIFY_KEY);
220 if (status != NOTIFY_STATUS_OK) {
221 SCLog(TRUE, LOG_ERR,
222 CFSTR("notify_post(" HOSTNAME_NOTIFY_KEY ") failed: error=%lu"),
223 status);
224 }
225 } else {
226 SCLog(TRUE, LOG_ERR,
227 CFSTR("sethostname(%s, %d) failed: %s"),
228 new_name,
229 strlen(new_name),
230 strerror(errno));
231 }
232 }
233 }
234
235 return;
236 }
237
238
239 #define HOSTCONFIG "/etc/hostconfig"
240 #define HOSTNAME_KEY "HOSTNAME="
241 #define AUTOMATIC "-AUTOMATIC-"
242
243 #define HOSTNAME_KEY_LEN (sizeof(HOSTNAME_KEY) - 1)
244
245 static CFStringRef
246 copy_static_name()
247 {
248 FILE * f;
249 char buf[256];
250 CFStringRef name = NULL;
251
252 f = fopen(HOSTCONFIG, "r");
253 if (f == NULL) {
254 return NULL;
255 }
256
257 while (fgets(buf, sizeof(buf), f) != NULL) {
258 char * bp;
259 int n;
260 char * np;
261 Boolean str_escape;
262 Boolean str_quote;
263
264 n = strlen(buf);
265 if (buf[n-1] == '\n') {
266 /* the entire line fit in the buffer, remove the newline */
267 buf[n-1] = '\0';
268 } else {
269 /* eat the remainder of the line */
270 do {
271 n = fgetc(f);
272 } while ((n != '\n') && (n != EOF));
273 }
274
275 // skip leading white space
276 bp = &buf[0];
277 while (isspace(*bp)) {
278 bp++;
279 }
280
281 // find "HOSTNAME=" key
282 if (strncmp(bp, HOSTNAME_KEY, HOSTNAME_KEY_LEN) != 0) {
283 continue; // if not
284 }
285
286 // get the hostname string
287 bp += HOSTNAME_KEY_LEN;
288 str_escape = FALSE;
289 str_quote = FALSE;
290
291 np = &buf[0];
292 while (*bp != '\0') {
293 char ch = *bp;
294
295 switch (ch) {
296 case '\\' :
297 if (!str_escape) {
298 str_escape = TRUE;
299 bp++;
300 continue;
301 }
302 break;
303 case '"' :
304 if (!str_escape) {
305 str_quote = !str_quote;
306 bp++;
307 continue;
308 }
309 break;
310 default :
311 break;
312 }
313
314 if (str_escape) {
315 str_escape = FALSE;
316 } else if (!str_quote && (isspace(ch) || (ch == '#'))) {
317 break;
318 }
319
320 *np++ = ch;
321 bp++;
322 }
323
324 *np = '\0';
325
326 if (name != NULL) {
327 CFRelease(name);
328 name = NULL;
329 }
330
331 if (str_quote) {
332 // the shell won't parse this file so neither will we
333 break;
334 }
335
336 if (strcmp(buf, AUTOMATIC) == 0) {
337 // skip "-AUTOMATIC-"
338 continue;
339 }
340
341 name = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
342 }
343
344 (void) fclose(f);
345 return name;
346 }
347
348
349 #ifndef kSCPropNetHostName
350 #define kSCPropNetHostName CFSTR("HostName")
351 #endif
352
353
354 static CFStringRef
355 copy_prefs_hostname(SCDynamicStoreRef store)
356 {
357 CFDictionaryRef dict;
358 CFStringRef key;
359 CFStringRef name = NULL;
360
361 key = SCDynamicStoreKeyCreateComputerName(NULL);
362 dict = SCDynamicStoreCopyValue(store, key);
363 CFRelease(key);
364 if (dict == NULL) {
365 goto done;
366 }
367 if (!isA_CFDictionary(dict)) {
368 goto done;
369 }
370
371 name = isA_CFString(CFDictionaryGetValue(dict, kSCPropNetHostName));
372 if (name == NULL) {
373 goto done;
374 }
375 CFRetain(name);
376
377 done :
378
379 if (dict != NULL) CFRelease(dict);
380
381 return name;
382 }
383
384
385 static CFStringRef
386 copy_primary_service(SCDynamicStoreRef store)
387 {
388 CFDictionaryRef dict;
389 CFStringRef key;
390 CFStringRef serviceID = NULL;
391
392 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
393 kSCDynamicStoreDomainState,
394 kSCEntNetIPv4);
395 dict = SCDynamicStoreCopyValue(store, key);
396 CFRelease(key);
397
398 if (dict != NULL) {
399 if (isA_CFDictionary(dict)) {
400 serviceID = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryService);
401 if (isA_CFString(serviceID)) {
402 CFRetain(serviceID);
403 } else {
404 serviceID = NULL;
405 }
406 }
407 CFRelease(dict);
408 }
409
410 return serviceID;
411 }
412
413
414 static CFStringRef
415 copy_primary_ip(SCDynamicStoreRef store, CFStringRef serviceID)
416 {
417 CFDictionaryRef dict;
418 CFStringRef key;
419 CFStringRef address = NULL;
420
421 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
422 kSCDynamicStoreDomainState,
423 serviceID,
424 kSCEntNetIPv4);
425 dict = SCDynamicStoreCopyValue(store, key);
426 CFRelease(key);
427
428 if (dict != NULL) {
429 if (isA_CFDictionary(dict)) {
430 CFArrayRef addresses;
431
432 addresses = CFDictionaryGetValue(dict, kSCPropNetIPv4Addresses);
433 if (isA_CFArray(addresses) && (CFArrayGetCount(addresses) > 0)) {
434 address = CFArrayGetValueAtIndex(addresses, 0);
435 if (isA_CFString(address)) {
436 CFRetain(address);
437 } else {
438 address = NULL;
439 }
440 }
441 }
442 CFRelease(dict);
443 }
444
445 return address;
446 }
447
448
449 #define DHCP_OPTION_HOSTNAME 12
450
451 static CFStringRef
452 copy_dhcp_name(SCDynamicStoreRef store, CFStringRef serviceID)
453 {
454 CFDictionaryRef info;
455 CFStringRef name = NULL;
456
457 info = SCDynamicStoreCopyDHCPInfo(store, serviceID);
458 if (info != NULL) {
459 CFDataRef data;
460
461 data = DHCPInfoGetOptionData(info, DHCP_OPTION_HOSTNAME);
462 if (data != NULL) {
463 name = CFStringCreateFromExternalRepresentation(NULL, data, kCFStringEncodingUTF8);
464 }
465
466 CFRelease(info);
467 }
468
469 return name;
470 }
471
472
473 static void
474 reverseDNSComplete(int32_t status, char *host, char *serv, void *context)
475 {
476 struct timeval dnsQueryComplete;
477 struct timeval dnsQueryElapsed;
478 CFStringRef hostname;
479 SCDynamicStoreRef store = (SCDynamicStoreRef)context;
480
481 (void) gettimeofday(&dnsQueryComplete, NULL);
482 timersub(&dnsQueryComplete, &dnsQueryStart, &dnsQueryElapsed);
483 SCLog(_verbose, LOG_INFO,
484 CFSTR("async DNS complete%s (query time = %d.%3.3d)"),
485 ((status == 0) && (host != NULL)) ? "" : ", host not found",
486 dnsQueryElapsed.tv_sec,
487 dnsQueryElapsed.tv_usec / 1000);
488
489 // use reverse DNS name, if available
490
491 switch (status) {
492 case 0 :
493 /*
494 * if [reverse] DNS query was successful
495 */
496 if (host != NULL) {
497 hostname = CFStringCreateWithCString(NULL, host, kCFStringEncodingUTF8);
498 SCLog(TRUE, LOG_INFO, CFSTR("hostname (reverse DNS query) = %@"), hostname);
499 set_hostname(hostname);
500 CFRelease(hostname);
501 goto done;
502 }
503 break;
504
505 case EAI_NONAME :
506 /*
507 * if no name available
508 */
509 break;
510
511 default :
512 /*
513 * Hmmmm...
514 */
515 SCLog(TRUE, LOG_ERR, CFSTR("getnameinfo() failed: %s"), gai_strerror(status));
516 }
517
518 // get local (multicast DNS) name, if available
519
520 hostname = SCDynamicStoreCopyLocalHostName(store);
521 if (hostname != NULL) {
522 CFMutableStringRef localName;
523
524 SCLog(TRUE, LOG_INFO, CFSTR("hostname (multicast DNS) = %@"), hostname);
525 localName = CFStringCreateMutableCopy(NULL, 0, hostname);
526 CFStringAppend(localName, CFSTR(".local"));
527 set_hostname(localName);
528 CFRelease(localName);
529 CFRelease(hostname);
530 goto done;
531 }
532
533 // use "localhost" if not other name is available
534
535 set_hostname(CFSTR("localhost"));
536
537 done :
538
539 if (host != NULL) free(host);
540 if (serv != NULL) free(serv);
541 return;
542 }
543
544
545 static void
546 getnameinfo_async_handleCFReply(CFMachPortRef port, void *msg, CFIndex size, void *info)
547 {
548 getnameinfo_async_handle_reply(msg);
549
550 if (port == dnsPort) {
551 CFRelease(dnsRLS);
552 dnsRLS = NULL;
553 CFRelease(dnsPort);
554 dnsPort = NULL;
555 }
556
557 return;
558 }
559
560
561 static void
562 start_dns_query(SCDynamicStoreRef store, CFStringRef address)
563 {
564 char addr[64];
565 Boolean ok;
566 struct sockaddr *sa;
567 struct sockaddr_in sin;
568 struct sockaddr_in6 sin6;
569
570 if (_SC_cfstring_to_cstring(address, addr, sizeof(addr), kCFStringEncodingASCII) == NULL) {
571 SCLog(TRUE, LOG_ERR, CFSTR("could not convert [primary] address"));
572 return;
573 }
574
575 bzero(&sin, sizeof(sin));
576 sin.sin_len = sizeof(sin);
577 sin.sin_family = AF_INET;
578
579 bzero(&sin6, sizeof(sin6));
580 sin6.sin6_len = sizeof(sin6);
581 sin6.sin6_family = AF_INET6;
582
583 if (inet_aton(addr, &sin.sin_addr) == 1) {
584 /*
585 * if IPv4 address
586 */
587 sa = (struct sockaddr *)&sin;
588 } else if (inet_pton(AF_INET6, addr, &sin6.sin6_addr) == 1) {
589 /*
590 * if IPv6 address
591 */
592 char *p;
593
594 p = strchr(addr, '%');
595 if (p != NULL) {
596 sin6.sin6_scope_id = if_nametoindex(p+1);
597 }
598
599 sa = (struct sockaddr *)&sin6;
600 } else {
601 goto done;
602 }
603
604 ok = checkResolverReachabilityByAddress(store, sa);
605 if (ok) {
606 CFMachPortContext context = { 0, (void *)store, CFRetain, CFRelease, CFCopyDescription };
607 mach_port_t port;
608 int32_t error;
609
610 if ((dnsPort != NULL) && (dnsRLS != NULL)) {
611 /* if we already have an active async DNS query */
612 lu_async_call_cancel(CFMachPortGetPort(dnsPort));
613 CFRelease(dnsRLS);
614 dnsRLS = NULL;
615 CFRelease(dnsPort);
616 dnsPort = NULL;
617 }
618
619 (void) gettimeofday(&dnsQueryStart, NULL);
620
621 error = getnameinfo_async_start(&port,
622 sa,
623 sa->sa_len,
624 0, // flags
625 reverseDNSComplete,
626 NULL);
627 if (error != 0) {
628 goto done;
629 }
630
631 dnsPort = CFMachPortCreateWithPort(NULL,
632 port,
633 getnameinfo_async_handleCFReply,
634 &context,
635 NULL);
636 dnsRLS = CFMachPortCreateRunLoopSource(NULL, dnsPort, 0);
637 CFRunLoopAddSource(CFRunLoopGetCurrent(), dnsRLS, kCFRunLoopDefaultMode);
638 }
639
640 done :
641
642 return;
643 }
644
645
646 static void
647 update_hostname(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
648 {
649 CFStringRef address = NULL;
650 CFStringRef hostname = NULL;
651 CFStringRef serviceID = NULL;
652
653 // get static hostname, if available
654
655 hostname = copy_static_name();
656 if (hostname != NULL) {
657 SCLog(TRUE, LOG_INFO, CFSTR("hostname (static) = %@"), hostname);
658 set_hostname(hostname);
659 goto done;
660 }
661
662 // get [prefs] hostname, if available
663
664 hostname = copy_prefs_hostname(store);
665 if (hostname != NULL) {
666 SCLog(TRUE, LOG_INFO, CFSTR("hostname (prefs) = %@"), hostname);
667 set_hostname(hostname);
668 goto done;
669 }
670
671 // get primary service ID
672
673 serviceID = copy_primary_service(store);
674 if (serviceID == NULL) {
675 goto mDNS;
676 }
677
678 // get DHCP provided name, if available
679
680 hostname = copy_dhcp_name(store, serviceID);
681 if (hostname != NULL) {
682 SCLog(TRUE, LOG_INFO, CFSTR("hostname (DHCP) = %@"), hostname);
683 set_hostname(hostname);
684 goto done;
685 }
686
687 // get DNS name associated with primary IP, if available
688
689 address = copy_primary_ip(store, serviceID);
690 if (address != NULL) {
691 // start reverse DNS query using primary IP address
692 (void) start_dns_query(store, address);
693 goto done;
694 }
695
696 mDNS :
697
698 // get local (multicast DNS) name, if available
699
700 hostname = SCDynamicStoreCopyLocalHostName(store);
701 if (hostname != NULL) {
702 CFMutableStringRef localName;
703
704 SCLog(TRUE, LOG_INFO, CFSTR("hostname (multicast DNS) = %@"), hostname);
705 localName = CFStringCreateMutableCopy(NULL, 0, hostname);
706 CFStringAppend(localName, CFSTR(".local"));
707 set_hostname(localName);
708 CFRelease(localName);
709 goto done;
710 }
711
712 // use "localhost" if not other name is available
713
714 set_hostname(CFSTR("localhost"));
715
716 done :
717
718 if (address) CFRelease(address);
719 if (hostname) CFRelease(hostname);
720 if (serviceID) CFRelease(serviceID);
721
722 return;
723 }
724
725
726 __private_extern__
727 void
728 load_hostname(Boolean verbose)
729 {
730 CFStringRef key;
731 CFMutableArrayRef keys = NULL;
732 CFMutableArrayRef patterns = NULL;
733
734 if (verbose) {
735 _verbose = TRUE;
736 }
737
738 /* initialize a few globals */
739
740 store = SCDynamicStoreCreate(NULL, CFSTR("set-hostname"), update_hostname, NULL);
741 if (store == NULL) {
742 SCLog(TRUE, LOG_ERR,
743 CFSTR("SCDynamicStoreCreate() failed: %s"),
744 SCErrorString(SCError()));
745 goto error;
746 }
747
748 /* establish notification keys and patterns */
749
750 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
751 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
752
753 /* ...watch for primary service / interface changes */
754 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
755 kSCDynamicStoreDomainState,
756 kSCEntNetIPv4);
757 CFArrayAppendValue(keys, key);
758 CFRelease(key);
759
760 /* ...watch for DNS configuration changes */
761 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
762 kSCDynamicStoreDomainState,
763 kSCEntNetDNS);
764 CFArrayAppendValue(keys, key);
765 CFRelease(key);
766
767 /* ...watch for (per-service) DHCP option changes */
768 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
769 kSCDynamicStoreDomainState,
770 kSCCompAnyRegex,
771 kSCEntNetDHCP);
772 CFArrayAppendValue(patterns, key);
773 CFRelease(key);
774
775 /* ...watch for (BSD) hostname changes */
776 key = SCDynamicStoreKeyCreateComputerName(NULL);
777 CFArrayAppendValue(keys, key);
778 CFRelease(key);
779
780 /* ...watch for local (multicast DNS) hostname changes */
781 key = SCDynamicStoreKeyCreateHostNames(NULL);
782 CFArrayAppendValue(keys, key);
783 CFRelease(key);
784
785 /* register the keys/patterns */
786 if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns)) {
787 SCLog(TRUE, LOG_ERR,
788 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s"),
789 SCErrorString(SCError()));
790 goto error;
791 }
792
793 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
794 if (!rls) {
795 SCLog(TRUE, LOG_ERR,
796 CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s"),
797 SCErrorString(SCError()));
798 goto error;
799 }
800 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
801
802 CFRelease(keys);
803 CFRelease(patterns);
804 return;
805
806 error :
807
808 if (keys != NULL) CFRelease(keys);
809 if (patterns != NULL) CFRelease(patterns);
810 if (store != NULL) CFRelease(store);
811 return;
812 }
813
814
815 #ifdef MAIN
816 int
817 main(int argc, char **argv)
818 {
819
820 #ifdef DEBUG
821
822 _sc_log = FALSE;
823 if ((argc > 1) && (strcmp(argv[1], "-d") == 0)) {
824 _sc_verbose = TRUE;
825 argv++;
826 argc--;
827 }
828
829 CFStringRef address;
830 CFStringRef hostname;
831 CFStringRef serviceID;
832 SCDynamicStoreRef store;
833
834 store = SCDynamicStoreCreate(NULL, CFSTR("set-hostname"), NULL, NULL);
835 if (store == NULL) {
836 SCPrint(TRUE, stdout,
837 CFSTR("SCDynamicStoreCreate() failed: %s\n"),
838 SCErrorString(SCError()));
839 exit(1);
840 }
841
842 // get static hostname
843 hostname = copy_static_name();
844 if (hostname != NULL) {
845 SCPrint(TRUE, stdout, CFSTR("hostname (static) = %@\n"), hostname);
846 CFRelease(hostname);
847 }
848
849 // get [prefs] hostname, if available
850 hostname = copy_prefs_hostname(store);
851 if (hostname != NULL) {
852 SCPrint(TRUE, stdout, CFSTR("hostname (prefs) = %@\n"), hostname);
853 CFRelease(hostname);
854 }
855
856 // get primary service
857 serviceID = copy_primary_service(store);
858 if (serviceID != NULL) {
859 SCPrint(TRUE, stdout, CFSTR("primary service ID = %@\n"), serviceID);
860 } else {
861 SCPrint(TRUE, stdout, CFSTR("No primary service\n"));
862 goto mDNS;
863 }
864
865 if ((argc == (2+1)) && (argv[1][0] == 's')) {
866 if (serviceID != NULL) CFRelease(serviceID);
867 serviceID = CFStringCreateWithCString(NULL, argv[2], kCFStringEncodingUTF8);
868 SCPrint(TRUE, stdout, CFSTR("alternate service ID = %@\n"), serviceID);
869 }
870
871 // get DHCP provided name
872 hostname = copy_dhcp_name(store, serviceID);
873 if (hostname != NULL) {
874 SCPrint(TRUE, stdout, CFSTR("hostname (DHCP) = %@\n"), hostname);
875 CFRelease(hostname);
876 }
877
878 // get primary IP address
879 address = copy_primary_ip(store, serviceID);
880 if (address != NULL) {
881 SCPrint(TRUE, stdout, CFSTR("primary address = %@\n"), address);
882
883 if ((argc == (2+1)) && (argv[1][0] == 'a')) {
884 if (address != NULL) CFRelease(address);
885 address = CFStringCreateWithCString(NULL, argv[2], kCFStringEncodingUTF8);
886 SCPrint(TRUE, stdout, CFSTR("alternate primary address = %@\n"), address);
887 }
888
889 // start reverse DNS query using primary IP address
890 start_dns_query(store, address);
891 CFRelease(address);
892 }
893
894 CFRelease(serviceID);
895
896 mDNS :
897
898 // get local (multicast DNS) name, if available
899
900 hostname = SCDynamicStoreCopyLocalHostName(store);
901 if (hostname != NULL) {
902 CFMutableStringRef localName;
903
904 SCPrint(TRUE, stdout, CFSTR("hostname (multicast DNS) = %@\n"), hostname);
905 localName = CFStringCreateMutableCopy(NULL, 0, hostname);
906 CFStringAppend(localName, CFSTR(".local"));
907 CFRelease(localName);
908 }
909
910 if (hostname != NULL) CFRelease(hostname);
911
912 update_hostname(store, NULL, NULL);
913
914 CFRelease(store);
915
916 CFRunLoopRun();
917
918 #else /* DEBUG */
919
920 _sc_log = FALSE;
921 _sc_verbose = (argc > 1) ? TRUE : FALSE;
922
923 load_hostname((argc > 1) ? TRUE : FALSE);
924 CFRunLoopRun();
925 /* not reached */
926
927 #endif /* DEBUG */
928
929 exit(0);
930 return 0;
931 }
932 #endif /* MAIN */