1/* $Id$ */ 2 3/*** 4 This file is part of avahi. 5 6 avahi is free software; you can redistribute it and/or modify it 7 under the terms of the GNU Lesser General Public License as 8 published by the Free Software Foundation; either version 2.1 of the 9 License, or (at your option) any later version. 10 11 avahi is distributed in the hope that it will be useful, but WITHOUT 12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 14 Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with avahi; if not, write to the Free Software 18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 19 USA. 20***/ 21 22#ifdef HAVE_CONFIG_H 23#include <config.h> 24#endif 25 26#include <assert.h> 27#include <getopt.h> 28#include <string.h> 29#include <signal.h> 30#include <errno.h> 31#include <string.h> 32#include <unistd.h> 33#include <grp.h> 34#include <pwd.h> 35#include <sys/stat.h> 36#include <sys/ioctl.h> 37#include <stdio.h> 38#include <fcntl.h> 39#include <time.h> 40#include <stdlib.h> 41#include <sys/time.h> 42#include <sys/resource.h> 43#include <sys/socket.h> 44 45#ifdef HAVE_INOTIFY 46#include <sys/inotify.h> 47#endif 48 49#ifdef HAVE_KQUEUE 50#include <sys/types.h> 51#include <sys/event.h> 52#include <unistd.h> 53#endif 54 55#include <libdaemon/dfork.h> 56#include <libdaemon/dsignal.h> 57#include <libdaemon/dlog.h> 58#include <libdaemon/dpid.h> 59 60#include <avahi-common/malloc.h> 61#include <avahi-common/simple-watch.h> 62#include <avahi-common/error.h> 63#include <avahi-common/alternative.h> 64#include <avahi-common/domain.h> 65 66#include <avahi-core/core.h> 67#include <avahi-core/publish.h> 68#include <avahi-core/dns-srv-rr.h> 69#include <avahi-core/log.h> 70 71#ifdef ENABLE_CHROOT 72#include "chroot.h" 73#include "caps.h" 74#endif 75 76#include "setproctitle.h" 77#include "main.h" 78#include "simple-protocol.h" 79#include "static-services.h" 80#include "static-hosts.h" 81#include "ini-file-parser.h" 82 83#ifdef HAVE_DBUS 84#include "dbus-protocol.h" 85#endif 86 87AvahiServer *avahi_server = NULL; 88AvahiSimplePoll *simple_poll_api = NULL; 89static char *argv0 = NULL; 90int nss_support = 0; 91 92typedef enum { 93 DAEMON_RUN, 94 DAEMON_KILL, 95 DAEMON_VERSION, 96 DAEMON_HELP, 97 DAEMON_RELOAD, 98 DAEMON_CHECK 99} DaemonCommand; 100 101typedef struct { 102 AvahiServerConfig server_config; 103 DaemonCommand command; 104 int daemonize; 105 int use_syslog; 106 char *config_file; 107#ifdef HAVE_DBUS 108 int enable_dbus; 109 int fail_on_missing_dbus; 110#endif 111 int drop_root; 112 int set_rlimits; 113#ifdef ENABLE_CHROOT 114 int use_chroot; 115#endif 116 int modify_proc_title; 117 118 int disable_user_service_publishing; 119 int publish_resolv_conf; 120 char ** publish_dns_servers; 121 int debug; 122 123 int rlimit_as_set, rlimit_core_set, rlimit_data_set, rlimit_fsize_set, rlimit_nofile_set, rlimit_stack_set; 124 rlim_t rlimit_as, rlimit_core, rlimit_data, rlimit_fsize, rlimit_nofile, rlimit_stack; 125 126#ifdef RLIMIT_NPROC 127 int rlimit_nproc_set; 128 rlim_t rlimit_nproc; 129#endif 130} DaemonConfig; 131 132#define RESOLV_CONF "/etc/resolv.conf" 133#define BROWSE_DOMAINS_MAX 16 134 135static AvahiSEntryGroup *dns_servers_entry_group = NULL; 136static AvahiSEntryGroup *resolv_conf_entry_group = NULL; 137 138static char **resolv_conf_name_servers = NULL; 139static char **resolv_conf_search_domains = NULL; 140 141static DaemonConfig config; 142 143static int has_prefix(const char *s, const char *prefix) { 144 size_t l; 145 146 l = strlen(prefix); 147 148 return strlen(s) >= l && strncmp(s, prefix, l) == 0; 149} 150 151static int load_resolv_conf(void) { 152 int ret = -1; 153 FILE *f; 154 int i = 0, j = 0; 155 156 avahi_strfreev(resolv_conf_name_servers); 157 resolv_conf_name_servers = NULL; 158 159 avahi_strfreev(resolv_conf_search_domains); 160 resolv_conf_search_domains = NULL; 161 162#ifdef ENABLE_CHROOT 163 f = avahi_chroot_helper_get_file(RESOLV_CONF); 164#else 165 f = fopen(RESOLV_CONF, "r"); 166#endif 167 168 if (!f) { 169 avahi_log_warn("Failed to open "RESOLV_CONF": %s", strerror(errno)); 170 goto finish; 171 } 172 173 resolv_conf_name_servers = avahi_new0(char*, AVAHI_WIDE_AREA_SERVERS_MAX+1); 174 resolv_conf_search_domains = avahi_new0(char*, BROWSE_DOMAINS_MAX+1); 175 176 while (!feof(f)) { 177 char ln[128]; 178 char *p; 179 180 if (!(fgets(ln, sizeof(ln), f))) 181 break; 182 183 ln[strcspn(ln, "\r\n#")] = 0; 184 p = ln + strspn(ln, "\t "); 185 186 if ((has_prefix(p, "nameserver ") || has_prefix(p, "nameserver\t")) && i < AVAHI_WIDE_AREA_SERVERS_MAX) { 187 p += 10; 188 p += strspn(p, "\t "); 189 p[strcspn(p, "\t ")] = 0; 190 resolv_conf_name_servers[i++] = avahi_strdup(p); 191 } 192 193 if ((has_prefix(p, "search ") || has_prefix(p, "search\t") || 194 has_prefix(p, "domain ") || has_prefix(p, "domain\t"))) { 195 196 p += 6; 197 198 while (j < BROWSE_DOMAINS_MAX) { 199 size_t k; 200 201 p += strspn(p, "\t "); 202 k = strcspn(p, "\t "); 203 204 if (k > 0) { 205 resolv_conf_search_domains[j++] = avahi_strndup(p, k); 206 p += k; 207 } 208 209 if (!*p) 210 break; 211 } 212 } 213 } 214 215 ret = 0; 216 217finish: 218 219 if (ret != 0) { 220 avahi_strfreev(resolv_conf_name_servers); 221 resolv_conf_name_servers = NULL; 222 223 avahi_strfreev(resolv_conf_search_domains); 224 resolv_conf_search_domains = NULL; 225 } 226 227 if (f) 228 fclose(f); 229 230 return ret; 231} 232 233static AvahiSEntryGroup* add_dns_servers(AvahiServer *s, AvahiSEntryGroup* g, char **l) { 234 char **p; 235 236 assert(s); 237 assert(l); 238 239 if (!g) 240 g = avahi_s_entry_group_new(s, NULL, NULL); 241 242 assert(avahi_s_entry_group_is_empty(g)); 243 244 for (p = l; *p; p++) { 245 AvahiAddress a; 246 247 if (!avahi_address_parse(*p, AVAHI_PROTO_UNSPEC, &a)) 248 avahi_log_warn("Failed to parse address '%s', ignoring.", *p); 249 else 250 if (avahi_server_add_dns_server_address(s, g, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, NULL, AVAHI_DNS_SERVER_RESOLVE, &a, 53) < 0) { 251 avahi_s_entry_group_free(g); 252 avahi_log_error("Failed to add DNS server address: %s", avahi_strerror(avahi_server_errno(s))); 253 return NULL; 254 } 255 } 256 257 avahi_s_entry_group_commit(g); 258 259 return g; 260} 261 262static void remove_dns_server_entry_groups(void) { 263 264 if (resolv_conf_entry_group) 265 avahi_s_entry_group_reset(resolv_conf_entry_group); 266 267 if (dns_servers_entry_group) 268 avahi_s_entry_group_reset(dns_servers_entry_group); 269} 270 271static void update_wide_area_servers(void) { 272 AvahiAddress a[AVAHI_WIDE_AREA_SERVERS_MAX]; 273 unsigned n = 0; 274 char **p; 275 276 if (!resolv_conf_name_servers) { 277 avahi_server_set_wide_area_servers(avahi_server, NULL, 0); 278 return; 279 } 280 281 for (p = resolv_conf_name_servers; *p && n < AVAHI_WIDE_AREA_SERVERS_MAX; p++) { 282 if (!avahi_address_parse(*p, AVAHI_PROTO_UNSPEC, &a[n])) 283 avahi_log_warn("Failed to parse address '%s', ignoring.", *p); 284 else 285 n++; 286 } 287 288 avahi_server_set_wide_area_servers(avahi_server, a, n); 289} 290 291static AvahiStringList *filter_duplicate_domains(AvahiStringList *l) { 292 AvahiStringList *e, *n, *p; 293 294 if (!l) 295 return l; 296 297 for (p = l, e = l->next; e; e = n) { 298 n = e->next; 299 300 if (avahi_domain_equal((char*) e->text, (char*) l->text)) { 301 p->next = e->next; 302 avahi_free(e); 303 } else 304 p = e; 305 } 306 307 l->next = filter_duplicate_domains(l->next); 308 return l; 309} 310 311static void update_browse_domains(void) { 312 AvahiStringList *l; 313 int n; 314 char **p; 315 316 if (!resolv_conf_search_domains) { 317 avahi_server_set_browse_domains(avahi_server, NULL); 318 return; 319 } 320 321 l = avahi_string_list_copy(config.server_config.browse_domains); 322 323 for (p = resolv_conf_search_domains, n = 0; *p && n < BROWSE_DOMAINS_MAX; p++, n++) { 324 if (!avahi_is_valid_domain_name(*p)) 325 avahi_log_warn("'%s' is no valid domain name, ignoring.", *p); 326 else 327 l = avahi_string_list_add(l, *p); 328 } 329 330 l = filter_duplicate_domains(l); 331 332 avahi_server_set_browse_domains(avahi_server, l); 333} 334 335static void server_callback(AvahiServer *s, AvahiServerState state, void *userdata) { 336 DaemonConfig *c = userdata; 337 338 assert(s); 339 assert(c); 340 341 /* This function is possibly called before the global variable 342 * avahi_server has been set, therefore we do it explicitly */ 343 344 avahi_server = s; 345 346#ifdef HAVE_DBUS 347 if (c->enable_dbus && state != AVAHI_SERVER_INVALID && state != AVAHI_SERVER_FAILURE) 348 dbus_protocol_server_state_changed(state); 349#endif 350 351 switch (state) { 352 case AVAHI_SERVER_RUNNING: 353 avahi_log_info("Server startup complete. Host name is %s. Local service cookie is %u.", avahi_server_get_host_name_fqdn(s), avahi_server_get_local_service_cookie(s)); 354 355 avahi_set_proc_title(argv0, "%s: running [%s]", argv0, avahi_server_get_host_name_fqdn(s)); 356 357 static_service_add_to_server(); 358 static_hosts_add_to_server(); 359 360 remove_dns_server_entry_groups(); 361 362 if (c->publish_resolv_conf && resolv_conf_name_servers && resolv_conf_name_servers[0]) 363 resolv_conf_entry_group = add_dns_servers(s, resolv_conf_entry_group, resolv_conf_name_servers); 364 365 if (c->publish_dns_servers && c->publish_dns_servers[0]) 366 dns_servers_entry_group = add_dns_servers(s, dns_servers_entry_group, c->publish_dns_servers); 367 368 simple_protocol_restart_queries(); 369 break; 370 371 case AVAHI_SERVER_COLLISION: { 372 char *n; 373 374 avahi_set_proc_title(argv0, "%s: collision", argv0); 375 376 static_service_remove_from_server(); 377 static_hosts_remove_from_server(); 378 remove_dns_server_entry_groups(); 379 380 n = avahi_alternative_host_name(avahi_server_get_host_name(s)); 381 avahi_log_warn("Host name conflict, retrying with <%s>", n); 382 avahi_server_set_host_name(s, n); 383 avahi_free(n); 384 385 break; 386 } 387 388 case AVAHI_SERVER_FAILURE: 389 390 avahi_log_error("Server error: %s", avahi_strerror(avahi_server_errno(s))); 391 avahi_simple_poll_quit(simple_poll_api); 392 break; 393 394 case AVAHI_SERVER_REGISTERING: 395 396 avahi_set_proc_title(argv0, "%s: registering [%s]", argv0, avahi_server_get_host_name_fqdn(s)); 397 398 static_service_remove_from_server(); 399 static_hosts_remove_from_server(); 400 remove_dns_server_entry_groups(); 401 402 break; 403 404 case AVAHI_SERVER_INVALID: 405 break; 406 407 } 408} 409 410static void help(FILE *f) { 411 fprintf(f, 412 "%s [options]\n" 413 " -h --help Show this help\n" 414 " -D --daemonize Daemonize after startup (implies -s)\n" 415 " -s --syslog Write log messages to syslog(3) instead of STDERR\n" 416 " -k --kill Kill a running daemon\n" 417 " -r --reload Request a running daemon to reload static services\n" 418 " -c --check Return 0 if a daemon is already running\n" 419 " -V --version Show version\n" 420 " -f --file=FILE Load the specified configuration file instead of\n" 421 " "AVAHI_CONFIG_FILE"\n" 422 " --no-rlimits Don't enforce resource limits\n" 423 " --no-drop-root Don't drop privileges\n" 424#ifdef ENABLE_CHROOT 425 " --no-chroot Don't chroot()\n" 426#endif 427 " --no-proc-title Don't modify process title\n" 428 " --debug Increase verbosity\n", 429 argv0); 430} 431 432 433static int parse_command_line(DaemonConfig *c, int argc, char *argv[]) { 434 int o; 435 436 enum { 437 OPTION_NO_RLIMITS = 256, 438 OPTION_NO_DROP_ROOT, 439#ifdef ENABLE_CHROOT 440 OPTION_NO_CHROOT, 441#endif 442 OPTION_NO_PROC_TITLE, 443 OPTION_DEBUG 444 }; 445 446 static const struct option long_options[] = { 447 { "help", no_argument, NULL, 'h' }, 448 { "daemonize", no_argument, NULL, 'D' }, 449 { "kill", no_argument, NULL, 'k' }, 450 { "version", no_argument, NULL, 'V' }, 451 { "file", required_argument, NULL, 'f' }, 452 { "reload", no_argument, NULL, 'r' }, 453 { "check", no_argument, NULL, 'c' }, 454 { "syslog", no_argument, NULL, 's' }, 455 { "no-rlimits", no_argument, NULL, OPTION_NO_RLIMITS }, 456 { "no-drop-root", no_argument, NULL, OPTION_NO_DROP_ROOT }, 457#ifdef ENABLE_CHROOT 458 { "no-chroot", no_argument, NULL, OPTION_NO_CHROOT }, 459#endif 460 { "no-proc-title", no_argument, NULL, OPTION_NO_PROC_TITLE }, 461 { "debug", no_argument, NULL, OPTION_DEBUG }, 462 { NULL, 0, NULL, 0 } 463 }; 464 465 assert(c); 466 467 while ((o = getopt_long(argc, argv, "hDkVf:rcs", long_options, NULL)) >= 0) { 468 469 switch(o) { 470 case 's': 471 c->use_syslog = 1; 472 break; 473 case 'h': 474 c->command = DAEMON_HELP; 475 break; 476 case 'D': 477 c->daemonize = 1; 478 break; 479 case 'k': 480 c->command = DAEMON_KILL; 481 break; 482 case 'V': 483 c->command = DAEMON_VERSION; 484 break; 485 case 'f': 486 avahi_free(c->config_file); 487 c->config_file = avahi_strdup(optarg); 488 break; 489 case 'r': 490 c->command = DAEMON_RELOAD; 491 break; 492 case 'c': 493 c->command = DAEMON_CHECK; 494 break; 495 case OPTION_NO_RLIMITS: 496 c->set_rlimits = 0; 497 break; 498 case OPTION_NO_DROP_ROOT: 499 c->drop_root = 0; 500 break; 501#ifdef ENABLE_CHROOT 502 case OPTION_NO_CHROOT: 503 c->use_chroot = 0; 504 break; 505#endif 506 case OPTION_NO_PROC_TITLE: 507 c->modify_proc_title = 0; 508 break; 509 case OPTION_DEBUG: 510 c->debug = 1; 511 break; 512 default: 513 return -1; 514 } 515 } 516 517 if (optind < argc) { 518 fprintf(stderr, "Too many arguments\n"); 519 return -1; 520 } 521 522 return 0; 523} 524 525static int is_yes(const char *s) { 526 assert(s); 527 528 return *s == 'y' || *s == 'Y' || *s == '1' || *s == 't' || *s == 'T'; 529} 530 531static int load_config_file(DaemonConfig *c) { 532 int r = -1; 533 AvahiIniFile *f; 534 AvahiIniFileGroup *g; 535 536 assert(c); 537 538 if (!(f = avahi_ini_file_load(c->config_file ? c->config_file : AVAHI_CONFIG_FILE))) 539 goto finish; 540 541 for (g = f->groups; g; g = g->groups_next) { 542 543 if (strcasecmp(g->name, "server") == 0) { 544 AvahiIniFilePair *p; 545 546 for (p = g->pairs; p; p = p->pairs_next) { 547 548 if (strcasecmp(p->key, "host-name") == 0) { 549 avahi_free(c->server_config.host_name); 550 c->server_config.host_name = avahi_strdup(p->value); 551 } else if (strcasecmp(p->key, "domain-name") == 0) { 552 avahi_free(c->server_config.domain_name); 553 c->server_config.domain_name = avahi_strdup(p->value); 554 } else if (strcasecmp(p->key, "browse-domains") == 0) { 555 char **e, **t; 556 557 e = avahi_split_csv(p->value); 558 559 for (t = e; *t; t++) { 560 char cleaned[AVAHI_DOMAIN_NAME_MAX]; 561 562 if (!avahi_normalize_name(*t, cleaned, sizeof(cleaned))) { 563 avahi_log_error("Invalid domain name \"%s\" for key \"%s\" in group \"%s\"\n", *t, p->key, g->name); 564 avahi_strfreev(e); 565 goto finish; 566 } 567 568 c->server_config.browse_domains = avahi_string_list_add(c->server_config.browse_domains, cleaned); 569 } 570 571 avahi_strfreev(e); 572 573 c->server_config.browse_domains = filter_duplicate_domains(c->server_config.browse_domains); 574 } else if (strcasecmp(p->key, "use-ipv4") == 0) 575 c->server_config.use_ipv4 = is_yes(p->value); 576 else if (strcasecmp(p->key, "use-ipv6") == 0) 577 c->server_config.use_ipv6 = is_yes(p->value); 578 else if (strcasecmp(p->key, "check-response-ttl") == 0) 579 c->server_config.check_response_ttl = is_yes(p->value); 580 else if (strcasecmp(p->key, "allow-point-to-point") == 0) 581 c->server_config.allow_point_to_point = is_yes(p->value); 582 else if (strcasecmp(p->key, "use-iff-running") == 0) 583 c->server_config.use_iff_running = is_yes(p->value); 584 else if (strcasecmp(p->key, "disallow-other-stacks") == 0) 585 c->server_config.disallow_other_stacks = is_yes(p->value); 586#ifdef HAVE_DBUS 587 else if (strcasecmp(p->key, "enable-dbus") == 0) { 588 589 if (*(p->value) == 'w' || *(p->value) == 'W') { 590 c->fail_on_missing_dbus = 0; 591 c->enable_dbus = 1; 592 } else if (*(p->value) == 'y' || *(p->value) == 'Y') { 593 c->fail_on_missing_dbus = 1; 594 c->enable_dbus = 1; 595 } else { 596 c->enable_dbus = 0; 597 } 598 } 599#endif 600 else if (strcasecmp(p->key, "allow-interfaces") == 0) { 601 char **e, **t; 602 603 avahi_string_list_free(c->server_config.allow_interfaces); 604 c->server_config.allow_interfaces = NULL; 605 e = avahi_split_csv(p->value); 606 607 for (t = e; *t; t++) 608 c->server_config.allow_interfaces = avahi_string_list_add(c->server_config.allow_interfaces, *t); 609 610 avahi_strfreev(e); 611 } else if (strcasecmp(p->key, "deny-interfaces") == 0) { 612 char **e, **t; 613 614 avahi_string_list_free(c->server_config.deny_interfaces); 615 c->server_config.deny_interfaces = NULL; 616 e = avahi_split_csv(p->value); 617 618 for (t = e; *t; t++) 619 c->server_config.deny_interfaces = avahi_string_list_add(c->server_config.deny_interfaces, *t); 620 621 avahi_strfreev(e); 622 } else { 623 avahi_log_error("Invalid configuration key \"%s\" in group \"%s\"\n", p->key, g->name); 624 goto finish; 625 } 626 } 627 628 } else if (strcasecmp(g->name, "publish") == 0) { 629 AvahiIniFilePair *p; 630 631 for (p = g->pairs; p; p = p->pairs_next) { 632 633 if (strcasecmp(p->key, "publish-addresses") == 0) 634 c->server_config.publish_addresses = is_yes(p->value); 635 else if (strcasecmp(p->key, "publish-hinfo") == 0) 636 c->server_config.publish_hinfo = is_yes(p->value); 637 else if (strcasecmp(p->key, "publish-workstation") == 0) 638 c->server_config.publish_workstation = is_yes(p->value); 639 else if (strcasecmp(p->key, "publish-domain") == 0) 640 c->server_config.publish_domain = is_yes(p->value); 641 else if (strcasecmp(p->key, "publish-resolv-conf-dns-servers") == 0) 642 c->publish_resolv_conf = is_yes(p->value); 643 else if (strcasecmp(p->key, "disable-publishing") == 0) 644 c->server_config.disable_publishing = is_yes(p->value); 645 else if (strcasecmp(p->key, "disable-user-service-publishing") == 0) 646 c->disable_user_service_publishing = is_yes(p->value); 647 else if (strcasecmp(p->key, "add-service-cookie") == 0) 648 c->server_config.add_service_cookie = is_yes(p->value); 649 else if (strcasecmp(p->key, "publish-dns-servers") == 0) { 650 avahi_strfreev(c->publish_dns_servers); 651 c->publish_dns_servers = avahi_split_csv(p->value); 652 } else if (strcasecmp(p->key, "publish-a-on-ipv6") == 0) 653 c->server_config.publish_a_on_ipv6 = is_yes(p->value); 654 else if (strcasecmp(p->key, "publish-aaaa-on-ipv4") == 0) 655 c->server_config.publish_aaaa_on_ipv4 = is_yes(p->value); 656 else { 657 avahi_log_error("Invalid configuration key \"%s\" in group \"%s\"\n", p->key, g->name); 658 goto finish; 659 } 660 } 661 662 } else if (strcasecmp(g->name, "wide-area") == 0) { 663 AvahiIniFilePair *p; 664 665 for (p = g->pairs; p; p = p->pairs_next) { 666 667 if (strcasecmp(p->key, "enable-wide-area") == 0) 668 c->server_config.enable_wide_area = is_yes(p->value); 669 else { 670 avahi_log_error("Invalid configuration key \"%s\" in group \"%s\"\n", p->key, g->name); 671 goto finish; 672 } 673 } 674 675 } else if (strcasecmp(g->name, "reflector") == 0) { 676 AvahiIniFilePair *p; 677 678 for (p = g->pairs; p; p = p->pairs_next) { 679 680 if (strcasecmp(p->key, "enable-reflector") == 0) 681 c->server_config.enable_reflector = is_yes(p->value); 682 else if (strcasecmp(p->key, "reflect-ipv") == 0) 683 c->server_config.reflect_ipv = is_yes(p->value); 684 else { 685 avahi_log_error("Invalid configuration key \"%s\" in group \"%s\"\n", p->key, g->name); 686 goto finish; 687 } 688 } 689 690 } else if (strcasecmp(g->name, "rlimits") == 0) { 691 AvahiIniFilePair *p; 692 693 for (p = g->pairs; p; p = p->pairs_next) { 694 695 if (strcasecmp(p->key, "rlimit-as") == 0) { 696 c->rlimit_as_set = 1; 697 c->rlimit_as = atoi(p->value); 698 } else if (strcasecmp(p->key, "rlimit-core") == 0) { 699 c->rlimit_core_set = 1; 700 c->rlimit_core = atoi(p->value); 701 } else if (strcasecmp(p->key, "rlimit-data") == 0) { 702 c->rlimit_data_set = 1; 703 c->rlimit_data = atoi(p->value); 704 } else if (strcasecmp(p->key, "rlimit-fsize") == 0) { 705 c->rlimit_fsize_set = 1; 706 c->rlimit_fsize = atoi(p->value); 707 } else if (strcasecmp(p->key, "rlimit-nofile") == 0) { 708 c->rlimit_nofile_set = 1; 709 c->rlimit_nofile = atoi(p->value); 710 } else if (strcasecmp(p->key, "rlimit-stack") == 0) { 711 c->rlimit_stack_set = 1; 712 c->rlimit_stack = atoi(p->value); 713 } else if (strcasecmp(p->key, "rlimit-nproc") == 0) { 714#ifdef RLIMIT_NPROC 715 c->rlimit_nproc_set = 1; 716 c->rlimit_nproc = atoi(p->value); 717#else 718 avahi_log_error("Ignoring configuration key \"%s\" in group \"%s\"\n", p->key, g->name); 719#endif 720 } else { 721 avahi_log_error("Invalid configuration key \"%s\" in group \"%s\"\n", p->key, g->name); 722 goto finish; 723 } 724 725 } 726 727 } else { 728 avahi_log_error("Invalid configuration file group \"%s\".\n", g->name); 729 goto finish; 730 } 731 } 732 733 r = 0; 734 735finish: 736 737 if (f) 738 avahi_ini_file_free(f); 739 740 return r; 741} 742 743static void log_function(AvahiLogLevel level, const char *txt) { 744 745 static const int log_level_map[] = { 746 LOG_ERR, 747 LOG_WARNING, 748 LOG_NOTICE, 749 LOG_INFO, 750 LOG_DEBUG 751 }; 752 753 assert(level < AVAHI_LOG_LEVEL_MAX); 754 assert(txt); 755 756 if (!config.debug && level == AVAHI_LOG_DEBUG) 757 return; 758 759 daemon_log(log_level_map[level], "%s", txt); 760} 761 762static void dump(const char *text, AVAHI_GCC_UNUSED void* userdata) { 763 avahi_log_info("%s", text); 764} 765 766#ifdef HAVE_INOTIFY 767 768static int inotify_fd = -1; 769 770static void add_inotify_watches(void) { 771 int c = 0; 772 /* We ignore the return values, because one or more of these files 773 * might not exist and we're OK with that. In addition we never 774 * want to remove these watches, hence we keep their ids? */ 775 776#ifdef ENABLE_CHROOT 777 c = config.use_chroot; 778#endif 779 780 inotify_add_watch(inotify_fd, c ? "/services" : AVAHI_SERVICE_DIR, IN_CLOSE_WRITE|IN_DELETE|IN_DELETE_SELF|IN_MOVED_FROM|IN_MOVED_TO|IN_MOVE_SELF 781#ifdef IN_ONLYDIR 782 |IN_ONLYDIR 783#endif 784 ); 785 inotify_add_watch(inotify_fd, c ? "/" : AVAHI_CONFIG_DIR, IN_CLOSE_WRITE|IN_DELETE|IN_DELETE_SELF|IN_MOVED_FROM|IN_MOVED_TO|IN_MOVE_SELF 786#ifdef IN_ONLYDIR 787 |IN_ONLYDIR 788#endif 789 ); 790} 791 792#endif 793 794#ifdef HAVE_KQUEUE 795 796#define NUM_WATCHES 2 797 798static int kq = -1; 799static int kfds[NUM_WATCHES]; 800static int num_kfds = 0; 801 802static void add_kqueue_watch(const char *dir); 803 804static void add_kqueue_watches(void) { 805 int c = 0; 806 807#ifdef ENABLE_CHROOT 808 c = config.use_chroot; 809#endif 810 811 add_kqueue_watch(c ? "/" : AVAHI_CONFIG_DIR); 812 add_kqueue_watch(c ? "/services" : AVAHI_SERVICE_DIR); 813} 814 815static void add_kqueue_watch(const char *dir) { 816 int fd; 817 struct kevent ev; 818 819 if (kq < 0) 820 return; 821 822 if (num_kfds >= NUM_WATCHES) 823 return; 824 825 fd = open(dir, O_RDONLY); 826 if (fd < 0) 827 return; 828 EV_SET(&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, 829 NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_RENAME, 830 0, 0); 831 if (kevent(kq, &ev, 1, NULL, 0, NULL) == -1) { 832 close(fd); 833 return; 834 } 835 836 kfds[num_kfds++] = fd; 837} 838 839#endif 840 841static void reload_config(void) { 842 843#ifdef HAVE_INOTIFY 844 /* Refresh in case the config dirs have been removed */ 845 add_inotify_watches(); 846#endif 847 848#ifdef HAVE_KQUEUE 849 add_kqueue_watches(); 850#endif 851 852#ifdef ENABLE_CHROOT 853 static_service_load(config.use_chroot); 854 static_hosts_load(config.use_chroot); 855#else 856 static_service_load(0); 857 static_hosts_load(0); 858#endif 859 static_service_add_to_server(); 860 static_hosts_add_to_server(); 861 862 if (resolv_conf_entry_group) 863 avahi_s_entry_group_reset(resolv_conf_entry_group); 864 865 load_resolv_conf(); 866 867 update_wide_area_servers(); 868 update_browse_domains(); 869 870 if (config.publish_resolv_conf && resolv_conf_name_servers && resolv_conf_name_servers[0]) 871 resolv_conf_entry_group = add_dns_servers(avahi_server, resolv_conf_entry_group, resolv_conf_name_servers); 872} 873 874#ifdef HAVE_INOTIFY 875 876static void inotify_callback(AvahiWatch *watch, int fd, AVAHI_GCC_UNUSED AvahiWatchEvent event, AVAHI_GCC_UNUSED void *userdata) { 877 char* buffer; 878 int n = 0; 879 880 assert(fd == inotify_fd); 881 assert(watch); 882 883 ioctl(inotify_fd, FIONREAD, &n); 884 if (n <= 0) 885 n = 128; 886 887 buffer = avahi_malloc(n); 888 if (read(inotify_fd, buffer, n) < 0 ) { 889 avahi_free(buffer); 890 avahi_log_error("Failed to read inotify event: %s", avahi_strerror(errno)); 891 return; 892 } 893 avahi_free(buffer); 894 895 avahi_log_info("Files changed, reloading."); 896 reload_config(); 897} 898 899#endif 900 901#ifdef HAVE_KQUEUE 902 903static void kqueue_callback(AvahiWatch *watch, int fd, AVAHI_GCC_UNUSED AvahiWatchEvent event, AVAHI_GCC_UNUSED void *userdata) { 904 struct kevent ev; 905 struct timespec nullts = { 0, 0 }; 906 int res; 907 908 assert(fd == kq); 909 assert(watch); 910 911 res = kevent(kq, NULL, 0, &ev, 1, &nullts); 912 913 if (res > 0) { 914 /* Sleep for a half-second to avoid potential races 915 * during install/uninstall. */ 916 usleep(500000); 917 avahi_log_info("Files changed, reloading."); 918 reload_config(); 919 } else { 920 avahi_log_error("Failed to read kqueue event: %s", avahi_strerror(errno)); 921 } 922} 923 924#endif 925 926static void signal_callback(AvahiWatch *watch, AVAHI_GCC_UNUSED int fd, AVAHI_GCC_UNUSED AvahiWatchEvent event, AVAHI_GCC_UNUSED void *userdata) { 927 int sig; 928 const AvahiPoll *poll_api; 929 930 assert(watch); 931 assert(simple_poll_api); 932 933 poll_api = avahi_simple_poll_get(simple_poll_api); 934 935 if ((sig = daemon_signal_next()) <= 0) { 936 avahi_log_error("daemon_signal_next() failed"); 937 poll_api->watch_free(watch); 938 return; 939 } 940 941 switch (sig) { 942 case SIGINT: 943 case SIGQUIT: 944 case SIGTERM: 945 avahi_log_info( 946 "Got %s, quitting.", 947 sig == SIGINT ? "SIGINT" : 948 (sig == SIGQUIT ? "SIGQUIT" : "SIGTERM")); 949 avahi_simple_poll_quit(simple_poll_api); 950 break; 951 952 case SIGHUP: 953 avahi_log_info("Got SIGHUP, reloading."); 954 955 reload_config(); 956 break; 957 958 case SIGUSR1: 959 avahi_log_info("Got SIGUSR1, dumping record data."); 960 avahi_server_dump(avahi_server, dump, NULL); 961 break; 962 963 default: 964 avahi_log_warn("Got spurious signal, ignoring."); 965 break; 966 } 967} 968 969/* Imported from ../avahi-client/nss-check.c */ 970int avahi_nss_support(void); 971 972static int run_server(DaemonConfig *c) { 973 int r = -1; 974 int error; 975 const AvahiPoll *poll_api = NULL; 976 AvahiWatch *sig_watch = NULL; 977 int retval_is_sent = 0; 978#ifdef HAVE_INOTIFY 979 AvahiWatch *inotify_watch = NULL; 980#endif 981#ifdef HAVE_KQUEUE 982 int i; 983 AvahiWatch *kqueue_watch = NULL; 984#endif 985 986 assert(c); 987 988 if (!(nss_support = avahi_nss_support())) 989 avahi_log_warn("WARNING: No NSS support for mDNS detected, consider installing nss-mdns!"); 990 991 if (!(simple_poll_api = avahi_simple_poll_new())) { 992 avahi_log_error("Failed to create main loop object."); 993 goto finish; 994 } 995 996 poll_api = avahi_simple_poll_get(simple_poll_api); 997 998 if (daemon_signal_init(SIGINT, SIGQUIT, SIGHUP, SIGTERM, SIGUSR1, 0) < 0) { 999 avahi_log_error("Could not register signal handlers (%s).", strerror(errno)); 1000 goto finish; 1001 } 1002 1003 if (!(sig_watch = poll_api->watch_new(poll_api, daemon_signal_fd(), AVAHI_WATCH_IN, signal_callback, simple_poll_api))) { 1004 avahi_log_error( "Failed to create signal watcher"); 1005 goto finish; 1006 } 1007 1008 if (simple_protocol_setup(poll_api) < 0) 1009 goto finish; 1010 1011#ifdef HAVE_DBUS 1012 if (c->enable_dbus) { 1013 if (dbus_protocol_setup(poll_api, config.disable_user_service_publishing, !c->fail_on_missing_dbus 1014#ifdef ENABLE_CHROOT 1015 && !config.use_chroot 1016#endif 1017 ) < 0) { 1018 1019 avahi_log_warn("WARNING: Failed to contact D-Bus daemon."); 1020 1021 if (c->fail_on_missing_dbus) 1022 goto finish; 1023 } 1024 } 1025#endif 1026 1027#ifdef ENABLE_CHROOT 1028 1029 if (config.drop_root && config.use_chroot) { 1030 if (chroot(AVAHI_CONFIG_DIR) < 0) { 1031 avahi_log_error("Failed to chroot(): %s", strerror(errno)); 1032 goto finish; 1033 } 1034 1035 avahi_log_info("Successfully called chroot()."); 1036 chdir("/"); 1037 1038 if (avahi_caps_drop_all() < 0) { 1039 avahi_log_error("Failed to drop capabilities."); 1040 goto finish; 1041 } 1042 avahi_log_info("Successfully dropped remaining capabilities."); 1043 } 1044 1045#endif 1046 1047#ifdef HAVE_INOTIFY 1048 if ((inotify_fd = inotify_init()) < 0) 1049 avahi_log_warn( "Failed to initialize inotify: %s", strerror(errno)); 1050 else { 1051 add_inotify_watches(); 1052 1053 if (!(inotify_watch = poll_api->watch_new(poll_api, inotify_fd, AVAHI_WATCH_IN, inotify_callback, NULL))) { 1054 avahi_log_error( "Failed to create inotify watcher"); 1055 goto finish; 1056 } 1057 } 1058#endif 1059 1060#ifdef HAVE_KQUEUE 1061 if ((kq = kqueue()) < 0) 1062 avahi_log_warn( "Failed to initialize kqueue: %s", strerror(errno)); 1063 else { 1064 add_kqueue_watches(); 1065 1066 if (!(kqueue_watch = poll_api->watch_new(poll_api, kq, AVAHI_WATCH_IN, kqueue_callback, NULL))) { 1067 avahi_log_error( "Failed to create kqueue watcher"); 1068 goto finish; 1069 } 1070 } 1071#endif 1072 1073 load_resolv_conf(); 1074#ifdef ENABLE_CHROOT 1075 static_service_load(config.use_chroot); 1076 static_hosts_load(config.use_chroot); 1077#else 1078 static_service_load(0); 1079 static_hosts_load(0); 1080#endif 1081 1082 if (!(avahi_server = avahi_server_new(poll_api, &c->server_config, server_callback, c, &error))) { 1083 avahi_log_error("Failed to create server: %s", avahi_strerror(error)); 1084 goto finish; 1085 } 1086 1087 update_wide_area_servers(); 1088 update_browse_domains(); 1089 1090 if (c->daemonize) { 1091 daemon_retval_send(0); 1092 retval_is_sent = 1; 1093 } 1094 1095 for (;;) { 1096 if ((r = avahi_simple_poll_iterate(simple_poll_api, -1)) < 0) { 1097 1098 /* We handle signals through an FD, so let's continue */ 1099 if (errno == EINTR) 1100 continue; 1101 1102 avahi_log_error("poll(): %s", strerror(errno)); 1103 goto finish; 1104 } else if (r > 0) 1105 /* Quit */ 1106 break; 1107 } 1108 1109 1110finish: 1111 1112 static_service_remove_from_server(); 1113 static_service_free_all(); 1114 1115 static_hosts_remove_from_server(); 1116 static_hosts_free_all(); 1117 1118 remove_dns_server_entry_groups(); 1119 1120 simple_protocol_shutdown(); 1121 1122#ifdef HAVE_DBUS 1123 if (c->enable_dbus) 1124 dbus_protocol_shutdown(); 1125#endif 1126 1127 if (avahi_server) { 1128 avahi_server_free(avahi_server); 1129 avahi_server = NULL; 1130 } 1131 1132 daemon_signal_done(); 1133 1134 if (sig_watch) 1135 poll_api->watch_free(sig_watch); 1136 1137#ifdef HAVE_INOTIFY 1138 if (inotify_watch) 1139 poll_api->watch_free(inotify_watch); 1140 if (inotify_fd >= 0) 1141 close(inotify_fd); 1142#endif 1143 1144#ifdef HAVE_KQUEUE 1145 if (kqueue_watch) 1146 poll_api->watch_free(kqueue_watch); 1147 if (kq >= 0) 1148 close(kq); 1149 for (i = 0; i < num_kfds; i++) { 1150 if (kfds[i] >= 0) 1151 close(kfds[i]); 1152 } 1153#endif 1154 1155 if (simple_poll_api) { 1156 avahi_simple_poll_free(simple_poll_api); 1157 simple_poll_api = NULL; 1158 } 1159 1160 if (!retval_is_sent && c->daemonize) 1161 daemon_retval_send(1); 1162 1163 return r; 1164} 1165 1166#define set_env(key, value) putenv(avahi_strdup_printf("%s=%s", (key), (value))) 1167 1168static int drop_root(void) { 1169 struct passwd *pw; 1170 struct group * gr; 1171 int r; 1172 1173 if (!(pw = getpwnam(AVAHI_USER))) { 1174 avahi_log_error( "Failed to find user '"AVAHI_USER"'."); 1175 return -1; 1176 } 1177 1178 if (!(gr = getgrnam(AVAHI_GROUP))) { 1179 avahi_log_error( "Failed to find group '"AVAHI_GROUP"'."); 1180 return -1; 1181 } 1182 1183 avahi_log_info("Found user '"AVAHI_USER"' (UID %lu) and group '"AVAHI_GROUP"' (GID %lu).", (unsigned long) pw->pw_uid, (unsigned long) gr->gr_gid); 1184 1185 if (initgroups(AVAHI_USER, gr->gr_gid) != 0) { 1186 avahi_log_error("Failed to change group list: %s", strerror(errno)); 1187 return -1; 1188 } 1189 1190#if defined(HAVE_SETRESGID) 1191 r = setresgid(gr->gr_gid, gr->gr_gid, gr->gr_gid); 1192#elif defined(HAVE_SETEGID) 1193 if ((r = setgid(gr->gr_gid)) >= 0) 1194 r = setegid(gr->gr_gid); 1195#elif defined(HAVE_SETREGID) 1196 r = setregid(gr->gr_gid, gr->gr_gid); 1197#else 1198#error "No API to drop privileges" 1199#endif 1200 1201 if (r < 0) { 1202 avahi_log_error("Failed to change GID: %s", strerror(errno)); 1203 return -1; 1204 } 1205 1206#if defined(HAVE_SETRESUID) 1207 r = setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid); 1208#elif defined(HAVE_SETEUID) 1209 if ((r = setuid(pw->pw_uid)) >= 0) 1210 r = seteuid(pw->pw_uid); 1211#elif defined(HAVE_SETREUID) 1212 r = setreuid(pw->pw_uid, pw->pw_uid); 1213#else 1214#error "No API to drop privileges" 1215#endif 1216 1217 if (r < 0) { 1218 avahi_log_error("Failed to change UID: %s", strerror(errno)); 1219 return -1; 1220 } 1221 1222 set_env("USER", pw->pw_name); 1223 set_env("LOGNAME", pw->pw_name); 1224 set_env("HOME", pw->pw_dir); 1225 1226 avahi_log_info("Successfully dropped root privileges."); 1227 1228 return 0; 1229} 1230 1231static const char* pid_file_proc(void) { 1232 return AVAHI_DAEMON_RUNTIME_DIR"/pid"; 1233} 1234 1235static int make_runtime_dir(void) { 1236 1237 /* Foxconn modified start */ 1238#if 1 1239 1240 mkdir(AVAHI_DAEMON_RUNTIME_DIR, 0755); 1241 return 0; 1242 1243#else 1244 int r = -1; 1245 mode_t u; 1246 int reset_umask = 0; 1247 struct passwd *pw; 1248 struct group * gr; 1249 struct stat st; 1250 1251 if (!(pw = getpwnam(AVAHI_USER))) { 1252 avahi_log_error( "Failed to find user '"AVAHI_USER"'."); 1253 goto fail; 1254 } 1255 1256 if (!(gr = getgrnam(AVAHI_GROUP))) { 1257 avahi_log_error( "Failed to find group '"AVAHI_GROUP"'."); 1258 goto fail; 1259 } 1260 1261 u = umask(0000); 1262 reset_umask = 1; 1263 1264 if (mkdir(AVAHI_DAEMON_RUNTIME_DIR, 0755) < 0 && errno != EEXIST) { 1265 avahi_log_error("mkdir(\""AVAHI_DAEMON_RUNTIME_DIR"\"): %s", strerror(errno)); 1266 goto fail; 1267 } 1268 1269 chown(AVAHI_DAEMON_RUNTIME_DIR, pw->pw_uid, gr->gr_gid); 1270 1271 if (stat(AVAHI_DAEMON_RUNTIME_DIR, &st) < 0) { 1272 avahi_log_error("stat(): %s\n", strerror(errno)); 1273 goto fail; 1274 } 1275 1276 if (!S_ISDIR(st.st_mode) || st.st_uid != pw->pw_uid || st.st_gid != gr->gr_gid) { 1277 avahi_log_error("Failed to create runtime directory "AVAHI_DAEMON_RUNTIME_DIR"."); 1278 goto fail; 1279 } 1280 1281 r = 0; 1282 1283fail: 1284 if (reset_umask) 1285 umask(u); 1286 return r; 1287#endif 1288 /* Foxconn modified end */ 1289} 1290 1291static void set_one_rlimit(int resource, rlim_t limit, const char *name) { 1292 struct rlimit rl; 1293 rl.rlim_cur = rl.rlim_max = limit; 1294 1295 if (setrlimit(resource, &rl) < 0) 1296 avahi_log_warn("setrlimit(%s, {%u, %u}) failed: %s", name, (unsigned) limit, (unsigned) limit, strerror(errno)); 1297} 1298 1299static void enforce_rlimits(void) { 1300#ifdef RLIMIT_AS 1301 if (config.rlimit_as_set) 1302 set_one_rlimit(RLIMIT_AS, config.rlimit_as, "RLIMIT_AS"); 1303#endif 1304 if (config.rlimit_core_set) 1305 set_one_rlimit(RLIMIT_CORE, config.rlimit_core, "RLIMIT_CORE"); 1306 if (config.rlimit_data_set) 1307 set_one_rlimit(RLIMIT_DATA, config.rlimit_data, "RLIMIT_DATA"); 1308 if (config.rlimit_fsize_set) 1309 set_one_rlimit(RLIMIT_FSIZE, config.rlimit_fsize, "RLIMIT_FSIZE"); 1310 if (config.rlimit_nofile_set) 1311 set_one_rlimit(RLIMIT_NOFILE, config.rlimit_nofile, "RLIMIT_NOFILE"); 1312 if (config.rlimit_stack_set) 1313 set_one_rlimit(RLIMIT_STACK, config.rlimit_stack, "RLIMIT_STACK"); 1314#ifdef RLIMIT_NPROC 1315 if (config.rlimit_nproc_set) 1316 set_one_rlimit(RLIMIT_NPROC, config.rlimit_nproc, "RLIMIT_NPROC"); 1317#endif 1318 1319 /* the sysctl() call from iface-pfroute.c needs locked memory on FreeBSD */ 1320#if defined(RLIMIT_MEMLOCK) && !defined(__FreeBSD__) 1321 /* We don't need locked memory */ 1322 set_one_rlimit(RLIMIT_MEMLOCK, 0, "RLIMIT_MEMLOCK"); 1323#endif 1324} 1325 1326#define RANDOM_DEVICE "/dev/urandom" 1327 1328static void init_rand_seed(void) { 1329 int fd; 1330 unsigned seed = 0; 1331 1332 /* Try to initialize seed from /dev/urandom, to make it a little 1333 * less predictable, and to make sure that multiple machines 1334 * booted at the same time choose different random seeds. */ 1335 if ((fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) { 1336 read(fd, &seed, sizeof(seed)); 1337 close(fd); 1338 } 1339 1340 /* If the initialization failed by some reason, we add the time to the seed*/ 1341 seed ^= (unsigned) time(NULL); 1342 1343 srand(seed); 1344} 1345 1346int main(int argc, char *argv[]) { 1347 int r = 255; 1348 int wrote_pid_file = 0; 1349 1350 avahi_set_log_function(log_function); 1351 1352 init_rand_seed(); 1353 1354 avahi_server_config_init(&config.server_config); 1355 config.command = DAEMON_RUN; 1356 config.daemonize = 0; 1357 config.config_file = NULL; 1358#ifdef HAVE_DBUS 1359 config.enable_dbus = 1; 1360 config.fail_on_missing_dbus = 1; 1361#endif 1362 1363 /*config.drop_root = 1;*/ 1364 config.drop_root = 0; /* foxconn modified */ 1365 config.set_rlimits = 1; 1366#ifdef ENABLE_CHROOT 1367 config.use_chroot = 1; 1368#endif 1369 config.modify_proc_title = 1; 1370 1371 config.disable_user_service_publishing = 0; 1372 config.publish_dns_servers = NULL; 1373 config.publish_resolv_conf = 0; 1374 config.use_syslog = 0; 1375 config.debug = 0; 1376 config.rlimit_as_set = 0; 1377 config.rlimit_core_set = 0; 1378 config.rlimit_data_set = 0; 1379 config.rlimit_fsize_set = 0; 1380 config.rlimit_nofile_set = 0; 1381 config.rlimit_stack_set = 0; 1382#ifdef RLIMIT_NPROC 1383 config.rlimit_nproc_set = 0; 1384#endif 1385 1386 if ((argv0 = strrchr(argv[0], '/'))) 1387 argv0 = avahi_strdup(argv0 + 1); 1388 else 1389 argv0 = avahi_strdup(argv[0]); 1390 1391 daemon_pid_file_ident = (const char *) argv0; 1392 daemon_log_ident = (char*) argv0; 1393 daemon_pid_file_proc = pid_file_proc; 1394 1395 if (parse_command_line(&config, argc, argv) < 0) 1396 goto finish; 1397 1398 if (config.modify_proc_title) 1399 avahi_init_proc_title(argc, argv); 1400 1401#ifdef ENABLE_CHROOT 1402 config.use_chroot = config.use_chroot && config.drop_root; 1403#endif 1404 1405 if (config.command == DAEMON_HELP) { 1406 help(stdout); 1407 r = 0; 1408 } else if (config.command == DAEMON_VERSION) { 1409 printf("%s "PACKAGE_VERSION"\n", argv0); 1410 r = 0; 1411 } else if (config.command == DAEMON_KILL) { 1412 if (daemon_pid_file_kill_wait(SIGTERM, 5) < 0) { 1413 avahi_log_warn("Failed to kill daemon: %s", strerror(errno)); 1414 goto finish; 1415 } 1416 1417 r = 0; 1418 1419 } else if (config.command == DAEMON_RELOAD) { 1420 if (daemon_pid_file_kill(SIGHUP) < 0) { 1421 avahi_log_warn("Failed to kill daemon: %s", strerror(errno)); 1422 goto finish; 1423 } 1424 1425 r = 0; 1426 1427 } else if (config.command == DAEMON_CHECK) 1428 r = (daemon_pid_file_is_running() >= 0) ? 0 : 1; 1429 else if (config.command == DAEMON_RUN) { 1430 pid_t pid; 1431 1432 if (getuid() != 0 && config.drop_root) { 1433 avahi_log_error("This program is intended to be run as root."); 1434 goto finish; 1435 } 1436 1437 if ((pid = daemon_pid_file_is_running()) >= 0) { 1438 avahi_log_error("Daemon already running on PID %u", pid); 1439 goto finish; 1440 } 1441 1442 if (load_config_file(&config) < 0) 1443 goto finish; 1444 1445 if (config.daemonize) { 1446 daemon_retval_init(); 1447 1448 if ((pid = daemon_fork()) < 0) 1449 goto finish; 1450 else if (pid != 0) { 1451 int ret; 1452 /** Parent **/ 1453 1454 if ((ret = daemon_retval_wait(20)) < 0) { 1455 avahi_log_error("Could not receive return value from daemon process."); 1456 goto finish; 1457 } 1458 1459 r = ret; 1460 goto finish; 1461 } 1462 1463 /* Child */ 1464 } 1465 /* foxconn removed 1466 if (config.use_syslog || config.daemonize) 1467 daemon_log_use = DAEMON_LOG_SYSLOG; 1468 */ 1469 if (daemon_close_all(-1) < 0) { 1470 avahi_log_error("Failed to close remaining file descriptors: %s", strerror(errno)); 1471 goto finish; 1472 } 1473 1474 if (make_runtime_dir() < 0) 1475 goto finish; 1476 1477 if (config.drop_root) { 1478#ifdef ENABLE_CHROOT 1479 if (config.use_chroot) 1480 if (avahi_caps_reduce() < 0) 1481 goto finish; 1482#endif 1483 1484 if (drop_root() < 0) 1485 goto finish; 1486 1487#ifdef ENABLE_CHROOT 1488 if (config.use_chroot) 1489 if (avahi_caps_reduce2() < 0) 1490 goto finish; 1491#endif 1492 } 1493 1494 if (daemon_pid_file_create() < 0) { 1495 avahi_log_error("Failed to create PID file: %s", strerror(errno)); 1496 1497 if (config.daemonize) 1498 daemon_retval_send(1); 1499 goto finish; 1500 } else 1501 wrote_pid_file = 1; 1502 1503 if (config.set_rlimits) 1504 enforce_rlimits(); 1505 1506 chdir("/"); 1507 1508#ifdef ENABLE_CHROOT 1509 if (config.drop_root && config.use_chroot) 1510 if (avahi_chroot_helper_start(argv0) < 0) { 1511 avahi_log_error("failed to start chroot() helper daemon."); 1512 goto finish; 1513 } 1514#endif 1515 avahi_log_info("%s "PACKAGE_VERSION" starting up.", argv0); 1516 1517 avahi_set_proc_title(argv0, "%s: starting up", argv0); 1518 1519 if (run_server(&config) == 0) 1520 r = 0; 1521 } 1522 1523finish: 1524 1525 if (config.daemonize) 1526 daemon_retval_done(); 1527 1528 avahi_server_config_free(&config.server_config); 1529 avahi_free(config.config_file); 1530 avahi_strfreev(config.publish_dns_servers); 1531 avahi_strfreev(resolv_conf_name_servers); 1532 avahi_strfreev(resolv_conf_search_domains); 1533 1534 if (wrote_pid_file) { 1535#ifdef ENABLE_CHROOT 1536 avahi_chroot_helper_unlink(pid_file_proc()); 1537#else 1538 daemon_pid_file_remove(); 1539#endif 1540 } 1541 1542#ifdef ENABLE_CHROOT 1543 avahi_chroot_helper_shutdown(); 1544#endif 1545 1546 avahi_free(argv0); 1547 1548 return r; 1549} 1550