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