1 /* GKrellM 2 | Copyright (C) 1999-2019 Bill Wilson 3 | 4 | Author: Bill Wilson billw@gkrellm.net 5 | Latest versions might be found at: http://gkrellm.net 6 | 7 | 8 | GKrellM is free software: you can redistribute it and/or modify it 9 | under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | GKrellM is distributed in the hope that it will be useful, but WITHOUT 14 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 16 | License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see http://www.gnu.org/licenses/ 20 | 21 | 22 | Additional permission under GNU GPL version 3 section 7 23 | 24 | If you modify this program, or any covered work, by linking or 25 | combining it with the OpenSSL project's OpenSSL library (or a 26 | modified version of that library), containing parts covered by 27 | the terms of the OpenSSL or SSLeay licenses, you are granted 28 | additional permission to convey the resulting work. 29 | Corresponding Source for a non-source form of such a combination 30 | shall include the source code for the parts of OpenSSL used as well 31 | as that of the covered work. 32 */ 33 34 #include "gkrellmd.h" 35 #include "gkrellmd-private.h" 36 #include <inttypes.h> 37 38 GList *gkrellmd_monitor_list; 39 40 static GList *serveflag_done_list; 41 42 static struct tm gkrellmd_current_tm; 43 44 gint 45 gkrellm_get_timer_ticks(void) 46 { pmx(PlannerInfo * root,Gene * tour1,Gene * tour2,Gene * offspring,int num_gene)47 return GK.timer_ticks; 48 } 49 50 gboolean 51 gkrellmd_check_client_version(GkrellmdMonitor *mon, 52 gint major, gint minor, gint rev) 53 { 54 GkrellmdClient *client = mon->privat->client; 55 56 if ( client->major_version > major 57 || (client->major_version == major && client->minor_version > minor) 58 || ( client->major_version == major && client->minor_version == minor 59 && client->rev_version >= rev 60 ) 61 ) 62 return TRUE; 63 return FALSE; 64 } 65 66 void 67 gkrellmd_add_serveflag_done(gboolean *flag) 68 { 69 serveflag_done_list = g_list_append(serveflag_done_list, flag); 70 } 71 72 73 void 74 gkrellmd_set_serve_name(GkrellmdMonitor *mon, const gchar *tag) 75 { 76 GkrellmdMonitorPrivate *mp = mon->privat; 77 78 mp->serve_name = tag; 79 mp->serve_name_sent = FALSE; 80 } 81 82 void 83 gkrellmd_serve_data(GkrellmdMonitor *mon, gchar *line) 84 { 85 GkrellmdMonitorPrivate *mp = mon->privat; 86 gchar buf[128]; 87 88 if (!line || !*line) 89 return; 90 if (!mp->serve_name_sent) 91 { 92 if (mp->serve_name) 93 { 94 snprintf(buf, sizeof(buf), "<%s>\n", mp->serve_name); 95 gkrellm_debug(DEBUG_SERVER, "%s", buf); 96 mp->serve_gstring = g_string_append(mp->serve_gstring, buf); 97 mp->serve_name_sent = TRUE; 98 } 99 else 100 { 101 g_warning("gkrellmd: %s forgot to gkrellmd_set_serve_name()\n", 102 mon->name); 103 return; 104 } 105 } 106 gkrellm_debug(DEBUG_SERVER,"%s", line); 107 mp->serve_gstring = g_string_append(mp->serve_gstring, line); 108 } 109 110 /* ======================================================= */ 111 typedef struct 112 { 113 gint instance; 114 gulong user, 115 nice, 116 sys, 117 idle; 118 } 119 CpuData; 120 121 static gchar *n_cpus_setup; 122 static gboolean nice_time_unsupported; 123 124 static GList *cpu_list; 125 static GList *instance_list; 126 127 void 128 gkrellm_cpu_set_number_of_cpus(gint n) 129 { 130 CpuData *cpu; 131 GList *list; 132 gint i; 133 134 n_cpus_setup = g_strdup_printf("n_cpus %d\n", n); 135 for (i = 0; i < n; ++i) 136 { 137 cpu = g_new0(CpuData, 1); 138 cpu_list = g_list_append(cpu_list, cpu); 139 140 if (instance_list && (list = g_list_nth(instance_list, i)) != NULL) 141 cpu->instance = GPOINTER_TO_INT(list->data); 142 else 143 cpu->instance = i; 144 } 145 } 146 147 void 148 gkrellm_cpu_add_instance(gint instance) 149 { 150 instance_list = g_list_append(instance_list, GINT_TO_POINTER(instance)); 151 } 152 153 void 154 gkrellm_cpu_nice_time_unsupported(void) 155 { 156 nice_time_unsupported = TRUE; 157 } 158 159 void 160 gkrellm_cpu_assign_composite_data(gulong user, gulong nice, 161 gulong sys, gulong idle) 162 { 163 return; /* let client gkrellm compute it */ 164 } 165 166 void 167 gkrellm_cpu_assign_data(gint n, gulong user, gulong nice, 168 gulong sys, gulong idle) 169 { 170 CpuData *cpu = NULL; 171 GList *list; 172 173 for (list = cpu_list; list; list = list->next) 174 { 175 cpu = (CpuData *) list->data; 176 if (cpu->instance == n) 177 break; 178 } 179 if (list) 180 { 181 cpu->user = user; 182 cpu->nice = nice; 183 cpu->sys = sys; 184 cpu->idle = idle; 185 } 186 } 187 188 static void 189 update_cpu(GkrellmdMonitor *mon, gboolean first_update) 190 { 191 gkrellm_sys_cpu_read_data(); 192 gkrellmd_need_serve(mon); 193 } 194 195 static void 196 serve_cpu_data(GkrellmdMonitor *mon, gboolean first_serve) 197 { 198 CpuData *cpu; 199 GList *list; 200 gchar buf[128]; 201 202 gkrellmd_set_serve_name(mon, "cpu"); 203 for (list = cpu_list; list; list = list->next) 204 { 205 cpu = (CpuData *) list->data; 206 snprintf(buf, sizeof(buf), "%d %lu %lu %lu %lu\n", cpu->instance, 207 cpu->user, cpu->nice, cpu->sys, cpu->idle); 208 gkrellmd_serve_data(mon, buf); 209 } 210 } 211 212 static void 213 serve_cpu_setup(GkrellmdMonitor *mon) 214 { 215 GkrellmdClient *client = mon->privat->client; 216 GList *list; 217 gchar buf[64]; 218 219 gkrellmd_send_to_client(client, "<cpu_setup>\n"); 220 for (list = instance_list; list; list = list->next) 221 { 222 snprintf(buf, sizeof(buf), "cpu_instance %d\n", 223 GPOINTER_TO_INT(list->data)); 224 gkrellmd_send_to_client(client, buf); 225 } 226 gkrellmd_send_to_client(client, n_cpus_setup); 227 if (nice_time_unsupported) 228 gkrellmd_send_to_client(client, "nice_time_unsupported\n"); 229 } 230 231 static GkrellmdMonitor cpu_monitor = 232 { 233 "cpu", 234 update_cpu, 235 serve_cpu_data, 236 serve_cpu_setup 237 }; 238 239 240 static GkrellmdMonitor * 241 init_cpu_monitor(void) 242 { 243 if (gkrellm_sys_cpu_init()) 244 return &cpu_monitor; 245 return NULL; 246 } 247 248 /* ======================================================= */ 249 struct 250 { 251 gboolean changed; 252 gint n_processes, 253 n_running, 254 n_users; 255 gulong n_forks; 256 gfloat fload; 257 } 258 proc; 259 260 void 261 gkrellm_proc_assign_data(gint n_processes, gint n_running, 262 gulong n_forks, gfloat load) 263 { 264 if ( proc.n_processes != n_processes 265 || proc.n_running != n_running 266 || proc.n_forks != n_forks 267 || proc.fload != load 268 ) 269 { 270 proc.n_processes = n_processes; 271 proc.n_running = n_running; 272 proc.n_forks = n_forks; 273 proc.fload = load; 274 proc.changed = TRUE; 275 } 276 } 277 278 void 279 gkrellm_proc_assign_users(gint n_users) 280 { 281 if (proc.n_users != n_users) 282 { 283 proc.n_users = n_users; 284 proc.changed = TRUE; 285 } 286 } 287 288 static void 289 update_proc(GkrellmdMonitor *mon, gboolean first_update) 290 { 291 proc.changed = FALSE; 292 gkrellm_sys_proc_read_data(); 293 if (first_update || GK.five_second_tick) 294 gkrellm_sys_proc_read_users(); 295 296 if (proc.changed) 297 gkrellmd_need_serve(mon); 298 } 299 300 static void 301 serve_proc_data(GkrellmdMonitor *mon, gboolean first_serve) 302 { 303 gchar buf[128]; 304 305 gkrellmd_set_serve_name(mon, "proc"); 306 snprintf(buf, sizeof(buf), "%d %d %lu %.2f %d\n", 307 proc.n_processes, proc.n_running, 308 proc.n_forks, proc.fload, proc.n_users); 309 gkrellmd_serve_data(mon, buf); 310 } 311 312 static GkrellmdMonitor proc_monitor = 313 { 314 "proc", 315 update_proc, 316 serve_proc_data, 317 NULL 318 }; 319 320 321 static GkrellmdMonitor * 322 init_proc_monitor(void) 323 { 324 if (!gkrellm_sys_proc_init()) 325 return NULL; 326 serveflag_done_list = g_list_append(serveflag_done_list, &proc.changed); 327 return &proc_monitor; 328 } 329 330 /* ======================================================= */ 331 typedef struct 332 { 333 gchar *name; 334 gchar *subdisk_parent; 335 gint order, 336 subdisk, 337 changed; 338 gint device_number, 339 unit_number; 340 gboolean virtual; 341 guint64 rb, 342 wb; 343 } 344 DiskData; 345 346 static GList *disk_list; 347 static gint n_disks; 348 static gboolean units_are_blocks; 349 350 351 static DiskData * 352 add_disk(const gchar *name, gint order, gint device_number, gint unit_number) 353 { 354 DiskData *disk; 355 GList *list; 356 gint i; 357 358 disk = g_new0(DiskData, 1); 359 disk->name = g_strdup(name); 360 disk->order = order; 361 disk->subdisk = -1; 362 disk->device_number = device_number; 363 disk->unit_number = unit_number; 364 if (order >= 0) 365 { 366 for (i = 0, list = disk_list; list; list = list->next, ++i) 367 if (disk->order < ((DiskData *) list->data)->order) 368 break; 369 disk_list = g_list_insert(disk_list, disk, i); 370 } 371 else 372 disk_list = g_list_append(disk_list, disk); 373 ++n_disks; 374 return disk; 375 } 376 377 static DiskData * 378 add_subdisk(gchar *subdisk_name, gchar *disk_name, gint subdisk) 379 { 380 DiskData *sdisk = NULL; 381 DiskData *disk; 382 GList *list = NULL; 383 384 for (list = disk_list; list; list = list->next) 385 { 386 disk = (DiskData * ) list->data; 387 if (!strcmp(disk_name, disk->name)) 388 break; 389 } 390 if (!list) 391 return NULL; 392 sdisk = g_new0(DiskData, 1); 393 sdisk->name = g_strdup(subdisk_name); 394 sdisk->subdisk_parent = g_strdup(disk_name); 395 sdisk->order = disk->order; 396 sdisk->subdisk = subdisk; 397 398 for (list = list->next; list; list = list->next) 399 { 400 disk = (DiskData * ) list->data; 401 if (disk->subdisk == -1 || disk->subdisk > subdisk) 402 break; 403 } 404 disk_list = g_list_insert_before(disk_list, list, sdisk); 405 ++n_disks; 406 return sdisk; 407 } 408 409 static void 410 disk_assign_data(DiskData *disk, guint64 rb, guint64 wb, gboolean virtual) 411 { 412 if (disk) 413 { 414 if (disk->rb != rb || disk->wb != wb) 415 disk->changed = TRUE; 416 else 417 disk->changed = FALSE; 418 disk->rb = rb; 419 disk->wb = wb; 420 disk->virtual = virtual; 421 } 422 } 423 424 void 425 gkrellm_disk_reset_composite(void) 426 { 427 /* Don't handle this. */ 428 } 429 430 void 431 gkrellm_disk_units_are_blocks(void) 432 { 433 units_are_blocks = TRUE; 434 } 435 436 void 437 gkrellm_disk_add_by_name(const gchar *name, const gchar *label) 438 { 439 gint order = -1; 440 441 if (NULL == name) // Cannot add disk without a name 442 return; 443 order = gkrellm_sys_disk_order_from_name(name); 444 /* FIXME: gkrellmd currently has no support for disk labels. Extend 445 network-protocol and server to support disks with both name and label. */ 446 add_disk(name, order, 0, 0); 447 } 448 449 void 450 gkrellm_disk_assign_data_by_device(gint device_number, gint unit_number, 451 guint64 rb, guint64 wb, gboolean virtual) 452 { 453 GList *list; 454 DiskData *disk = NULL; 455 gchar *name; 456 gint order = -1; 457 458 for (list = disk_list; list; list = list->next) 459 { 460 disk = (DiskData * ) list->data; 461 if ( disk->device_number == device_number 462 && disk->unit_number == unit_number 463 ) 464 break; 465 disk = NULL; 466 } 467 if (!disk) 468 { 469 name = gkrellm_sys_disk_name_from_device(device_number, 470 unit_number, &order); 471 if (name) 472 disk = add_disk(name, order, device_number, unit_number); 473 } 474 disk_assign_data(disk, rb, wb, virtual); 475 } 476 477 void 478 gkrellm_disk_assign_data_nth(gint n, guint64 rb, guint64 wb, gboolean virtual) 479 { 480 DiskData *disk; 481 gchar name[32]; 482 483 if (n < n_disks) 484 disk = (DiskData *) g_list_nth_data(disk_list, n); 485 else 486 { 487 snprintf(name, sizeof(name), "%s%c", _("Disk"), 'A' + n); 488 disk = add_disk(name, n, 0, 0); 489 } 490 disk_assign_data(disk, rb, wb, virtual); 491 } 492 493 void 494 gkrellm_disk_assign_data_by_name(gchar *name, 495 guint64 rb, guint64 wb, gboolean virtual) 496 { 497 GList *list; 498 DiskData *disk = NULL; 499 gint order = -1; 500 501 for (list = disk_list; list; list = list->next) 502 { 503 disk = (DiskData * ) list->data; 504 if (!strcmp(name, disk->name)) 505 break; 506 disk = NULL; 507 } 508 if (!disk) 509 { 510 order = gkrellm_sys_disk_order_from_name(name); 511 disk = add_disk(name, order, 0, 0); 512 } 513 disk_assign_data(disk, rb, wb, virtual); 514 } 515 516 void 517 gkrellm_disk_subdisk_assign_data_by_name(gchar *subdisk_name, gchar *disk_name, 518 guint64 rb, guint64 wb) 519 { 520 GList *list; 521 DiskData *disk = NULL; 522 gchar *s, *endptr; 523 gint subdisk; 524 525 if (!subdisk_name || !disk_name) 526 return; 527 for (list = disk_list; list; list = list->next) 528 { 529 disk = (DiskData * ) list->data; 530 if (!strcmp(subdisk_name, disk->name)) 531 break; 532 disk = NULL; 533 } 534 if (!disk) 535 { 536 /* A subdisk name is expected to be the disk_name with a number string 537 | appended. Eg. "hda1" is a subdisk_name of disk_name "hda" 538 */ 539 s = subdisk_name + strlen(disk_name); 540 if (*s == 'p') /* except mmcblkN SD disks have "pN" partition numbers */ 541 ++s; 542 subdisk = strtol(s, &endptr, 0); 543 if (!*s || *endptr) 544 return; 545 disk = add_subdisk(subdisk_name, disk_name, subdisk); 546 } 547 disk_assign_data(disk, rb, wb, FALSE); 548 } 549 550 static void 551 update_disk(GkrellmdMonitor *mon, gboolean first_update) 552 { 553 GList *list; 554 DiskData *disk = NULL; 555 556 gkrellm_sys_disk_read_data(); 557 for (list = disk_list; list; list = list->next) 558 { 559 disk = (DiskData * ) list->data; 560 if (disk->changed) 561 { 562 gkrellmd_need_serve(mon); 563 break; 564 } 565 } 566 } 567 568 569 static void 570 serve_disk_data(GkrellmdMonitor *mon, gboolean first_serve) 571 { 572 DiskData *disk; 573 GList *list; 574 gchar *buf = NULL; 575 576 gkrellmd_set_serve_name(mon, "disk"); 577 for (list = disk_list; list; list = list->next) 578 { 579 disk = (DiskData *) list->data; 580 if (!disk->changed && !first_serve) 581 continue; 582 if (!disk->subdisk_parent) 583 { 584 if (gkrellmd_check_client_version(mon, 2, 2, 7) && disk->virtual) 585 buf = g_strdup_printf("%s virtual %" PRIu64 " %" PRIu64 "\n", 586 disk->name, disk->rb, disk->wb); 587 else 588 buf = g_strdup_printf("%s %" PRIu64 " %" PRIu64 "\n", 589 disk->name, disk->rb, disk->wb); 590 } 591 else if (mon->privat->client->feature_subdisk) 592 buf = g_strdup_printf("%s %s %" PRIu64 " %" PRIu64 "\n", 593 disk->name, disk->subdisk_parent, disk->rb, disk->wb); 594 else 595 continue; 596 gkrellmd_serve_data(mon, buf); 597 g_free(buf); 598 buf = NULL; 599 } 600 } 601 602 static void 603 serve_disk_setup(GkrellmdMonitor *mon) 604 { 605 GkrellmdClient *client = mon->privat->client; 606 607 if (units_are_blocks) 608 gkrellmd_send_to_client(client, "<disk_setup>\nunits_are_blocks\n"); 609 if (gkrellmd_check_client_version(mon, 2,1,3)) 610 client->feature_subdisk = TRUE; 611 } 612 613 static GkrellmdMonitor disk_monitor = 614 { 615 "disk", 616 update_disk, 617 serve_disk_data, 618 serve_disk_setup 619 }; 620 621 622 static GkrellmdMonitor * 623 init_disk_monitor(void) 624 { 625 if (gkrellm_sys_disk_init()) 626 return &disk_monitor; 627 return NULL; 628 } 629 630 /* ======================================================= */ 631 #include "../src/inet.h" 632 633 typedef struct 634 { 635 ActiveTCP tcp; 636 gboolean alive, 637 new_connection; 638 } 639 InetData; 640 641 static GList *inet_list, 642 *inet_dead_list; 643 644 static gboolean inet_unsupported, 645 inet_new; 646 647 void 648 gkrellm_inet_log_tcp_port_data(gpointer data) 649 { 650 GList *list; 651 InetData *in; 652 ActiveTCP *tcp, *active_tcp = NULL; 653 gchar *ap, *aap; 654 gint slen; 655 656 tcp = (ActiveTCP *) data; 657 for (list = inet_list; list; list = list->next) 658 { 659 in = (InetData *) list->data; 660 active_tcp = &in->tcp; 661 if (tcp->family == AF_INET) 662 { 663 ap = (char *)&tcp->remote_addr; 664 aap = (char *)&active_tcp->remote_addr; 665 slen = sizeof(struct in_addr); 666 } 667 #if defined(INET6) 668 else if (tcp->family == AF_INET6) 669 { 670 ap = (char *)&tcp->remote_addr6; 671 aap = (char *)&active_tcp->remote_addr6; 672 slen = sizeof(struct in6_addr); 673 } 674 #endif 675 else 676 return; 677 if ( memcmp(aap, ap, slen) == 0 678 && active_tcp->remote_port == tcp->remote_port 679 && active_tcp->local_port == tcp->local_port 680 ) 681 { 682 in->alive = TRUE; /* Old alive connection still alive */ 683 return; 684 } 685 } 686 inet_new = TRUE; 687 in = g_new0(InetData, 1); 688 in->tcp = *tcp; 689 in->alive = TRUE; 690 in->new_connection = TRUE; 691 inet_list = g_list_append(inet_list, in); 692 } 693 694 static void 695 update_inet(GkrellmdMonitor *mon, gboolean first_update) 696 { 697 GList *list; 698 InetData *in; 699 static gint check_tcp; 700 701 702 if (!first_update && !GK.second_tick) 703 return; 704 705 if (first_update || check_tcp == 0) 706 { 707 gkrellm_free_glist_and_data(&inet_dead_list); 708 inet_new = FALSE; 709 for (list = inet_list; list; list = list->next) 710 { 711 in = (InetData *) list->data; 712 in->alive = FALSE; 713 in->new_connection = FALSE; 714 } 715 716 gkrellm_sys_inet_read_tcp_data(); 717 718 for (list = inet_list; list; ) 719 { 720 in = (InetData *) list->data; 721 if (!in->alive) 722 { 723 if (list == inet_list) 724 inet_list = inet_list->next; 725 list = g_list_remove(list, in); 726 inet_dead_list = g_list_append(inet_dead_list, in); 727 } 728 else 729 list = list->next; 730 } 731 if (inet_new || inet_dead_list) 732 gkrellmd_need_serve(mon); 733 } 734 check_tcp = (check_tcp + 1) % _GK.inet_interval; 735 } 736 737 static void 738 serve_inet_data(GkrellmdMonitor *mon, gboolean first_serve) 739 { 740 InetData *in; 741 ActiveTCP *tcp; 742 GList *list; 743 gchar buf[NI_MAXHOST + 128], *cp; 744 #if defined(INET6) && defined(HAVE_GETADDRINFO) 745 struct sockaddr_in6 sin6; 746 char addrbuf[NI_MAXHOST]; 747 #endif 748 749 if (inet_new || first_serve) 750 { 751 gkrellmd_set_serve_name(mon, "inet"); 752 for (list = inet_list; list; list = list->next) 753 { 754 in = (InetData *) list->data; 755 tcp = &in->tcp; 756 if ( tcp->family == AF_INET 757 && (in->new_connection || first_serve) 758 ) 759 { 760 cp = inet_ntoa(tcp->remote_addr); 761 snprintf(buf, sizeof(buf), "+0 %x %s:%x\n", 762 tcp->local_port, cp, tcp->remote_port); 763 } 764 #if defined(INET6) && defined(HAVE_GETADDRINFO) 765 else if (tcp->family == AF_INET6 766 && (in->new_connection || first_serve)) 767 { 768 memset(&sin6, 0, sizeof(sin6)); 769 memcpy(&sin6.sin6_addr, &tcp->remote_addr6, 770 sizeof(struct in6_addr)); 771 sin6.sin6_family = AF_INET6; 772 #ifdef SIN6_LEN 773 sin6.sin6_len = sizeof(struct sockaddr_in6); 774 #endif 775 if (getnameinfo((struct sockaddr *)&sin6, 776 sizeof(struct sockaddr_in6), 777 addrbuf, sizeof(addrbuf), 778 NULL, 0, 779 NI_NUMERICHOST|NI_WITHSCOPEID) 780 != 0) 781 continue; 782 snprintf(buf, sizeof(buf), "+6 %x [%s]:%x\n", 783 tcp->local_port, addrbuf, 784 tcp->remote_port); 785 } 786 #endif 787 else 788 continue; 789 790 gkrellmd_serve_data(mon, buf); 791 } 792 } 793 if (!first_serve) 794 { 795 gkrellmd_set_serve_name(mon, "inet"); 796 for (list = inet_dead_list; list; list = list->next) 797 { 798 in = (InetData *) list->data; 799 tcp = &in->tcp; 800 if (tcp->family == AF_INET) 801 { 802 cp = inet_ntoa(tcp->remote_addr); 803 snprintf(buf, sizeof(buf), "-0 %x %s:%x\n", 804 tcp->local_port, cp, tcp->remote_port); 805 } 806 #if defined(INET6) && defined(HAVE_GETADDRINFO) 807 else if (tcp->family == AF_INET6) 808 { 809 memset(&sin6, 0, sizeof(sin6)); 810 memcpy(&sin6.sin6_addr, &tcp->remote_addr6, 811 sizeof(struct in6_addr)); 812 sin6.sin6_family = AF_INET6; 813 #ifdef SIN6_LEN 814 sin6.sin6_len = sizeof(struct sockaddr_in6); 815 #endif 816 if (getnameinfo((struct sockaddr *)&sin6, 817 sizeof(struct sockaddr_in6), 818 addrbuf, sizeof(addrbuf), 819 NULL, 0, 820 NI_NUMERICHOST|NI_WITHSCOPEID) 821 != 0) 822 continue; 823 snprintf(buf, sizeof(buf), "-6 %x [%s]:%x\n", 824 tcp->local_port, addrbuf, 825 tcp->remote_port); 826 } 827 #endif 828 else 829 continue; 830 831 gkrellmd_serve_data(mon, buf); 832 } 833 } 834 } 835 836 static void 837 serve_inet_setup(GkrellmdMonitor *mon) 838 { 839 GkrellmdClient *client = mon->privat->client; 840 841 if (inet_unsupported) 842 gkrellmd_send_to_client(client, "<inet_setup>\ninet_unsupported\n"); 843 } 844 845 static GkrellmdMonitor inet_monitor = 846 { 847 "inet", 848 update_inet, 849 serve_inet_data, 850 serve_inet_setup 851 }; 852 853 854 static GkrellmdMonitor * 855 init_inet_monitor(void) 856 { 857 if (_GK.inet_interval > 0 && gkrellm_sys_inet_init()) 858 return &inet_monitor; 859 inet_unsupported = TRUE; 860 return NULL; 861 } 862 863 /* ======================================================= */ 864 865 #define TIMER_TYPE_NONE 0 866 #define TIMER_TYPE_PPP 1 867 #define TIMER_TYPE_IPPP 2 868 869 typedef struct 870 { 871 gchar *name; 872 gboolean changed, 873 up, 874 up_prev, 875 up_event, 876 down_event; 877 878 gboolean timed_changed; 879 time_t up_time; 880 881 gulong rx, 882 tx; 883 } 884 NetData; 885 886 static NetData *net_timer; 887 888 static GList *net_list, 889 *net_sys_list; 890 891 static time_t net_timer0; 892 static gint net_timer_type; 893 894 static gboolean net_use_routed; 895 896 897 gchar * 898 gkrellm_net_mon_first(void) 899 { 900 gchar *name = NULL; 901 902 net_sys_list = net_list; 903 if (net_sys_list) 904 { 905 name = ((NetData *) (net_sys_list->data))->name; 906 net_sys_list = net_sys_list->next; 907 } 908 return name; 909 } 910 911 gchar * 912 gkrellm_net_mon_next(void) 913 { 914 gchar *name = NULL; 915 916 if (net_sys_list) 917 { 918 name = ((NetData *) (net_sys_list->data))->name; 919 net_sys_list = net_sys_list->next; 920 } 921 return name; 922 } 923 924 void 925 gkrellm_net_use_routed(gboolean real_routed /* not applicable in server */) 926 { 927 net_use_routed = TRUE; 928 } 929 930 static NetData * 931 net_new(gchar *name) 932 { 933 NetData *net; 934 935 net = g_new0(NetData, 1); 936 net->name = g_strdup(name); 937 net_list = g_list_append(net_list, net); 938 939 if (net_timer_type != TIMER_TYPE_NONE && !strcmp(_GK.net_timer, net->name)) 940 net_timer = net; 941 942 return net; 943 } 944 945 void 946 gkrellm_net_assign_data(gchar *name, gulong rx, gulong tx) 947 { 948 GList *list; 949 NetData *net; 950 951 for (list = net_list; list; list = list->next) 952 { 953 net = (NetData *) list->data; 954 if (!strcmp(net->name, name)) 955 { 956 if (net->rx != rx || net->tx != tx) 957 net->changed = TRUE; 958 else 959 net->changed = FALSE; 960 break; 961 } 962 } 963 if (!list) 964 net = net_new(name); 965 966 if (GK.second_tick && !net_use_routed) 967 net->up = TRUE; 968 net->rx = rx; 969 net->tx = tx; 970 } 971 972 void 973 gkrellm_net_routed_event(gchar *name, gboolean routed) 974 { 975 GList *list; 976 NetData *net; 977 978 for (list = net_list; list; list = list->next) 979 { 980 net = (NetData *) list->data; 981 if (!strcmp(net->name, name)) 982 break; 983 } 984 if (!list) 985 net = net_new(name); 986 987 if (routed) 988 net->up_event = TRUE; 989 else 990 net->down_event = TRUE; 991 net->up = routed; 992 } 993 994 void 995 gkrellm_net_add_timer_type_ppp(gchar *name) 996 { 997 if (!_GK.net_timer || !name) 998 return; 999 if (name && !strncmp(_GK.net_timer, name, strlen(name) - 1)) 1000 net_timer_type = TIMER_TYPE_PPP; 1001 } 1002 1003 void 1004 gkrellm_net_add_timer_type_ippp(gchar *name) 1005 { 1006 if (!_GK.net_timer || !name) 1007 return; 1008 if (name && !strncmp(_GK.net_timer, name, strlen(name) - 1)) 1009 net_timer_type = TIMER_TYPE_IPPP; 1010 } 1011 1012 void 1013 gkrellm_net_set_lock_directory(gchar *dir) 1014 { 1015 /* Not supported remotely */ 1016 } 1017 1018 static void 1019 update_net(GkrellmdMonitor *mon, gboolean first_update) 1020 { 1021 GList *list; 1022 NetData *net; 1023 gint up_time = 0; 1024 1025 if (GK.second_tick) 1026 { 1027 if (!net_use_routed) 1028 { 1029 for (list = net_list; list; list = list->next) 1030 { 1031 net = (NetData *) list->data; 1032 net->up_prev = net->up; 1033 net->up = FALSE; 1034 } 1035 } 1036 else 1037 gkrellm_sys_net_check_routes(); 1038 } 1039 gkrellm_sys_net_read_data(); 1040 1041 if (GK.second_tick && !net_use_routed) 1042 { 1043 for (list = net_list; list; list = list->next) 1044 { 1045 net = (NetData *) list->data; 1046 if (net->up && !net->up_prev) 1047 net->up_event = TRUE; 1048 else if (!net->up && net->up_prev) 1049 net->down_event = TRUE; 1050 } 1051 } 1052 1053 if (net_timer && GK.second_tick) 1054 { 1055 if (net_timer_type == TIMER_TYPE_PPP) 1056 { 1057 struct stat st; 1058 gchar buf[256]; 1059 1060 if (net_timer->up_event) 1061 { 1062 snprintf(buf, sizeof(buf), "/var/run/%s.pid", net_timer->name); 1063 if (g_stat(buf, &st) == 0) 1064 net_timer0 = st.st_mtime; 1065 else 1066 time(&net_timer0); 1067 } 1068 if (net_timer->up) 1069 up_time = (int) (time(0) - net_timer0); 1070 } 1071 else if (net_timer_type == TIMER_TYPE_IPPP) 1072 { 1073 /* get all isdn status from its connect state because the 1074 | net_timer->up can be UP even with isdn line not connected. 1075 | Can't get time history if gkrellmd started after connects. 1076 */ 1077 static gboolean old_connected; 1078 gboolean connected; 1079 1080 connected = gkrellm_sys_net_isdn_online(); 1081 if (connected && !old_connected) 1082 time(&net_timer0); /* New session just started */ 1083 old_connected = connected; 1084 1085 up_time = (int) (time(0) - net_timer0); 1086 } 1087 if (up_time != net_timer->up_time) 1088 net_timer->timed_changed = TRUE; 1089 net_timer->up_time = up_time; 1090 } 1091 1092 gkrellmd_need_serve(mon); /* serve func checks for changed */ 1093 } 1094 1095 static void 1096 serve_net_data(GkrellmdMonitor *mon, gboolean first_serve) 1097 { 1098 NetData *net; 1099 GList *list; 1100 gchar buf[128]; 1101 gboolean fake_up_event; 1102 1103 gkrellmd_set_serve_name(mon, "net"); 1104 for (list = net_list; list; list = list->next) 1105 { 1106 net = (NetData *) list->data; 1107 if (net->changed || first_serve) 1108 { 1109 snprintf(buf, sizeof(buf), "%s %lu %lu\n", net->name, net->rx, net->tx); 1110 gkrellmd_serve_data(mon, buf); 1111 } 1112 } 1113 1114 /* Since the server transmits changes only, use the routed interface 1115 | to the client regardless if the sysdep code uses routed. 1116 */ 1117 if (GK.second_tick || first_serve) 1118 { 1119 gkrellmd_set_serve_name(mon, "net_routed"); 1120 for (list = net_list; list; list = list->next) 1121 { 1122 net = (NetData *) list->data; 1123 fake_up_event = (first_serve && net->up); 1124 if (net->up_event || net->down_event || fake_up_event) 1125 { 1126 snprintf(buf, sizeof(buf), "%s %d\n", net->name, 1127 fake_up_event ? TRUE : net->up_event); 1128 gkrellmd_serve_data(mon, buf); 1129 } 1130 if (mon->privat->client->last_client) 1131 net->up_event = net->down_event = FALSE; 1132 } 1133 } 1134 1135 if (net_timer && GK.second_tick) 1136 { 1137 if (net_timer->timed_changed || first_serve) 1138 { 1139 gkrellmd_set_serve_name(mon, "net_timer"); 1140 snprintf(buf, sizeof(buf), "%s %d\n", net_timer->name, (gint)net_timer->up_time); 1141 gkrellmd_serve_data(mon, buf); 1142 } 1143 } 1144 } 1145 1146 static void 1147 serve_net_setup(GkrellmdMonitor *mon) 1148 { 1149 GkrellmdClient *client = mon->privat->client; 1150 gchar buf[128]; 1151 1152 /* The client <-> server link always uses routed mode, but the client 1153 | needs to know if server sysdep uses routed for config purposes. 1154 */ 1155 if (net_use_routed) 1156 gkrellmd_send_to_client(client, "<net_setup>\nnet_use_routed\n"); 1157 1158 if (net_timer_type != TIMER_TYPE_NONE) 1159 { 1160 snprintf(buf, sizeof(buf), 1161 "<net_setup>\nnet_timer %s\n", _GK.net_timer); 1162 gkrellmd_send_to_client(client, buf); 1163 } 1164 } 1165 1166 static GkrellmdMonitor net_monitor = 1167 { 1168 "net", 1169 update_net, 1170 serve_net_data, 1171 serve_net_setup 1172 }; 1173 1174 1175 static GkrellmdMonitor * 1176 init_net_monitor(void) 1177 { 1178 net_timer_type = TIMER_TYPE_NONE; 1179 if (gkrellm_sys_net_init()) 1180 return &net_monitor; 1181 return NULL; 1182 } 1183 1184 1185 /* ======================================================= */ 1186 struct 1187 { 1188 gboolean mem_changed; 1189 guint64 total, 1190 used, 1191 free, 1192 shared, 1193 buffers, 1194 cached; 1195 1196 gboolean swap_changed; 1197 guint64 swap_total, 1198 swap_used; 1199 gulong swap_in, 1200 swap_out; 1201 } 1202 mem; 1203 1204 void 1205 gkrellm_mem_assign_data(guint64 total, guint64 used, guint64 free, 1206 guint64 shared, guint64 buffers, guint64 cached) 1207 { 1208 if ( mem.total != total 1209 || mem.used != used 1210 || mem.free != free 1211 || mem.shared != shared 1212 || mem.buffers != buffers 1213 || mem.cached != cached 1214 ) 1215 { 1216 mem.total = total; 1217 mem.used = used; 1218 mem.free = free; 1219 mem.shared = shared; 1220 mem.buffers = buffers; 1221 mem.cached = cached; 1222 mem.mem_changed = TRUE; 1223 } 1224 } 1225 1226 void 1227 gkrellm_swap_assign_data(guint64 total, guint64 used, 1228 gulong swap_in, gulong swap_out) 1229 { 1230 if ( mem.swap_total != total 1231 || mem.swap_used != used 1232 || mem.swap_in != swap_in 1233 || mem.swap_out != swap_out 1234 ) 1235 { 1236 mem.swap_total = total; 1237 mem.swap_used = used; 1238 mem.swap_in = swap_in; 1239 mem.swap_out = swap_out; 1240 mem.swap_changed = TRUE; 1241 } 1242 } 1243 1244 static void 1245 update_mem(GkrellmdMonitor *mon, gboolean first_update) 1246 { 1247 mem.mem_changed = mem.swap_changed = FALSE; 1248 1249 gkrellm_sys_swap_read_data(); 1250 if (first_update || GK.five_second_tick) 1251 gkrellm_sys_mem_read_data(); 1252 1253 if (mem.mem_changed || mem.swap_changed) 1254 gkrellmd_need_serve(mon); 1255 } 1256 1257 static void 1258 serve_mem_data(GkrellmdMonitor *mon, gboolean first_serve) 1259 { 1260 gchar buf[128]; 1261 1262 if (mem.mem_changed || first_serve) 1263 { 1264 gkrellmd_set_serve_name(mon, "mem"); 1265 snprintf(buf, sizeof(buf), "%" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", 1266 mem.total, mem.used, mem.free, 1267 mem.shared, mem.buffers, mem.cached); 1268 gkrellmd_serve_data(mon, buf); 1269 } 1270 1271 if (mem.swap_changed || first_serve) 1272 { 1273 gkrellmd_set_serve_name(mon, "swap"); 1274 snprintf(buf, sizeof(buf), "%" PRIu64 " %" PRIu64 " %lu %lu\n", 1275 mem.swap_total, mem.swap_used, 1276 mem.swap_in, mem.swap_out); 1277 gkrellmd_serve_data(mon, buf); 1278 } 1279 } 1280 1281 static GkrellmdMonitor mem_monitor = 1282 { 1283 "mem", 1284 update_mem, 1285 serve_mem_data, 1286 NULL 1287 }; 1288 1289 1290 static GkrellmdMonitor * 1291 init_mem_monitor(void) 1292 { 1293 if (!gkrellm_sys_mem_init()) 1294 return NULL; 1295 serveflag_done_list = g_list_append(serveflag_done_list, &mem.mem_changed); 1296 serveflag_done_list = g_list_append(serveflag_done_list,&mem.swap_changed); 1297 return &mem_monitor; 1298 } 1299 1300 /* ======================================================= */ 1301 typedef struct 1302 { 1303 gboolean busy, 1304 deleted, 1305 is_mounted, 1306 is_nfs, 1307 changed; 1308 gchar *directory, 1309 *device, 1310 *type, 1311 *options; 1312 gint64 blocks, 1313 bavail, 1314 bfree, 1315 bsize; 1316 } 1317 Mount; 1318 1319 static GList *mounts_list, 1320 *fstab_list; 1321 1322 static gboolean nfs_check, 1323 fs_check, 1324 fs_need_serve, 1325 fstab_list_modified, 1326 mounts_list_modified, 1327 mounting_unsupported; 1328 1329 static gchar *remote_fs_types[] = 1330 { 1331 "cifs", 1332 "nfs", 1333 "smbfs" 1334 }; 1335 1336 void 1337 gkrellm_fs_setup_eject(gchar *eject_tray, gchar *close_tray, 1338 void (*eject_func)(), void (*close_func)()) 1339 { 1340 /* Not supported remotely */ 1341 } 1342 1343 void 1344 gkrellm_fs_add_to_mounts_list(gchar *dir, gchar *dev, gchar *type) 1345 { 1346 GList *list; 1347 Mount *m; 1348 gint i; 1349 1350 for (list = mounts_list; list; list = list->next) 1351 { 1352 m = (Mount *) list->data; 1353 if ( !strcmp(m->directory, dir) 1354 && !strcmp(m->device, dev) 1355 && !strcmp(m->type, type) 1356 ) 1357 break; 1358 } 1359 if (!list) 1360 { 1361 m = g_new0(Mount, 1); 1362 m->directory = g_strdup(dir); 1363 m->device = g_strdup(dev); 1364 m->type = g_strdup(type); 1365 mounts_list = g_list_append(mounts_list, m); 1366 mounts_list_modified = TRUE; 1367 serveflag_done_list = g_list_append(serveflag_done_list, &m->changed); 1368 1369 for (i = 0; i < (sizeof(remote_fs_types) / sizeof(gchar *)); ++i) 1370 { 1371 if (!strcmp(m->type, remote_fs_types[i])) 1372 { 1373 m->is_nfs = TRUE; 1374 break; 1375 } 1376 } 1377 } 1378 m->is_mounted = TRUE; 1379 } 1380 1381 void 1382 gkrellm_fs_add_to_fstab_list(gchar *dir, gchar *dev, gchar *type, gchar *opt) 1383 { 1384 Mount *m; 1385 1386 m = g_new0(Mount, 1); 1387 m->directory = g_strdup(dir); 1388 m->device = g_strdup(dev); 1389 m->type = g_strdup(type); 1390 fstab_list = g_list_append(fstab_list, m); 1391 } 1392 1393 void 1394 gkrellm_fs_assign_fsusage_data(gpointer pointer, 1395 gint64 blocks, gint64 bavail, gint64 bfree, gint64 bsize) 1396 { 1397 Mount *m = (Mount *) pointer; 1398 1399 if ( m->blocks != blocks 1400 || m->bavail != bavail 1401 || m->bfree != bfree 1402 || m->bsize != bsize 1403 ) 1404 { 1405 m->blocks = blocks; 1406 m->bavail = bavail; 1407 m->bfree = bfree; 1408 m->bsize = bsize; 1409 1410 m->changed = TRUE; 1411 } 1412 } 1413 1414 void 1415 gkrellm_fs_mounting_unsupported(void) 1416 { 1417 mounting_unsupported = TRUE; 1418 } 1419 1420 static void 1421 refresh_mounts_list(void) 1422 { 1423 GList *list; 1424 Mount *m; 1425 1426 for (list = mounts_list; list; list = list->next) 1427 ((Mount *) list->data)->is_mounted = FALSE; 1428 1429 gkrellm_sys_fs_get_mounts_list(); 1430 1431 for (list = mounts_list; list; ) 1432 { 1433 m = (Mount *) list->data; 1434 if (!m->is_mounted) 1435 { 1436 if (list == mounts_list) 1437 mounts_list = mounts_list->next; 1438 list = g_list_remove_link(list, list); 1439 g_free(m->directory); 1440 g_free(m->device); 1441 g_free(m->type); 1442 serveflag_done_list = g_list_remove(serveflag_done_list, 1443 &m->changed); 1444 if (m->busy) 1445 m->deleted = TRUE; 1446 else 1447 g_free(m); 1448 mounts_list_modified = TRUE; 1449 } 1450 else 1451 list = list->next; 1452 } 1453 } 1454 1455 static void 1456 refresh_fstab_list(void) 1457 { 1458 Mount *m; 1459 1460 while (fstab_list) 1461 { 1462 m = (Mount *) fstab_list->data; 1463 g_free(m->directory); 1464 g_free(m->device); 1465 g_free(m->type); 1466 g_free(m); 1467 fstab_list = g_list_remove(fstab_list, fstab_list->data); 1468 } 1469 gkrellm_sys_fs_get_fstab_list(); 1470 fstab_list_modified = TRUE; 1471 } 1472 1473 static gpointer 1474 get_fsusage_thread(void *data) 1475 { 1476 Mount *m = (Mount *) data; 1477 1478 gkrellm_sys_fs_get_fsusage(m, m->directory); 1479 1480 if (m->deleted) 1481 g_free(m); 1482 else 1483 { 1484 if (m->changed) 1485 fs_need_serve = TRUE; 1486 m->busy = FALSE; 1487 } 1488 return NULL; 1489 } 1490 1491 static void 1492 update_fs(GkrellmdMonitor *mon, gboolean first_update) 1493 { 1494 GThread *gth; 1495 GList *list; 1496 Mount *m; 1497 static gint check_tick; 1498 1499 if (fs_need_serve) /* Asynchronous change in fsusage thread? */ 1500 gkrellmd_need_serve(mon); 1501 fs_need_serve = FALSE; 1502 1503 if (GK.second_tick) 1504 ++check_tick; 1505 fs_check = !(check_tick % _GK.fs_interval); 1506 1507 if (_GK.nfs_interval > 0) 1508 nfs_check = !(check_tick % _GK.nfs_interval); 1509 else 1510 nfs_check = 0; 1511 1512 if (!first_update && (!GK.second_tick || (!fs_check && !nfs_check))) 1513 return; 1514 refresh_mounts_list(); 1515 for (list = mounts_list; list; list = list->next) 1516 { 1517 m = (Mount *) list->data; 1518 if (fs_check && !m->is_nfs) 1519 gkrellm_sys_fs_get_fsusage(m, m->directory); 1520 else if (nfs_check && m->is_nfs && !m->busy) 1521 { 1522 m->busy = TRUE; 1523 gth = g_thread_new("get_fsusage", get_fsusage_thread, m); 1524 g_thread_unref(gth); 1525 } 1526 } 1527 if (first_update || gkrellm_sys_fs_fstab_modified()) 1528 refresh_fstab_list(); 1529 1530 gkrellmd_need_serve(mon); 1531 } 1532 1533 static void 1534 serve_fs_data(GkrellmdMonitor *mon, gboolean first_serve) 1535 { 1536 Mount *m; 1537 GList *list; 1538 gchar buf[128]; 1539 1540 if (mounts_list_modified || first_serve) 1541 { 1542 gkrellmd_set_serve_name(mon, "fs_mounts"); 1543 gkrellmd_serve_data(mon, ".clear\n"); 1544 for (list = mounts_list; list; list = list->next) 1545 { 1546 m = (Mount *) list->data; 1547 snprintf(buf, sizeof(buf), 1548 "%s %s %s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", 1549 m->directory, m->device, m->type, 1550 m->blocks, m->bavail, m->bfree, m->bsize); 1551 /*gkrellm_debug(DEBUG_SERVER, 1552 "Adding mount-line for %s to serve-data\n", m->directory);*/ 1553 gkrellmd_serve_data(mon, buf); 1554 } 1555 } 1556 else 1557 { 1558 gkrellmd_set_serve_name(mon, "fs"); 1559 for (list = mounts_list; list; list = list->next) 1560 { 1561 m = (Mount *) list->data; 1562 if (!m->changed) 1563 continue; 1564 snprintf(buf, sizeof(buf), 1565 "%s %s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", 1566 m->directory, m->device, 1567 m->blocks, m->bavail, m->bfree, m->bsize); 1568 /*gkrellm_debug(DEBUG_SERVER, 1569 "Updating fs %s in serve-data\n", m->directory);*/ 1570 gkrellmd_serve_data(mon, buf); 1571 } 1572 } 1573 if (fstab_list_modified || first_serve) 1574 { 1575 gkrellmd_set_serve_name(mon, "fs_fstab"); 1576 gkrellmd_serve_data(mon, ".clear\n"); 1577 for (list = fstab_list; list; list = list->next) 1578 { 1579 m = (Mount *) list->data; 1580 snprintf(buf, sizeof(buf), "%s %s %s\n", 1581 m->directory, m->device, m->type); 1582 /*gkrellm_debug(DEBUG_SERVER, 1583 "Adding fstab-line for %s to serve-data\n", m->directory);*/ 1584 gkrellmd_serve_data(mon, buf); 1585 } 1586 } 1587 } 1588 1589 static void 1590 serve_fs_setup(GkrellmdMonitor *mon) 1591 { 1592 GkrellmdClient *client = mon->privat->client; 1593 1594 if (mounting_unsupported) 1595 gkrellmd_send_to_client(client, "<fs_setup>\nmounting_unsupported\n"); 1596 } 1597 1598 static GkrellmdMonitor fs_monitor = 1599 { 1600 "fs", 1601 update_fs, 1602 serve_fs_data, 1603 serve_fs_setup 1604 }; 1605 1606 1607 static GkrellmdMonitor * 1608 init_fs_monitor(void) 1609 { 1610 if (!gkrellm_sys_fs_init()) 1611 return NULL; 1612 serveflag_done_list = 1613 g_list_append(serveflag_done_list, &fstab_list_modified); 1614 serveflag_done_list = 1615 g_list_append(serveflag_done_list, &mounts_list_modified); 1616 return &fs_monitor; 1617 } 1618 1619 /* ======================================================= */ 1620 1621 1622 typedef struct 1623 { 1624 gboolean changed, 1625 have_data; 1626 1627 gint id; 1628 gboolean present, 1629 on_line, 1630 charging; 1631 gint percent; 1632 gint time_left; 1633 } 1634 Battery; 1635 1636 static GList *battery_list; 1637 1638 static Battery *composite_battery; 1639 1640 1641 static Battery * 1642 battery_nth(gint n) 1643 { 1644 Battery *bat; 1645 static gint n_batteries; 1646 1647 if (n > 10) 1648 return NULL; 1649 if (n < 0) 1650 { 1651 if (!composite_battery) 1652 { 1653 bat = g_new0(Battery, 1); 1654 battery_list = g_list_prepend(battery_list, bat); 1655 bat->id = GKRELLM_BATTERY_COMPOSITE_ID; 1656 composite_battery = bat; 1657 serveflag_done_list = g_list_append(serveflag_done_list, 1658 &composite_battery->changed); 1659 } 1660 return composite_battery; 1661 } 1662 1663 if (composite_battery) 1664 ++n; 1665 1666 while ((bat = (Battery *)g_list_nth_data(battery_list, n)) == NULL) 1667 { 1668 bat = g_new0(Battery, 1); 1669 battery_list = g_list_append(battery_list, bat); 1670 bat->id = n_batteries++; 1671 serveflag_done_list = g_list_append(serveflag_done_list, 1672 &bat->changed); 1673 } 1674 return bat; 1675 } 1676 1677 void 1678 gkrellm_battery_assign_data(gint id, gboolean present, gboolean on_line, 1679 gboolean charging, gint percent, gint time_left) 1680 { 1681 Battery *bat; 1682 1683 bat = battery_nth(id); 1684 if (!bat) 1685 return; 1686 1687 if ( present != bat->present 1688 || on_line != bat->on_line 1689 || charging != bat->charging 1690 || percent != bat->percent 1691 || time_left != bat->time_left 1692 ) 1693 { 1694 bat->present = present; 1695 bat->on_line = on_line; 1696 bat->charging = charging; 1697 bat->percent = percent; 1698 bat->time_left = time_left; 1699 bat->changed = TRUE; 1700 } 1701 1702 bat->have_data = TRUE; 1703 } 1704 1705 gint 1706 gkrellm_battery_full_cap_fallback() 1707 { 1708 return 5000; /* XXX Linux ACPI bug not handled by server */ 1709 } 1710 1711 static void 1712 update_battery(GkrellmdMonitor *mon, gboolean first_update) 1713 { 1714 GList *list; 1715 Battery *bat; 1716 1717 if (!first_update && !GK.five_second_tick) 1718 return; 1719 1720 for (list = battery_list; list; list = list->next) 1721 { 1722 bat = (Battery *) list->data; 1723 bat->have_data = FALSE; 1724 bat->changed = FALSE; 1725 } 1726 gkrellm_sys_battery_read_data(); 1727 1728 for (list = battery_list; list; list = list->next) 1729 { 1730 bat = (Battery *) list->data; 1731 if (!bat->have_data && bat->present) 1732 { 1733 bat->present = FALSE; 1734 bat->changed = TRUE; 1735 } 1736 if (bat->changed) 1737 gkrellmd_need_serve(mon); 1738 } 1739 } 1740 1741 static void 1742 serve_battery_data(GkrellmdMonitor *mon, gboolean first_serve) 1743 { 1744 Battery *bat; 1745 GList *list; 1746 gchar buf[128]; 1747 1748 gkrellmd_set_serve_name(mon, "battery"); 1749 for (list = battery_list; list; list = list->next) 1750 { 1751 bat = (Battery *) list->data; 1752 1753 if ( (!bat->changed && !first_serve) 1754 || ( !gkrellmd_check_client_version(mon, 2,1,9) 1755 && bat->id > 0 1756 ) 1757 ) 1758 continue; 1759 snprintf(buf, sizeof(buf), "%d %d %d %d %d %d\n", 1760 bat->present, bat->on_line, bat->charging, 1761 bat->percent, bat->time_left, bat->id); 1762 gkrellmd_serve_data(mon, buf); 1763 } 1764 } 1765 1766 static void 1767 serve_battery_setup(GkrellmdMonitor *mon) 1768 { 1769 GkrellmdClient *client = mon->privat->client; 1770 1771 gkrellm_sys_battery_read_data(); 1772 if (battery_list) 1773 gkrellmd_send_to_client(client, 1774 "<battery_setup>\nbattery_available\n"); 1775 } 1776 1777 static GkrellmdMonitor battery_monitor = 1778 { 1779 "battery", 1780 update_battery, 1781 serve_battery_data, 1782 serve_battery_setup 1783 }; 1784 1785 static GkrellmdMonitor * 1786 init_battery_monitor(void) 1787 { 1788 if (!gkrellm_sys_battery_init()) 1789 return NULL; 1790 return &battery_monitor; 1791 } 1792 1793 /* ======================================================= */ 1794 1795 typedef struct 1796 { 1797 gboolean changed; 1798 gint type; 1799 1800 gchar *path; /* Pathname to sensor data or device file */ 1801 1802 gchar *id_name; /* These 4 are unique sensor identification */ 1803 gint id; /* of a particular sensor type */ 1804 gint iodev; /* One or any combination may be used. */ 1805 gint inter; 1806 1807 gchar *vref; 1808 gchar *default_label; 1809 gint group; 1810 1811 gfloat factor; 1812 gfloat offset; 1813 gfloat raw_value; 1814 } 1815 Sensor; 1816 1817 static GList *sensors_list; 1818 1819 static gboolean thread_busy, 1820 sensors_need_serve; 1821 1822 static gpointer 1823 read_sensors(void *data) 1824 { 1825 GList *list; 1826 Sensor *sensor; 1827 gfloat tmp; 1828 gboolean need_serve = FALSE; 1829 1830 for (list = sensors_list; list; list = list->next) 1831 { 1832 sensor = (Sensor *) list->data; 1833 tmp = sensor->raw_value; 1834 if (sensor->type == SENSOR_TEMPERATURE) 1835 gkrellm_sys_sensors_get_temperature(sensor->path, sensor->id, 1836 sensor->iodev, sensor->inter, &sensor->raw_value); 1837 else if (sensor->type == SENSOR_FAN) 1838 gkrellm_sys_sensors_get_fan(sensor->path, sensor->id, 1839 sensor->iodev, sensor->inter, &sensor->raw_value); 1840 else if (sensor->type == SENSOR_VOLTAGE) 1841 gkrellm_sys_sensors_get_voltage(sensor->path, sensor->id, 1842 sensor->iodev, sensor->inter, &sensor->raw_value); 1843 if (sensor->raw_value != tmp) 1844 { 1845 sensor->changed = TRUE; 1846 need_serve = TRUE; 1847 } 1848 else 1849 sensor->changed = FALSE; 1850 } 1851 thread_busy = FALSE; 1852 sensors_need_serve = need_serve; /* Thread, so set after data collected */ 1853 1854 return NULL; 1855 } 1856 1857 static void 1858 run_sensors_thread(void) 1859 { 1860 GThread *gth; 1861 1862 if (thread_busy) 1863 return; 1864 thread_busy = TRUE; 1865 gth = g_thread_new("read_sensors", read_sensors, NULL); 1866 g_thread_unref(gth); 1867 } 1868 1869 1870 void 1871 gkrellm_sensors_config_migrate_connect(gboolean (*func)(), gint sysdep_version) 1872 { 1873 } 1874 1875 void 1876 gkrellm_sensors_update_volt_order_base(void) 1877 { 1878 } 1879 1880 void 1881 gkrellm_sensors_set_group(gpointer sr, gint group) 1882 { 1883 Sensor *sensor = (Sensor *) sr; 1884 1885 if (sensor) 1886 sensor->group = group; 1887 } 1888 1889 void 1890 gkrellm_sensors_sysdep_option(gchar *keyword, gchar *label, void (*func)()) 1891 { 1892 } 1893 1894 /* A sensor within a type is uniquely identified by its id_name. 1895 | A sysdep interface may additionally use any of the triple integer 1896 | set (id, iodev, inter) for internal identification. 1897 | Monitor code here uses path to read the sensor values, but id_name is only 1898 | passed to the client since that is all that is needed for identification 1899 | (the client is no longer interfacing to sysdep code). 1900 */ 1901 gpointer 1902 gkrellm_sensors_add_sensor(gint type, gchar *sensor_path, gchar *id_name, 1903 gint id, gint iodev, gint inter, 1904 gfloat factor, gfloat offset, gchar *vref, gchar *default_label) 1905 { 1906 Sensor *sensor; 1907 1908 if (!id_name || !*id_name || type < 0 || type > 2) 1909 return NULL; 1910 1911 sensor = g_new0(Sensor, 1); 1912 sensor->id_name = g_strdup(id_name); 1913 1914 if (sensor_path) 1915 sensor->path = g_strdup(sensor_path); 1916 else 1917 sensor->path = g_strdup(id_name); 1918 1919 sensor->vref = g_strdup(vref ? vref : "NONE"); 1920 sensor->default_label = g_strdup(default_label ? default_label : "NONE"); 1921 1922 sensor->factor = factor; 1923 sensor->offset = offset; 1924 sensor->type = type; 1925 sensor->id = id; 1926 sensor->iodev = iodev; 1927 sensor->inter = inter; 1928 sensors_list = g_list_append(sensors_list, sensor); 1929 return sensor; 1930 } 1931 1932 static void 1933 update_sensors(GkrellmdMonitor *mon, gboolean first_update) 1934 { 1935 if (sensors_need_serve) /* Asynchronously set in thread */ 1936 gkrellmd_need_serve(mon); 1937 sensors_need_serve = FALSE; 1938 1939 if (!GK.five_second_tick && !first_update) 1940 return; 1941 if (first_update) 1942 read_sensors(NULL); /* No thread on first read */ 1943 else 1944 run_sensors_thread(); 1945 } 1946 1947 static void 1948 serve_sensors_data(GkrellmdMonitor *mon, gboolean first_serve) 1949 { 1950 Sensor *sr; 1951 GList *list; 1952 gchar buf[128]; 1953 gboolean sensor_disk_ok; 1954 1955 gkrellmd_set_serve_name(mon, "sensors"); 1956 sensor_disk_ok = gkrellmd_check_client_version(mon, 2,2,0); 1957 for (list = sensors_list; list; list = list->next) 1958 { 1959 sr = (Sensor *) list->data; 1960 if (sr->group == SENSOR_GROUP_DISK && !sensor_disk_ok) 1961 continue; 1962 if (sr->changed || first_serve) 1963 { 1964 snprintf(buf, sizeof(buf), "%d \"%s\" %d %d %d %.2f\n", 1965 sr->type, sr->id_name, 1966 sr->id, sr->iodev, sr->inter, sr->raw_value); 1967 gkrellmd_serve_data(mon, buf); 1968 } 1969 } 1970 } 1971 1972 static void 1973 serve_sensors_setup(GkrellmdMonitor *mon) 1974 { 1975 GkrellmdClient *client = mon->privat->client; 1976 GList *list; 1977 Sensor *s; 1978 gchar buf[256]; 1979 gboolean sensor_disk_ok; 1980 1981 gkrellmd_send_to_client(client, "<sensors_setup>\n"); 1982 sensor_disk_ok = gkrellmd_check_client_version(mon, 2,2,0); 1983 for (list = sensors_list; list; list = list->next) 1984 { 1985 s = (Sensor *) list->data; 1986 if (s->group == SENSOR_GROUP_DISK && !sensor_disk_ok) 1987 continue; 1988 if (sensor_disk_ok) 1989 snprintf(buf, sizeof(buf), "%d \"%s\" %d %d %d %.4f %.4f \"%s\" \"%s\" %d\n", 1990 s->type, s->id_name, 1991 s->id, s->iodev, s->inter, 1992 s->factor, s->offset, s->vref, s->default_label, s->group); 1993 else 1994 snprintf(buf, sizeof(buf), "%d \"%s\" %d %d %d %.4f %.4f \"%s\" \"%s\"\n", 1995 s->type, s->id_name, 1996 s->id, s->iodev, s->inter, 1997 s->factor, s->offset, s->vref, s->default_label); 1998 gkrellmd_send_to_client(client, buf); 1999 } 2000 } 2001 2002 static GkrellmdMonitor sensors_monitor = 2003 { 2004 "sensors", 2005 update_sensors, 2006 serve_sensors_data, 2007 serve_sensors_setup 2008 }; 2009 2010 static GkrellmdMonitor * 2011 init_sensors_monitor(void) 2012 { 2013 if (!gkrellm_sys_sensors_init()) 2014 return NULL; 2015 return &sensors_monitor; 2016 } 2017 2018 /* ======================================================= */ 2019 static time_t base_uptime, 2020 up_seconds; 2021 static glong up_minutes = -1; 2022 2023 void 2024 gkrellm_uptime_set_base_uptime(time_t base) 2025 { 2026 base_uptime = base; 2027 } 2028 2029 static void 2030 update_uptime(GkrellmdMonitor *mon, gboolean first_update) 2031 { 2032 glong prev_up; 2033 2034 if (GK.ten_second_tick || up_minutes < 0 || first_update) 2035 { 2036 prev_up = up_minutes; 2037 up_seconds = gkrellm_sys_uptime_read_uptime(); 2038 if (up_seconds > 0) 2039 up_minutes = (glong) (up_seconds / 60); 2040 else 2041 up_minutes = (glong)(time(0) - _GK.start_time + base_uptime) / 60; 2042 if (up_minutes != prev_up) 2043 gkrellmd_need_serve(mon); 2044 } 2045 } 2046 2047 static void 2048 serve_uptime_data(GkrellmdMonitor *mon, gboolean first_serve) 2049 { 2050 gchar buf[128]; 2051 2052 gkrellmd_set_serve_name(mon, "uptime"); 2053 snprintf(buf, sizeof(buf), "%ld\n", (glong) (up_minutes >= 0 ? up_minutes : 0)); 2054 gkrellmd_serve_data(mon, buf); 2055 } 2056 2057 static GkrellmdMonitor uptime_monitor = 2058 { 2059 "uptime", 2060 update_uptime, 2061 serve_uptime_data, 2062 NULL 2063 }; 2064 2065 static GkrellmdMonitor * 2066 init_uptime_monitor(void) 2067 { 2068 if (!gkrellm_sys_uptime_init()) 2069 return NULL; 2070 return &uptime_monitor; 2071 } 2072 2073 /* ======================================================= */ 2074 static void 2075 send_time(GkrellmdClient *client) 2076 { 2077 struct tm *t; 2078 gchar buf[128]; 2079 2080 t = &gkrellmd_current_tm; 2081 snprintf(buf, sizeof(buf), "<time>\n%d %d %d %d %d %d %d %d %d\n", 2082 t->tm_sec, t->tm_min, t->tm_hour, 2083 t->tm_mday, t->tm_mon, t->tm_year, 2084 t->tm_wday, t->tm_yday, t->tm_isdst); 2085 gkrellmd_send_to_client(client, buf); 2086 } 2087 2088 /* ======================================================= */ 2089 2090 void 2091 gkrellmd_plugin_serve_setup(GkrellmdMonitor *mon, gchar *name, gchar *line) 2092 { 2093 GkrellmdClient *client = mon->privat->client; 2094 gchar buf[256]; 2095 2096 if (!mon || !name || !line) 2097 return; 2098 gkrellmd_send_to_client(client, "<plugin_setup>\n"); 2099 snprintf(buf, sizeof(buf), "%s %s\n", name, line); 2100 gkrellmd_send_to_client(client, buf); 2101 } 2102 2103 static void 2104 add_monitor(GkrellmdMonitor *mon) 2105 { 2106 if (!mon) 2107 return; 2108 mon->privat = g_new0(GkrellmdMonitorPrivate, 1); 2109 mon->privat->serve_gstring = g_string_new(""); 2110 gkrellmd_monitor_list = g_list_append(gkrellmd_monitor_list, mon); 2111 } 2112 2113 void 2114 gkrellmd_load_monitors(void) 2115 { 2116 GList *list; 2117 GkrellmdMonitor *mon; 2118 2119 add_monitor(init_sensors_monitor()); 2120 add_monitor(init_cpu_monitor()); 2121 add_monitor(init_proc_monitor()); 2122 add_monitor(init_disk_monitor()); 2123 add_monitor(init_net_monitor()); 2124 add_monitor(init_inet_monitor()); 2125 add_monitor(init_mem_monitor()); 2126 add_monitor(init_fs_monitor()); 2127 add_monitor(gkrellmd_init_mail_monitor()); 2128 add_monitor(init_battery_monitor()); 2129 add_monitor(init_uptime_monitor()); 2130 2131 list = gkrellmd_plugins_load(); 2132 if (_GK.list_plugins) 2133 exit(0); 2134 if (_GK.log_plugins) 2135 g_message("%s\n", plugin_install_log ? plugin_install_log : 2136 _("No plugins found\n")); 2137 for ( ; list; list = list->next) 2138 { 2139 mon = (GkrellmdMonitor *) list->data; 2140 mon->privat->serve_gstring = g_string_new(""); 2141 mon->privat->is_plugin = TRUE; 2142 gkrellmd_monitor_list = g_list_append(gkrellmd_monitor_list, mon); 2143 } 2144 } 2145 2146 void 2147 gkrellmd_need_serve(GkrellmdMonitor *mon) 2148 { 2149 if (mon) 2150 mon->privat->need_serve = TRUE; 2151 } 2152 2153 gint 2154 gkrellmd_update_monitors(void) 2155 { 2156 GList *list, *c_list; 2157 GkrellmdMonitor *mon; 2158 GkrellmdMonitorPrivate *mp; 2159 GkrellmdClient *client; 2160 struct tm *pCur; 2161 static time_t time_prev; 2162 gchar buf[64]; 2163 static gboolean first_update = TRUE; 2164 static GString *serve_gstring; 2165 2166 time(&_GK.time_now); 2167 GK.second_tick = (_GK.time_now == time_prev) ? FALSE : TRUE; 2168 time_prev = _GK.time_now; 2169 2170 if (GK.second_tick) 2171 { 2172 pCur = localtime(&_GK.time_now); 2173 GK.two_second_tick = ((pCur->tm_sec % 2) == 0) ? TRUE : FALSE; 2174 GK.five_second_tick = ((pCur->tm_sec % 5) == 0) ? TRUE : FALSE; 2175 GK.ten_second_tick = ((pCur->tm_sec % 10) == 0) ? TRUE : FALSE; 2176 GK.minute_tick = (pCur->tm_min != gkrellmd_current_tm.tm_min); 2177 gkrellmd_current_tm = *pCur; 2178 } 2179 else 2180 { 2181 GK.two_second_tick = FALSE; 2182 GK.five_second_tick = FALSE; 2183 GK.ten_second_tick = FALSE; 2184 GK.minute_tick = FALSE; 2185 } 2186 2187 for (list = gkrellmd_monitor_list; list; list = list->next) 2188 { 2189 mon = (GkrellmdMonitor *) list->data; 2190 if (mon->update_monitor) 2191 (*(mon->update_monitor))(mon, first_update); 2192 } 2193 ++GK.timer_ticks; 2194 if (!serve_gstring) 2195 serve_gstring = g_string_new(""); 2196 for (c_list = gkrellmd_client_list; c_list; c_list = c_list->next) 2197 { 2198 client = (GkrellmdClient *) c_list->data; 2199 client->last_client = !c_list->next; 2200 if (!client->served) 2201 gkrellmd_send_to_client(client, "<initial_update>\n"); 2202 for (list = gkrellmd_monitor_list; list; list = list->next) 2203 { 2204 mon = (GkrellmdMonitor *) list->data; 2205 mp = mon->privat; 2206 if (!mon->serve_data || (!mp->need_serve && client->served)) 2207 continue; 2208 mp->client = client; 2209 mp->serve_name_sent = FALSE; 2210 (*(mon->serve_data))(mon, client->served ? FALSE : TRUE); 2211 if (mp->serve_gstring->len > 0) 2212 { 2213 serve_gstring = 2214 g_string_append(serve_gstring, mp->serve_gstring->str); 2215 mp->serve_gstring = g_string_truncate(mp->serve_gstring, 0); 2216 } 2217 } 2218 gkrellmd_send_to_client(client, serve_gstring->str); 2219 serve_gstring = g_string_truncate(serve_gstring, 0); 2220 2221 if (GK.minute_tick || !client->served) 2222 send_time(client); 2223 else if (GK.second_tick) 2224 { 2225 snprintf(buf, sizeof(buf), "<.%d>\n", gkrellmd_current_tm.tm_sec); 2226 gkrellmd_send_to_client(client, buf); 2227 } 2228 2229 if (!client->served) 2230 gkrellmd_send_to_client(client, "</initial_update>\n"); 2231 client->served = TRUE; 2232 } 2233 2234 for (list = gkrellmd_monitor_list; list; list = list->next) 2235 { 2236 mon = (GkrellmdMonitor *) list->data; 2237 mp = mon->privat; 2238 mp->need_serve = FALSE; 2239 } 2240 2241 for (list = serveflag_done_list; list; list = list->next) 2242 *((gboolean *) list->data) = FALSE; 2243 2244 first_update = FALSE; 2245 return TRUE; 2246 } 2247 2248 void 2249 gkrellmd_serve_setup(GkrellmdClient *client) 2250 { 2251 GList *list; 2252 GkrellmdMonitor *mon; 2253 struct lconv *lc; 2254 gchar buf[32], *s, *name; 2255 2256 gkrellmd_send_to_client(client, "<gkrellmd_setup>\n"); 2257 2258 s = g_strdup_printf("<version>\ngkrellmd %d.%d.%d%s\n", 2259 GKRELLMD_VERSION_MAJOR, GKRELLMD_VERSION_MINOR, 2260 GKRELLMD_VERSION_REV, GKRELLMD_EXTRAVERSION); 2261 gkrellmd_send_to_client(client, s); 2262 g_free(s); 2263 2264 lc = localeconv(); 2265 snprintf(buf, sizeof(buf), "%c\n", *lc->decimal_point); 2266 s = g_strconcat("<decimal_point>\n", buf, "\n", NULL); 2267 gkrellmd_send_to_client(client, s); 2268 g_free(s); 2269 2270 for (list = gkrellmd_monitor_list; list; list = list->next) 2271 { 2272 mon = (GkrellmdMonitor *) list->data; 2273 mon->privat->client = client; 2274 if (mon->serve_setup) 2275 (*(mon->serve_setup))(mon); 2276 } 2277 name = gkrellm_sys_get_host_name(); 2278 s = g_strconcat("<hostname>\n", name, "\n", NULL); 2279 gkrellmd_send_to_client(client, s); 2280 g_free(s); 2281 2282 name = gkrellm_sys_get_system_name(); 2283 s = g_strconcat("<sysname>\n", name, "\n", NULL); 2284 gkrellmd_send_to_client(client, s); 2285 g_free(s); 2286 2287 send_time(client); 2288 2289 gkrellmd_send_to_client(client, "<monitors>\n"); 2290 for (list = gkrellmd_monitor_list; list; list = list->next) 2291 { 2292 mon = (GkrellmdMonitor *) list->data; 2293 snprintf(buf, sizeof(buf), "%s\n", mon->name); 2294 gkrellmd_send_to_client(client, buf); 2295 } 2296 2297 snprintf(buf, sizeof(buf), "%d\n", _GK.io_timeout); 2298 s = g_strconcat("<io_timeout>\n", buf, "\n", NULL); 2299 gkrellmd_send_to_client(client, s); 2300 g_free(s); 2301 2302 snprintf(buf, sizeof(buf), "%d\n", _GK.reconnect_timeout); 2303 s = g_strconcat("<reconnect_timeout>\n", buf, "\n", NULL); 2304 gkrellmd_send_to_client(client, s); 2305 g_free(s); 2306 2307 gkrellmd_send_to_client(client, "</gkrellmd_setup>\n"); 2308 } 2309 2310 void 2311 gkrellmd_client_input_connect(GkrellmdMonitor *mon, 2312 void (*func)(GkrellmdClient *, gchar *)) 2313 { 2314 mon->privat->client_input_func = func; 2315 } 2316 2317 void 2318 gkrellmd_client_read(gint fd, gint nbytes) 2319 { 2320 GList *list; 2321 GkrellmdClient *client = NULL; 2322 GkrellmdMonitor *mon; 2323 GkrellmdMonitorPrivate *mp; 2324 gchar buf[513], *s, *e; 2325 gint n, buflen; 2326 2327 for (list = gkrellmd_client_list; list; list = list->next) 2328 { 2329 client = (GkrellmdClient *) list->data; 2330 if (client->fd != fd) 2331 continue; 2332 2333 if (!client->input_gstring) 2334 client->input_gstring = g_string_new(""); 2335 2336 buflen = sizeof(buf) - 1; 2337 while (nbytes > 0) 2338 { 2339 n = (nbytes > buflen) ? buflen : nbytes; 2340 n = recv(fd, buf, n, 0); 2341 if (n <= 0) 2342 break; 2343 nbytes -= n; 2344 buf[n] = '\0'; 2345 client->input_gstring = 2346 g_string_append(client->input_gstring, buf); 2347 } 2348 break; 2349 } 2350 if (!list) 2351 return; 2352 2353 while (gkrellmd_getline_from_gstring(&client->input_gstring, 2354 buf, sizeof(buf) - 1)) 2355 { 2356 if (*buf == '<') 2357 { 2358 client->input_func = NULL; 2359 s = buf + 1; 2360 for (list = gkrellmd_monitor_list; list; list = list->next) 2361 { 2362 mon = (GkrellmdMonitor *) list->data; 2363 mp = mon->privat; 2364 if (!mp->serve_name) 2365 continue; 2366 n = strlen(mp->serve_name); 2367 e = s + n; 2368 if (*e == '>' && !strncmp(mp->serve_name, s, n)) 2369 { 2370 client->input_func = mp->client_input_func; 2371 break; 2372 } 2373 } 2374 } 2375 else if (client->input_func) 2376 (*client->input_func)(client, buf); 2377 // printf("%s: %s", client->hostname, buf); 2378 } 2379 } 2380