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 <string.h> 27#include <errno.h> 28#include <stdio.h> 29 30#include <avahi-common/llist.h> 31#include <avahi-common/malloc.h> 32#include <avahi-common/error.h> 33#include <avahi-core/log.h> 34#include <avahi-core/publish.h> 35 36#include "main.h" 37#include "static-hosts.h" 38 39typedef struct StaticHost StaticHost; 40 41struct StaticHost { 42 AvahiSEntryGroup *group; 43 int iteration; 44 45 char *host; 46 AvahiAddress address; 47 48 AVAHI_LLIST_FIELDS(StaticHost, hosts); 49}; 50 51static AVAHI_LLIST_HEAD(StaticHost, hosts) = NULL; 52static int current_iteration = 0; 53 54static void add_static_host_to_server(StaticHost *h); 55static void remove_static_host_from_server(StaticHost *h); 56 57static void entry_group_callback(AvahiServer *s, AVAHI_GCC_UNUSED AvahiSEntryGroup *eg, AvahiEntryGroupState state, void* userdata) { 58 StaticHost *h; 59 60 assert(s); 61 assert(eg); 62 63 h = userdata; 64 65 switch (state) { 66 67 case AVAHI_ENTRY_GROUP_COLLISION: 68 avahi_log_error("Host name conflict for \"%s\", not established.", h->host); 69 break; 70 71 case AVAHI_ENTRY_GROUP_ESTABLISHED: 72 avahi_log_notice ("Static host name \"%s\" successfully established.", h->host); 73 break; 74 75 case AVAHI_ENTRY_GROUP_FAILURE: 76 avahi_log_notice ("Failed to establish static host name \"%s\": %s.", h->host, avahi_strerror (avahi_server_errno (s))); 77 break; 78 79 case AVAHI_ENTRY_GROUP_UNCOMMITED: 80 case AVAHI_ENTRY_GROUP_REGISTERING: 81 ; 82 } 83} 84 85static StaticHost *static_host_new(void) { 86 StaticHost *s; 87 88 s = avahi_new(StaticHost, 1); 89 90 s->group = NULL; 91 s->host = NULL; 92 s->iteration = current_iteration; 93 94 AVAHI_LLIST_PREPEND(StaticHost, hosts, hosts, s); 95 96 return s; 97} 98 99static void static_host_free(StaticHost *s) { 100 assert(s); 101 102 AVAHI_LLIST_REMOVE(StaticHost, hosts, hosts, s); 103 104 if (s->group) 105 avahi_s_entry_group_free (s->group); 106 107 avahi_free(s->host); 108 109 avahi_free(s); 110} 111 112static StaticHost *static_host_find(const char *host, const AvahiAddress *a) { 113 StaticHost *h; 114 115 assert(host); 116 assert(a); 117 118 for (h = hosts; h; h = h->hosts_next) 119 if (!strcmp(h->host, host) && !avahi_address_cmp(a, &h->address)) 120 return h; 121 122 return NULL; 123} 124 125static void add_static_host_to_server(StaticHost *h) 126{ 127 128 if (!h->group) 129 if (!(h->group = avahi_s_entry_group_new (avahi_server, entry_group_callback, h))) { 130 avahi_log_error("avahi_s_entry_group_new() failed: %s", avahi_strerror(avahi_server_errno(avahi_server))); 131 return; 132 } 133 134 if (avahi_s_entry_group_is_empty(h->group)) { 135 AvahiProtocol p; 136 int err; 137 const AvahiServerConfig *config; 138 config = avahi_server_get_config(avahi_server); 139 140 p = (h->address.proto == AVAHI_PROTO_INET && config->publish_a_on_ipv6) || 141 (h->address.proto == AVAHI_PROTO_INET6 && config->publish_aaaa_on_ipv4) ? AVAHI_PROTO_UNSPEC : h->address.proto; 142 143 if ((err = avahi_server_add_address(avahi_server, h->group, AVAHI_IF_UNSPEC, p, 0, h->host, &h->address)) < 0) { 144 avahi_log_error ("Static host name %s: avahi_server_add_address failure: %s", h->host, avahi_strerror(err)); 145 return; 146 } 147 148 avahi_s_entry_group_commit (h->group); 149 } 150} 151 152static void remove_static_host_from_server(StaticHost *h) 153{ 154 if (h->group) 155 avahi_s_entry_group_reset (h->group); 156} 157 158void static_hosts_add_to_server(void) { 159 StaticHost *h; 160 161 for (h = hosts; h; h = h->hosts_next) 162 add_static_host_to_server(h); 163} 164 165void static_hosts_remove_from_server(void) { 166 StaticHost *h; 167 168 for (h = hosts; h; h = h->hosts_next) 169 remove_static_host_from_server(h); 170} 171 172void static_hosts_load(int in_chroot) { 173 FILE *f; 174 unsigned int line = 0; 175 StaticHost *h, *next; 176 const char *filename = in_chroot ? "/hosts" : AVAHI_CONFIG_DIR "/hosts"; 177 178 if (!(f = fopen(filename, "r"))) { 179 if (errno != ENOENT) 180 avahi_log_error ("Failed to open static hosts file: %s", strerror (errno)); 181 return; 182 } 183 184 current_iteration++; 185 186 while (!feof(f)) { 187 unsigned int len; 188 char ln[256], *s; 189 char *host, *ip; 190 AvahiAddress a; 191 192 if (!fgets(ln, sizeof (ln), f)) 193 break; 194 195 line++; 196 197 /* Find the start of the line, ignore whitespace */ 198 s = ln + strspn(ln, " \t"); 199 /* Set the end of the string to NULL */ 200 s[strcspn(s, "#\r\n")] = 0; 201 202 /* Ignore blank lines */ 203 if (*s == 0) 204 continue; 205 206 /* Read the first string (ip) up to the next whitespace */ 207 len = strcspn(s, " \t"); 208 ip = avahi_strndup(s, len); 209 210 /* Skip past it */ 211 s += len; 212 213 /* Find the next token */ 214 s += strspn(s, " \t"); 215 len = strcspn(s, " \t"); 216 host = avahi_strndup(s, len); 217 218 if (*host == 0) 219 { 220 avahi_log_error("%s:%d: Error, unexpected end of line!", filename, line); 221 avahi_free(host); 222 avahi_free(ip); 223 goto fail; 224 } 225 226 /* Skip over the host */ 227 s += len; 228 229 /* Skip past any more spaces */ 230 s += strspn(s, " \t"); 231 232 /* Anything left? */ 233 if (*s != 0) { 234 avahi_log_error ("%s:%d: Junk on the end of the line!", filename, line); 235 avahi_free(host); 236 avahi_free(ip); 237 goto fail; 238 } 239 240 if (!avahi_address_parse(ip, AVAHI_PROTO_UNSPEC, &a)) { 241 avahi_log_error("Static host name %s: failed to parse address %s", host, ip); 242 avahi_free(host); 243 avahi_free(ip); 244 goto fail; 245 } 246 247 avahi_free(ip); 248 249 if ((h = static_host_find(host, &a))) 250 avahi_free(host); 251 else { 252 h = static_host_new(); 253 h->host = host; 254 h->address = a; 255 256 avahi_log_info("Loading new static hostname %s.", h->host); 257 } 258 259 h->iteration = current_iteration; 260 } 261 262 for (h = hosts; h; h = next) { 263 next = h->hosts_next; 264 265 if (h->iteration != current_iteration) { 266 avahi_log_info("Static hostname %s vanished, removing.", h->host); 267 static_host_free(h); 268 } 269 } 270 271fail: 272 273 fclose(f); 274} 275 276void static_hosts_free_all (void) 277{ 278 while(hosts) 279 static_host_free(hosts); 280} 281