1 /**
2 * collectd - src/unixsock.c
3 * Copyright (C) 2007 Florian octo Forster
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; only version 2 of the License is applicable.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 * Author:
19 * Florian octo Forster <octo at verplant.org>
20 **/
22 #include "collectd.h"
23 #include "common.h"
24 #include "plugin.h"
25 #include "configfile.h"
27 /* Folks without pthread will need to disable this plugin. */
28 #include <pthread.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
33 #include <grp.h>
35 #ifndef UNIX_PATH_MAX
36 # define UNIX_PATH_MAX sizeof (((struct sockaddr_un *)0)->sun_path)
37 #endif
39 #define US_DEFAULT_PATH PREFIX"/var/run/"PACKAGE_NAME"-unixsock"
41 /*
42 * Private data structures
43 */
44 /* linked list of cached values */
45 typedef struct value_cache_s
46 {
47 char name[4*DATA_MAX_NAME_LEN];
48 int values_num;
49 gauge_t *gauge;
50 counter_t *counter;
51 const data_set_t *ds;
52 time_t time;
53 struct value_cache_s *next;
54 } value_cache_t;
56 /*
57 * Private variables
58 */
59 /* valid configuration file keys */
60 static const char *config_keys[] =
61 {
62 "SocketFile",
63 "SocketGroup",
64 "SocketPerms",
65 NULL
66 };
67 static int config_keys_num = 3;
69 static int loop = 0;
71 /* socket configuration */
72 static int sock_fd = -1;
73 static char *sock_file = NULL;
74 static char *sock_group = NULL;
75 static int sock_perms = S_IRWXU | S_IRWXG;
77 static pthread_t listen_thread = (pthread_t) 0;
79 /* Linked list and auxilliary variables for saving values */
80 static value_cache_t *cache_head = NULL;
81 static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
82 static unsigned int cache_oldest = UINT_MAX;
84 /*
85 * Functions
86 */
87 static int parse_identifier (char *str, char **ret_host,
88 char **ret_plugin, char **ret_plugin_instance,
89 char **ret_type, char **ret_type_instance)
90 {
91 char *hostname = NULL;
92 char *plugin = NULL;
93 char *plugin_instance = NULL;
94 char *type = NULL;
95 char *type_instance = NULL;
97 hostname = str;
98 if (hostname == NULL)
99 return (-1);
101 plugin = strchr (hostname, '/');
102 if (plugin == NULL)
103 return (-1);
104 *plugin = '\0'; plugin++;
106 type = strchr (plugin, '/');
107 if (type == NULL)
108 return (-1);
109 *type = '\0'; type++;
111 plugin_instance = strchr (plugin, '-');
112 if (plugin_instance != NULL)
113 {
114 *plugin_instance = '\0';
115 plugin_instance++;
116 }
118 type_instance = strchr (type, '-');
119 if (type_instance != NULL)
120 {
121 *type_instance = '\0';
122 type_instance++;
123 }
125 *ret_host = hostname;
126 *ret_plugin = plugin;
127 *ret_plugin_instance = plugin_instance;
128 *ret_type = type;
129 *ret_type_instance = type_instance;
130 return (0);
131 } /* int parse_identifier */
133 static value_cache_t *cache_search (const char *name)
134 {
135 value_cache_t *vc;
137 for (vc = cache_head; vc != NULL; vc = vc->next)
138 {
139 if (strcmp (vc->name, name) == 0)
140 break;
141 } /* for vc = cache_head .. NULL */
143 return (vc);
144 } /* value_cache_t *cache_search */
146 static int cache_insert (const data_set_t *ds, const value_list_t *vl)
147 {
148 /* We're called from `cache_update' so we don't need to lock the mutex */
149 value_cache_t *vc;
150 int i;
152 DEBUG ("unixsock plugin: cache_insert: ds->type = %s; ds->ds_num = %i;"
153 " vl->values_len = %i;",
154 ds->type, ds->ds_num, vl->values_len);
155 #if COLLECT_DEBUG
156 assert (ds->ds_num == vl->values_len);
157 #else
158 if (ds->ds_num != vl->values_len)
159 {
160 ERROR ("unixsock plugin: ds->type = %s: (ds->ds_num = %i) != "
161 "(vl->values_len = %i)",
162 ds->type, ds->ds_num, vl->values_len);
163 return (-1);
164 }
165 #endif
167 vc = (value_cache_t *) malloc (sizeof (value_cache_t));
168 if (vc == NULL)
169 {
170 char errbuf[1024];
171 pthread_mutex_unlock (&cache_lock);
172 ERROR ("unixsock plugin: malloc failed: %s",
173 sstrerror (errno, errbuf, sizeof (errbuf)));
174 return (-1);
175 }
177 vc->gauge = (gauge_t *) malloc (sizeof (gauge_t) * vl->values_len);
178 if (vc->gauge == NULL)
179 {
180 char errbuf[1024];
181 pthread_mutex_unlock (&cache_lock);
182 ERROR ("unixsock plugin: malloc failed: %s",
183 sstrerror (errno, errbuf, sizeof (errbuf)));
184 free (vc);
185 return (-1);
186 }
188 vc->counter = (counter_t *) malloc (sizeof (counter_t) * vl->values_len);
189 if (vc->counter == NULL)
190 {
191 char errbuf[1024];
192 pthread_mutex_unlock (&cache_lock);
193 ERROR ("unixsock plugin: malloc failed: %s",
194 sstrerror (errno, errbuf, sizeof (errbuf)));
195 free (vc->gauge);
196 free (vc);
197 return (-1);
198 }
200 if (FORMAT_VL (vc->name, sizeof (vc->name), vl, ds))
201 {
202 pthread_mutex_unlock (&cache_lock);
203 ERROR ("unixsock plugin: FORMAT_VL failed.");
204 free (vc->counter);
205 free (vc->gauge);
206 free (vc);
207 return (-1);
208 }
210 for (i = 0; i < ds->ds_num; i++)
211 {
212 if (ds->ds[i].type == DS_TYPE_COUNTER)
213 {
214 vc->gauge[i] = 0.0;
215 vc->counter[i] = vl->values[i].counter;
216 }
217 else if (ds->ds[i].type == DS_TYPE_GAUGE)
218 {
219 vc->gauge[i] = vl->values[i].gauge;
220 vc->counter[i] = 0;
221 }
222 else
223 {
224 vc->gauge[i] = 0.0;
225 vc->counter[i] = 0;
226 }
227 }
228 vc->values_num = ds->ds_num;
229 vc->ds = ds;
231 vc->next = cache_head;
232 cache_head = vc;
234 vc->time = vl->time;
235 if (vc->time < cache_oldest)
236 cache_oldest = vc->time;
238 pthread_mutex_unlock (&cache_lock);
239 return (0);
240 } /* int cache_insert */
242 static int cache_update (const data_set_t *ds, const value_list_t *vl)
243 {
244 char name[4*DATA_MAX_NAME_LEN];;
245 value_cache_t *vc;
246 int i;
248 if (FORMAT_VL (name, sizeof (name), vl, ds) != 0)
249 return (-1);
251 pthread_mutex_lock (&cache_lock);
253 vc = cache_search (name);
255 /* pthread_mutex_lock is called by cache_insert. */
256 if (vc == NULL)
257 return (cache_insert (ds, vl));
259 assert (vc->values_num == ds->ds_num);
260 assert (vc->values_num == vl->values_len);
262 /* Avoid floating-point exceptions due to division by zero. */
263 if (vc->time >= vl->time)
264 {
265 pthread_mutex_unlock (&cache_lock);
266 ERROR ("unixsock plugin: vc->time >= vl->time. vc->time = %u; "
267 "vl->time = %u; vl = %s;",
268 (unsigned int) vc->time, (unsigned int) vl->time,
269 name);
270 return (-1);
271 } /* if (vc->time >= vl->time) */
273 /*
274 * Update the values. This is possibly a lot more that you'd expect
275 * because we honor min and max values and handle counter overflows here.
276 */
277 for (i = 0; i < ds->ds_num; i++)
278 {
279 if (ds->ds[i].type == DS_TYPE_COUNTER)
280 {
281 if (vl->values[i].counter < vc->counter[i])
282 {
283 if (vl->values[i].counter <= 4294967295U)
284 {
285 vc->gauge[i] = ((4294967295U - vl->values[i].counter)
286 + vc->counter[i]) / (vl->time - vc->time);
287 }
288 else
289 {
290 vc->gauge[i] = ((18446744073709551615ULL - vl->values[i].counter)
291 + vc->counter[i]) / (vl->time - vc->time);
292 }
293 }
294 else
295 {
296 vc->gauge[i] = (vl->values[i].counter - vc->counter[i])
297 / (vl->time - vc->time);
298 }
300 vc->counter[i] = vl->values[i].counter;
301 }
302 else if (ds->ds[i].type == DS_TYPE_GAUGE)
303 {
304 vc->gauge[i] = vl->values[i].gauge;
305 vc->counter[i] = 0;
306 }
307 else
308 {
309 vc->gauge[i] = NAN;
310 vc->counter[i] = 0;
311 }
313 if (isnan (vc->gauge[i])
314 || (!isnan (ds->ds[i].min) && (vc->gauge[i] < ds->ds[i].min))
315 || (!isnan (ds->ds[i].max) && (vc->gauge[i] > ds->ds[i].max)))
316 vc->gauge[i] = NAN;
317 } /* for i = 0 .. ds->ds_num */
319 vc->ds = ds;
320 vc->time = vl->time;
322 if (vc->time < cache_oldest)
323 cache_oldest = vc->time;
325 pthread_mutex_unlock (&cache_lock);
326 return (0);
327 } /* int cache_update */
329 static void cache_flush (int max_age)
330 {
331 value_cache_t *this;
332 value_cache_t *prev;
333 time_t now;
335 pthread_mutex_lock (&cache_lock);
337 now = time (NULL);
339 if ((now - cache_oldest) <= max_age)
340 {
341 pthread_mutex_unlock (&cache_lock);
342 return;
343 }
345 cache_oldest = now;
347 prev = NULL;
348 this = cache_head;
350 while (this != NULL)
351 {
352 if ((now - this->time) <= max_age)
353 {
354 if (this->time < cache_oldest)
355 cache_oldest = this->time;
357 prev = this;
358 this = this->next;
359 continue;
360 }
362 if (prev == NULL)
363 cache_head = this->next;
364 else
365 prev->next = this->next;
367 free (this->gauge);
368 free (this->counter);
369 free (this);
371 if (prev == NULL)
372 this = cache_head;
373 else
374 this = prev->next;
375 } /* while (this != NULL) */
377 pthread_mutex_unlock (&cache_lock);
378 } /* int cache_flush */
380 static int us_open_socket (void)
381 {
382 struct sockaddr_un sa;
383 int status;
385 sock_fd = socket (PF_UNIX, SOCK_STREAM, 0);
386 if (sock_fd < 0)
387 {
388 char errbuf[1024];
389 ERROR ("unixsock plugin: socket failed: %s",
390 sstrerror (errno, errbuf, sizeof (errbuf)));
391 return (-1);
392 }
394 memset (&sa, '\0', sizeof (sa));
395 sa.sun_family = AF_UNIX;
396 strncpy (sa.sun_path, (sock_file != NULL) ? sock_file : US_DEFAULT_PATH,
397 sizeof (sa.sun_path) - 1);
398 /* unlink (sa.sun_path); */
400 status = bind (sock_fd, (struct sockaddr *) &sa, sizeof (sa));
401 if (status != 0)
402 {
403 char errbuf[1024];
404 sstrerror (errno, errbuf, sizeof (errbuf));
405 DEBUG ("bind failed: %s; sa.sun_path = %s", errbuf, sa.sun_path);
406 ERROR ("unixsock plugin: bind failed: %s", errbuf);
407 close (sock_fd);
408 sock_fd = -1;
409 return (-1);
410 }
412 status = listen (sock_fd, 8);
413 if (status != 0)
414 {
415 char errbuf[1024];
416 ERROR ("unixsock plugin: listen failed: %s",
417 sstrerror (errno, errbuf, sizeof (errbuf)));
418 close (sock_fd);
419 sock_fd = -1;
420 return (-1);
421 }
423 do
424 {
425 char *grpname;
426 struct group *g;
427 struct group sg;
428 char grbuf[2048];
430 grpname = (sock_group != NULL) ? sock_group : COLLECTD_GRP_NAME;
431 g = NULL;
433 status = getgrnam_r (grpname, &sg, grbuf, sizeof (grbuf), &g);
434 if (status != 0)
435 {
436 char errbuf[1024];
437 WARNING ("unixsock plugin: getgrnam_r (%s) failed: %s", grpname,
438 sstrerror (errno, errbuf, sizeof (errbuf)));
439 break;
440 }
441 if (g == NULL)
442 {
443 WARNING ("unixsock plugin: No such group: `%s'",
444 grpname);
445 break;
446 }
448 if (chown ((sock_file != NULL) ? sock_file : US_DEFAULT_PATH,
449 (uid_t) -1, g->gr_gid) != 0)
450 {
451 char errbuf[1024];
452 WARNING ("unixsock plugin: chown (%s, -1, %i) failed: %s",
453 (sock_file != NULL) ? sock_file : US_DEFAULT_PATH,
454 (int) g->gr_gid,
455 sstrerror (errno, errbuf, sizeof (errbuf)));
456 }
457 } while (0);
459 return (0);
460 } /* int us_open_socket */
462 static int us_handle_getval (FILE *fh, char **fields, int fields_num)
463 {
464 char *hostname;
465 char *plugin;
466 char *plugin_instance;
467 char *type;
468 char *type_instance;
469 char name[4*DATA_MAX_NAME_LEN];
470 value_cache_t *vc;
471 int status;
472 int i;
474 if (fields_num != 2)
475 {
476 DEBUG ("unixsock plugin: Wrong number of fields: %i", fields_num);
477 fprintf (fh, "-1 Wrong number of fields: Got %i, expected 2.\n",
478 fields_num);
479 fflush (fh);
480 return (-1);
481 }
482 DEBUG ("unixsock plugin: Got query for `%s'", fields[1]);
484 status = parse_identifier (fields[1], &hostname,
485 &plugin, &plugin_instance,
486 &type, &type_instance);
487 if (status != 0)
488 {
489 DEBUG ("unixsock plugin: Cannot parse `%s'", fields[1]);
490 fprintf (fh, "-1 Cannot parse identifier.\n");
491 fflush (fh);
492 return (-1);
493 }
495 status = format_name (name, sizeof (name),
496 hostname, plugin, plugin_instance, type, type_instance);
497 /* FIXME: Send some response */
498 if (status != 0)
499 return (-1);
501 pthread_mutex_lock (&cache_lock);
503 DEBUG ("vc = cache_search (%s)", name);
504 vc = cache_search (name);
506 if (vc == NULL)
507 {
508 DEBUG ("Did not find cache entry.");
509 fprintf (fh, "-1 No such value");
510 }
511 else
512 {
513 DEBUG ("Found cache entry.");
514 fprintf (fh, "%i", vc->values_num);
515 for (i = 0; i < vc->values_num; i++)
516 {
517 fprintf (fh, " %s=", vc->ds->ds[i].name);
518 if (isnan (vc->gauge[i]))
519 fprintf (fh, "NaN");
520 else
521 fprintf (fh, "%12e", vc->gauge[i]);
522 }
523 }
525 /* Free the mutex as soon as possible and definitely before flushing */
526 pthread_mutex_unlock (&cache_lock);
528 fprintf (fh, "\n");
529 fflush (fh);
531 return (0);
532 } /* int us_handle_getval */
534 static int us_handle_putval (FILE *fh, char **fields, int fields_num)
535 {
536 char *hostname;
537 char *plugin;
538 char *plugin_instance;
539 char *type;
540 char *type_instance;
541 int status;
542 int i;
544 const data_set_t *ds;
545 value_list_t vl = VALUE_LIST_INIT;
547 char **value_ptr;
549 if (fields_num != 3)
550 {
551 DEBUG ("unixsock plugin: Wrong number of fields: %i", fields_num);
552 fprintf (fh, "-1 Wrong number of fields: Got %i, expected 3.\n",
553 fields_num);
554 fflush (fh);
555 return (-1);
556 }
558 status = parse_identifier (fields[1], &hostname,
559 &plugin, &plugin_instance,
560 &type, &type_instance);
561 if (status != 0)
562 {
563 DEBUG ("unixsock plugin: Cannot parse `%s'", fields[1]);
564 fprintf (fh, "-1 Cannot parse identifier.\n");
565 fflush (fh);
566 return (-1);
567 }
569 /* FIXME: Send some response */
570 if ((strlen (hostname) > sizeof (vl.host))
571 || (strlen (plugin) > sizeof (vl.plugin))
572 || ((plugin_instance != NULL)
573 && (strlen (plugin_instance) > sizeof (vl.plugin_instance)))
574 || ((type_instance != NULL)
575 && (strlen (type_instance) > sizeof (vl.type_instance))))
576 return (-1);
578 strcpy (vl.host, hostname);
579 strcpy (vl.plugin, plugin);
580 if (plugin_instance != NULL)
581 strcpy (vl.plugin_instance, plugin_instance);
582 if (type_instance != NULL)
583 strcpy (vl.type_instance, type_instance);
585 { /* parse the time */
586 char *t = fields[2];
587 char *v = strchr (t, ':');
588 if (v == NULL)
589 return (-1);
590 *v = '\0'; v++;
592 vl.time = (time_t) atoi (t);
593 if (vl.time == 0)
594 vl.time = time (NULL);
596 fields[2] = v;
597 }
599 ds = plugin_get_ds (type);
600 if (ds == NULL)
601 return (-1);
603 value_ptr = (char **) calloc (ds->ds_num, sizeof (char *));
604 /* FIXME: Send some response */
605 if (value_ptr == NULL)
606 return (-1);
609 { /* parse the value-list. It's colon-separated. */
610 char *dummy;
611 char *ptr;
612 char *saveptr;
614 i = 0;
615 dummy = fields[2];
616 saveptr = NULL;
617 while ((ptr = strtok_r (dummy, ":", &saveptr)) != NULL)
618 {
619 dummy = NULL;
620 if (i >= ds->ds_num)
621 {
622 i = ds->ds_num + 1;
623 break;
624 }
625 value_ptr[i] = ptr;
626 i++;
627 }
629 if (i != ds->ds_num)
630 {
631 sfree (value_ptr);
632 /* FIXME: Send some response */
633 return (-1);
634 }
635 } /* done parsing the value-list */
637 vl.values_len = ds->ds_num;
638 vl.values = (value_t *) malloc (vl.values_len * sizeof (value_t));
639 if (vl.values == NULL)
640 {
641 sfree (value_ptr);
642 return (-1);
643 }
644 DEBUG ("value_ptr = 0x%p; vl.values = 0x%p;", (void *) value_ptr, (void *) vl.values);
646 for (i = 0; i < ds->ds_num; i++)
647 {
648 if (strcmp (value_ptr[i], "U") == 0)
649 vl.values[i].gauge = NAN;
650 else if (ds->ds[i].type == DS_TYPE_COUNTER)
651 vl.values[i].counter = atoll (value_ptr[i]);
652 else if (ds->ds[i].type == DS_TYPE_GAUGE)
653 vl.values[i].gauge = atof (value_ptr[i]);
654 } /* for (i = 2 .. fields_num) */
656 plugin_dispatch_values (type, &vl);
658 DEBUG ("value_ptr = 0x%p; vl.values = 0x%p;", (void *) value_ptr, (void *) vl.values);
660 sfree (value_ptr);
661 sfree (vl.values);
663 fprintf (fh, "0 Success\n");
664 fflush (fh);
666 return (0);
667 } /* int us_handle_putval */
669 static void *us_handle_client (void *arg)
670 {
671 int fd;
672 FILE *fh;
673 char buffer[1024];
674 char *fields[128];
675 int fields_num;
677 fd = *((int *) arg);
678 free (arg);
679 arg = NULL;
681 DEBUG ("Reading from fd #%i", fd);
683 fh = fdopen (fd, "r+");
684 if (fh == NULL)
685 {
686 char errbuf[1024];
687 ERROR ("unixsock plugin: fdopen failed: %s",
688 sstrerror (errno, errbuf, sizeof (errbuf)));
689 close (fd);
690 pthread_exit ((void *) 1);
691 }
693 while (fgets (buffer, sizeof (buffer), fh) != NULL)
694 {
695 int len;
697 len = strlen (buffer);
698 while ((len > 0)
699 && ((buffer[len - 1] == '\n') || (buffer[len - 1] == '\r')))
700 buffer[--len] = '\0';
702 if (len == 0)
703 continue;
705 DEBUG ("fgets -> buffer = %s; len = %i;", buffer, len);
707 fields_num = strsplit (buffer, fields,
708 sizeof (fields) / sizeof (fields[0]));
710 if (fields_num < 1)
711 {
712 close (fd);
713 break;
714 }
716 if (strcasecmp (fields[0], "getval") == 0)
717 {
718 us_handle_getval (fh, fields, fields_num);
719 }
720 else if (strcasecmp (fields[0], "putval") == 0)
721 {
722 us_handle_putval (fh, fields, fields_num);
723 }
724 else
725 {
726 fprintf (fh, "Unknown command: %s\n", fields[0]);
727 fflush (fh);
728 }
729 } /* while (fgets) */
731 DEBUG ("Exiting..");
732 close (fd);
734 pthread_exit ((void *) 0);
735 } /* void *us_handle_client */
737 static void *us_server_thread (void *arg)
738 {
739 int status;
740 int *remote_fd;
741 pthread_t th;
742 pthread_attr_t th_attr;
744 if (us_open_socket () != 0)
745 pthread_exit ((void *) 1);
747 while (loop != 0)
748 {
749 DEBUG ("Calling accept..");
750 status = accept (sock_fd, NULL, NULL);
751 if (status < 0)
752 {
753 char errbuf[1024];
755 if (errno == EINTR)
756 continue;
758 ERROR ("unixsock plugin: accept failed: %s",
759 sstrerror (errno, errbuf, sizeof (errbuf)));
760 close (sock_fd);
761 sock_fd = -1;
762 pthread_exit ((void *) 1);
763 }
765 remote_fd = (int *) malloc (sizeof (int));
766 if (remote_fd == NULL)
767 {
768 char errbuf[1024];
769 WARNING ("unixsock plugin: malloc failed: %s",
770 sstrerror (errno, errbuf, sizeof (errbuf)));
771 close (status);
772 continue;
773 }
774 *remote_fd = status;
776 DEBUG ("Spawning child to handle connection on fd #%i", *remote_fd);
778 pthread_attr_init (&th_attr);
779 pthread_attr_setdetachstate (&th_attr, PTHREAD_CREATE_DETACHED);
781 status = pthread_create (&th, &th_attr, us_handle_client, (void *) remote_fd);
782 if (status != 0)
783 {
784 char errbuf[1024];
785 WARNING ("unixsock plugin: pthread_create failed: %s",
786 sstrerror (errno, errbuf, sizeof (errbuf)));
787 close (*remote_fd);
788 free (remote_fd);
789 continue;
790 }
791 } /* while (loop) */
793 close (sock_fd);
794 sock_fd = -1;
796 status = unlink ((sock_file != NULL) ? sock_file : US_DEFAULT_PATH);
797 if (status != 0)
798 {
799 char errbuf[1024];
800 NOTICE ("unixsock plugin: unlink (%s) failed: %s",
801 (sock_file != NULL) ? sock_file : US_DEFAULT_PATH,
802 sstrerror (errno, errbuf, sizeof (errbuf)));
803 }
805 return ((void *) 0);
806 } /* void *us_server_thread */
808 static int us_config (const char *key, const char *val)
809 {
810 if (strcasecmp (key, "SocketFile") == 0)
811 {
812 sfree (sock_file);
813 sock_file = strdup (val);
814 }
815 else if (strcasecmp (key, "SocketGroup") == 0)
816 {
817 sfree (sock_group);
818 sock_group = strdup (val);
819 }
820 else if (strcasecmp (key, "SocketPerms") == 0)
821 {
822 sock_perms = (int) strtol (val, NULL, 8);
823 }
824 else
825 {
826 return (-1);
827 }
829 return (0);
830 } /* int us_config */
832 static int us_init (void)
833 {
834 int status;
836 loop = 1;
838 status = pthread_create (&listen_thread, NULL, us_server_thread, NULL);
839 if (status != 0)
840 {
841 char errbuf[1024];
842 ERROR ("unixsock plugin: pthread_create failed: %s",
843 sstrerror (errno, errbuf, sizeof (errbuf)));
844 return (-1);
845 }
847 return (0);
848 } /* int us_init */
850 static int us_shutdown (void)
851 {
852 void *ret;
854 loop = 0;
856 if (listen_thread != (pthread_t) 0)
857 {
858 pthread_kill (listen_thread, SIGTERM);
859 pthread_join (listen_thread, &ret);
860 listen_thread = (pthread_t) 0;
861 }
863 plugin_unregister_init ("unixsock");
864 plugin_unregister_write ("unixsock");
865 plugin_unregister_shutdown ("unixsock");
867 return (0);
868 } /* int us_shutdown */
870 static int us_write (const data_set_t *ds, const value_list_t *vl)
871 {
872 cache_update (ds, vl);
873 cache_flush (2 * interval_g);
875 return (0);
876 }
878 void module_register (void)
879 {
880 plugin_register_config ("unixsock", us_config,
881 config_keys, config_keys_num);
882 plugin_register_init ("unixsock", us_init);
883 plugin_register_write ("unixsock", us_write);
884 plugin_register_shutdown ("unixsock", us_shutdown);
885 } /* void module_register (void) */
887 /* vim: set sw=4 ts=4 sts=4 tw=78 : */