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