1 /*
2 * ProFTPD: mod_load -- a module for refusing connections based on system load
3 * Copyright (c) 2001-2017 TJ Saunders
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 *
19 * As a special exemption, TJ Saunders and other respective copyright holders
20 * give permission to link this program with OpenSSL, and distribute the
21 * resulting executable, without including the source code for OpenSSL in the
22 * source distribution.
23 *
24 * This is mod_load, contrib software for proftpd 1.2.x and above.
25 * For more information contact TJ Saunders <tj@castaglia.org>.
26 *
27 * Based on the getloadavg.c file included in GNU make-3.79, which carries
28 * the following copyright:
29 *
30 * Copyright (C) 1985, 86, 87, 88, 89, 91, 92, 93, 1994, 1995, 1997
31 * Free Software Foundation, Inc.
32 */
33
34 #include "conf.h"
35 #include "privs.h"
36 #include "mod_load.h"
37
38 #define MOD_LOAD_VERSION "mod_load/1.0.1"
39
40 /* Make sure the version of proftpd is as necessary. */
41 #if PROFTPD_VERSION_NUMBER < 0x0001030402
42 # error "ProFTPD 1.3.4rc2 or later required"
43 #endif
44
45 /* Support code. Most of this is from getloadavg.c
46 */
47
48 #if defined (unix) || defined (__unix)
49 # include <sys/param.h>
50 #endif
51
52 #ifndef HAVE_GETLOADAVG
53 # if !defined(LDAV_CVT) && defined(LOAD_AVE_CVT)
54 # define LDAV_CVT(n) (LOAD_AVE_CVT (n) / 100.0)
55 # endif
56
57 # if !defined (BSD) && defined (ultrix)
58 # define BSD
59 # endif
60
61 # ifdef NeXT
62 # undef BSD
63 # undef FSCALE
64 # endif
65
66 # ifdef __GNU__
67 # undef BSD
68 # undef FSCALE
69 # endif /* __GNU__ */
70
71 # if defined (HPUX) && !defined (hpux)
72 # define hpux
73 # endif
74
75 # if defined (__hpux) && !defined (hpux)
76 # define hpux
77 # endif
78
79 # if defined (__sun) && !defined (sun)
80 # define sun
81 # endif
82
83 # if defined(hp300) && !defined(hpux)
84 # define MORE_BSD
85 # endif
86
87 # if defined(ultrix) && defined(mips)
88 # define decstation
89 # endif
90
91 # if defined (__SVR4) && !defined (SVR4)
92 # define SVR4
93 # endif
94
95 # if (defined(sun) && defined(SVR4)) || defined (SOLARIS2)
96 # define SUNOS_5
97 # endif
98
99 # if defined (__osf__) && (defined (__alpha) || defined (__alpha__))
100 # define OSF_ALPHA
101 # include <sys/mbuf.h>
102 # include <sys/socket.h>
103 # include <net/route.h>
104 # include <sys/table.h>
105 # endif
106
107 # if defined (__osf__) && (defined (mips) || defined (__mips__))
108 # define OSF_MIPS
109 # include <sys/table.h>
110 # endif
111
112 # if !defined (tek4300) && defined (unix) && defined (m68k) && defined (mc68000) && defined (mc68020) && defined (_MACH_IND_SYS_TYPES)
113 # define tek4300
114 # endif
115
116 # ifndef LOAD_AVE_TYPE
117
118 # ifdef MORE_BSD
119 # define LOAD_AVE_TYPE long
120 # endif
121
122 # ifdef sun
123 # define LOAD_AVE_TYPE long
124 # endif
125
126 # ifdef decstation
127 # define LOAD_AVE_TYPE long
128 # endif
129
130 # ifdef _SEQUENT_
131 # define LOAD_AVE_TYPE long
132 # endif
133
134 # ifdef sgi
135 # define LOAD_AVE_TYPE long
136 # endif
137
138 # ifdef SVR4
139 # define LOAD_AVE_TYPE long
140 # endif
141
142 # ifdef sony_news
143 # define LOAD_AVE_TYPE long
144 # endif
145
146 # ifdef sequent
147 # define LOAD_AVE_TYPE long
148 # endif
149
150 # ifdef OSF_ALPHA
151 # define LOAD_AVE_TYPE long
152 # endif
153
154 # if defined (ardent) && defined (titan)
155 # define LOAD_AVE_TYPE long
156 # endif
157
158 # ifdef tek4300
159 # define LOAD_AVE_TYPE long
160 # endif
161
162 # if defined(alliant) && defined(i860) /* Alliant FX/2800 */
163 # define LOAD_AVE_TYPE long
164 # endif
165
166 # ifdef _AIX
167 # define LOAD_AVE_TYPE long
168 # endif
169
170 # ifdef convex
171 # define LOAD_AVE_TYPE double
172 # ifndef LDAV_CVT
173 # define LDAV_CVT(n) (n)
174 # endif
175 # endif
176
177 # endif /* No LOAD_AVE_TYPE. */
178
179 # ifdef OSF_ALPHA
180 # undef FSCALE
181 # define FSCALE 1024.0
182 # endif
183
184 # if defined(alliant) && defined(i860) /* Alliant FX/2800 */
185 # undef FSCALE
186 # define FSCALE 100.0
187 # endif
188
189 # ifndef FSCALE
190
191 # ifdef MORE_BSD
192 # define FSCALE 2048.0
193 # endif
194
195 # if defined(MIPS) || defined(SVR4) || defined(decstation)
196 # define FSCALE 256
197 # endif
198
199 # if defined (sgi) || defined (sequent)
200 # undef FSCALE
201 # define FSCALE 1000.0
202 # endif
203
204 # if defined (ardent) && defined (titan)
205 # define FSCALE 65536.0
206 # endif
207
208 # ifdef tek4300
209 # define FSCALE 100.0
210 # endif
211
212 # ifdef _AIX
213 # define FSCALE 65536.0
214 # endif
215
216 # endif /* Not FSCALE. */
217
218 # if !defined (LDAV_CVT) && defined (FSCALE)
219 # define LDAV_CVT(n) (((double) (n)) / FSCALE)
220 # endif
221
222 # ifndef NLIST_STRUCT
223
224 # ifdef MORE_BSD
225 # define NLIST_STRUCT
226 # endif
227
228 # ifdef sun
229 # define NLIST_STRUCT
230 # endif
231
232 # ifdef decstation
233 # define NLIST_STRUCT
234 # endif
235
236 # ifdef hpux
237 # define NLIST_STRUCT
238 # endif
239
240 # if defined (_SEQUENT_) || defined (sequent)
241 # define NLIST_STRUCT
242 # endif
243
244 # ifdef sgi
245 # define NLIST_STRUCT
246 # endif
247
248 # ifdef SVR4
249 # define NLIST_STRUCT
250 # endif
251
252 # ifdef sony_news
253 # define NLIST_STRUCT
254 # endif
255
256 # ifdef OSF_ALPHA
257 # define NLIST_STRUCT
258 # endif
259
260 # if defined (ardent) && defined (titan)
261 # define NLIST_STRUCT
262 # endif
263
264 # ifdef tek4300
265 # define NLIST_STRUCT
266 # endif
267
268 # ifdef butterfly
269 # define NLIST_STRUCT
270 # endif
271
272 # if defined(alliant) && defined(i860) /* Alliant FX/2800 */
273 # define NLIST_STRUCT
274 # endif
275
276 # ifdef _AIX
277 # define NLIST_STRUCT
278 # endif
279
280 # endif /* defined (NLIST_STRUCT) */
281
282 # if defined(sgi) || (defined(mips) && !defined(BSD))
283 # define FIXUP_KERNEL_SYMBOL_ADDR(nl) ((nl)[0].n_value &= ~(1 << 31))
284 # endif
285
286 # if !defined (KERNEL_FILE) && defined (sequent)
287 # define KERNEL_FILE "/dynix"
288 # endif
289
290 # if !defined (KERNEL_FILE) && defined (hpux)
291 # define KERNEL_FILE "/hp-ux"
292 # endif
293
294 # if !defined(KERNEL_FILE) && (defined(_SEQUENT_) || defined(MIPS) || defined(SVR4) || defined(ISC) || defined (sgi) || (defined (ardent) && defined (titan)))
295 # define KERNEL_FILE "/unix"
296 # endif
297
298 # if !defined (LDAV_SYMBOL) && defined (alliant)
299 # define LDAV_SYMBOL "_Loadavg"
300 # endif
301
302 # if !defined(LDAV_SYMBOL) && ((defined(hpux) && !defined(hp9000s300)) || defined(_SEQUENT_) || defined(SVR4) || defined(ISC) || defined(sgi) || (defined (ardent) && defined (titan)) || defined (_AIX))
303 # define LDAV_SYMBOL "avenrun"
304 # endif
305
306 # ifdef HAVE_UNISTD_H
307 # include <unistd.h>
308 # endif
309
310 # include <stdio.h>
311
312 # if !defined(LOAD_AVE_TYPE) && (defined(BSD) || defined(LDAV_CVT) || defined(KERNEL_FILE) || defined(LDAV_SYMBOL))
313 # define LOAD_AVE_TYPE double
314 # endif
315
316 # ifdef LOAD_AVE_TYPE
317
318 # ifndef VMS
319 # ifndef __linux__
320 # ifndef NLIST_STRUCT
321 # include <a.out.h>
322 # else /* NLIST_STRUCT */
323 # include <nlist.h>
324 # endif /* NLIST_STRUCT */
325
326 # ifdef SUNOS_5
327 # include <fcntl.h>
328 # include <kvm.h>
329 # include <kstat.h>
330 # endif
331
332 # if defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC)
333 # include <sys/pstat.h>
334 # endif
335
336 # ifndef KERNEL_FILE
337 # define KERNEL_FILE "/vmunix"
338 # endif /* KERNEL_FILE */
339
340 # ifndef LDAV_SYMBOL
341 # define LDAV_SYMBOL "_avenrun"
342 # endif /* LDAV_SYMBOL */
343 # endif /* __linux__ */
344
345 # else /* VMS */
346
347 # ifndef eunice
348 # include <iodef.h>
349 # include <descrip.h>
350 # else /* eunice */
351 # include <vms/iodef.h>
352 # endif /* eunice */
353 # endif /* VMS */
354
355 # ifndef LDAV_CVT
356 # define LDAV_CVT(n) ((double) (n))
357 # endif /* !LDAV_CVT */
358
359 # endif /* LOAD_AVE_TYPE */
360
361 # if defined(__GNU__) && !defined (NeXT)
362 # define NeXT
363 # define host_self mach_host_self
364 # endif
365
366 # ifdef NeXT
367 # ifdef HAVE_MACH_MACH_H
368 # include <mach/mach.h>
369 # else
370 # include <mach.h>
371 # endif
372 # endif /* NeXT */
373
374 # ifdef sgi
375 # include <sys/sysmp.h>
376 # endif /* sgi */
377
378 # ifdef UMAX
379 # include <stdio.h>
380 # include <signal.h>
381 # include <sys/time.h>
382 # include <sys/wait.h>
383 # include <sys/syscall.h>
384
385 # ifdef UMAX_43
386 # include <machine/cpu.h>
387 # include <inq_stats/statistics.h>
388 # include <inq_stats/sysstats.h>
389 # include <inq_stats/cpustats.h>
390 # include <inq_stats/procstats.h>
391 # else /* Not UMAX_43. */
392 # include <sys/sysdefs.h>
393 # include <sys/statistics.h>
394 # include <sys/sysstats.h>
395 # include <sys/cpudefs.h>
396 # include <sys/cpustats.h>
397 # include <sys/procstats.h>
398 # endif /* Not UMAX_43. */
399 # endif /* UMAX */
400
401 # ifdef DGUX
402 # include <sys/dg_sys_info.h>
403 # endif
404
405 # if defined(HAVE_FCNTL_H) || defined(_POSIX_VERSION)
406 # include <fcntl.h>
407 # else
408 # include <sys/file.h>
409 # endif
410
411 # ifdef NeXT
412 static processor_set_t default_set;
413 static int getloadavg_initialized;
414 # endif /* NeXT */
415
416 # ifdef UMAX
417 static unsigned int cpus = 0;
418 static unsigned int samples;
419 # endif /* UMAX */
420
421 # ifdef DGUX
422 static struct dg_sys_info_load_info load_info; /* what-a-mouthful! */
423 # endif /* DGUX */
424
425 # if !defined(HAVE_LIBKSTAT) && defined(LOAD_AVE_TYPE) && !defined(__linux__)
426 /* File descriptor open to /dev/kmem or VMS load ave driver. */
427 static int channel;
428 /* Nonzero iff channel is valid. */
429 static int getloadavg_initialized;
430 /* Offset in kmem to seek to read load average, or 0 means invalid. */
431 static long offset;
432
433 # if !defined(VMS) && !defined(sgi) && !defined(__linux__)
434 static struct nlist nl[2];
435 # endif /* Not VMS or sgi */
436
437 # ifdef SUNOS_5
438 static kvm_t *kd;
439 # endif /* SUNOS_5 */
440
441 # endif /* LOAD_AVE_TYPE && !HAVE_LIBKSTAT */
442
443 /* Put the 1 minute, 5 minute and 15 minute load averages into the first
444 * NELEM elements of LOADAVG. Return the number written (never more than 3,
445 * but may be less than NELEM), or -1 if an error occurred.
446 */
447
getloadavg(double * loadavg,int nelem)448 static int getloadavg(double *loadavg, int nelem) {
449 int elem = 0; /* Return value. */
450
451 # ifdef NO_GET_LOAD_AVG
452 # define LDAV_DONE
453 /* Set errno to zero to indicate that there was no particular error;
454 this function just can't work at all on this system. */
455 errno = 0;
456 elem = -1;
457 # endif
458
459 # if !defined (LDAV_DONE) && defined (HAVE_LIBKSTAT)
460 /* Use libkstat because we don't have to be root. */
461 # define LDAV_DONE
462 kstat_ctl_t *kc;
463 kstat_t *ksp;
464 kstat_named_t *kn;
465
466 kc = kstat_open ();
467 if (kc == 0)
468 return -1;
469 ksp = kstat_lookup (kc, "unix", 0, "system_misc");
470 if (ksp == 0 )
471 return -1;
472 if (kstat_read (kc, ksp, 0) == -1)
473 return -1;
474
475
476 kn = kstat_data_lookup (ksp, "avenrun_1min");
477 if (kn == 0)
478 {
479 /* Return -1 if no load average information is available. */
480 nelem = 0;
481 elem = -1;
482 }
483
484 if (nelem >= 1)
485 loadavg[elem++] = (double) kn->value.ul/FSCALE;
486
487 if (nelem >= 2)
488 {
489 kn = kstat_data_lookup (ksp, "avenrun_5min");
490 if (kn != 0)
491 {
492 loadavg[elem++] = (double) kn->value.ul/FSCALE;
493
494 if (nelem >= 3)
495 {
496 kn = kstat_data_lookup (ksp, "avenrun_15min");
497 if (kn != 0)
498 loadavg[elem++] = (double) kn->value.ul/FSCALE;
499 }
500 }
501 }
502
503 kstat_close (kc);
504 # endif /* HAVE_LIBKSTAT */
505
506 # if !defined (LDAV_DONE) && defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC)
507 /* Use pstat_getdynamic() because we don't have to be root. */
508 # define LDAV_DONE
509 # undef LOAD_AVE_TYPE
510
511 struct pst_dynamic dyn_info;
512 if (pstat_getdynamic (&dyn_info, sizeof (dyn_info), 0, 0) < 0)
513 return -1;
514 if (nelem > 0)
515 loadavg[elem++] = dyn_info.psd_avg_1_min;
516 if (nelem > 1)
517 loadavg[elem++] = dyn_info.psd_avg_5_min;
518 if (nelem > 2)
519 loadavg[elem++] = dyn_info.psd_avg_15_min;
520
521 # endif /* hpux && HAVE_PSTAT_GETDYNAMIC */
522
523 # if !defined (LDAV_DONE) && defined (__linux__)
524 # define LDAV_DONE
525 # undef LOAD_AVE_TYPE
526
527 # ifndef LINUX_LDAV_FILE
528 # define LINUX_LDAV_FILE "/proc/loadavg"
529 # endif
530
531 char ldavgbuf[40];
532 double load_ave[3];
533 int fd, count;
534
535 fd = open (LINUX_LDAV_FILE, O_RDONLY);
536 if (fd == -1)
537 return -1;
538 count = read (fd, ldavgbuf, 40);
539 (void) close (fd);
540 if (count <= 0)
541 return -1;
542
543 count = sscanf (ldavgbuf, "%lf %lf %lf",
544 &load_ave[0], &load_ave[1], &load_ave[2]);
545 if (count < 1)
546 return -1;
547
548 for (elem = 0; elem < nelem && elem < count; elem++)
549 loadavg[elem] = load_ave[elem];
550
551 return elem;
552
553 # endif /* __linux__ */
554
555 # if !defined (LDAV_DONE) && defined (__NetBSD__)
556 # define LDAV_DONE
557 # undef LOAD_AVE_TYPE
558
559 # ifndef NETBSD_LDAV_FILE
560 # define NETBSD_LDAV_FILE "/kern/loadavg"
561 # endif
562
563 unsigned long int load_ave[3], scale;
564 int count;
565 FILE *fp;
566
567 fp = fopen (NETBSD_LDAV_FILE, "r");
568 if (fp == NULL)
569 return -1;
570 count = fscanf (fp, "%lu %lu %lu %lu\n",
571 &load_ave[0], &load_ave[1], &load_ave[2],
572 &scale);
573 (void) fclose (fp);
574 if (count != 4)
575 return -1;
576
577 for (elem = 0; elem < nelem; elem++)
578 loadavg[elem] = (double) load_ave[elem] / (double) scale;
579
580 return elem;
581
582 # endif /* __NetBSD__ */
583
584 # if !defined (LDAV_DONE) && defined (NeXT)
585 # define LDAV_DONE
586 /* The NeXT code was adapted from iscreen 3.2. */
587
588 host_t host;
589 struct processor_set_basic_info info;
590 unsigned info_count;
591
592 /* We only know how to get the 1-minute average for this system,
593 so even if the caller asks for more than 1, we only return 1. */
594
595 if (!getloadavg_initialized)
596 {
597 if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS)
598 getloadavg_initialized = 1;
599 }
600
601 if (getloadavg_initialized)
602 {
603 info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
604 if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host,
605 (processor_set_info_t) &info, &info_count)
606 != KERN_SUCCESS)
607 getloadavg_initialized = 0;
608 else
609 {
610 if (nelem > 0)
611 loadavg[elem++] = (double) info.load_average / LOAD_SCALE;
612 }
613 }
614
615 if (!getloadavg_initialized)
616 return -1;
617 # endif /* NeXT */
618
619 # if !defined (LDAV_DONE) && defined (UMAX)
620 # define LDAV_DONE
621 /* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not
622 have a /dev/kmem. Information about the workings of the running kernel
623 can be gathered with inq_stats system calls.
624 We only know how to get the 1-minute average for this system. */
625
626 struct proc_summary proc_sum_data;
627 struct stat_descr proc_info;
628 double load;
629 register unsigned int i, j;
630
631 if (cpus == 0)
632 {
633 register unsigned int c, i;
634 struct cpu_config conf;
635 struct stat_descr desc;
636
637 desc.sd_next = 0;
638 desc.sd_subsys = SUBSYS_CPU;
639 desc.sd_type = CPUTYPE_CONFIG;
640 desc.sd_addr = (char *) &conf;
641 desc.sd_size = sizeof conf;
642
643 if (inq_stats (1, &desc))
644 return -1;
645
646 c = 0;
647 for (i = 0; i < conf.config_maxclass; ++i)
648 {
649 struct class_stats stats;
650 bzero ((char *) &stats, sizeof stats);
651
652 desc.sd_type = CPUTYPE_CLASS;
653 desc.sd_objid = i;
654 desc.sd_addr = (char *) &stats;
655 desc.sd_size = sizeof stats;
656
657 if (inq_stats (1, &desc))
658 return -1;
659
660 c += stats.class_numcpus;
661 }
662 cpus = c;
663 samples = cpus < 2 ? 3 : (2 * cpus / 3);
664 }
665
666 proc_info.sd_next = 0;
667 proc_info.sd_subsys = SUBSYS_PROC;
668 proc_info.sd_type = PROCTYPE_SUMMARY;
669 proc_info.sd_addr = (char *) &proc_sum_data;
670 proc_info.sd_size = sizeof (struct proc_summary);
671 proc_info.sd_sizeused = 0;
672
673 if (inq_stats (1, &proc_info) != 0)
674 return -1;
675
676 load = proc_sum_data.ps_nrunnable;
677 j = 0;
678 for (i = samples - 1; i > 0; --i)
679 {
680 load += proc_sum_data.ps_nrun[j];
681 if (j++ == PS_NRUNSIZE)
682 j = 0;
683 }
684
685 if (nelem > 0)
686 loadavg[elem++] = load / samples / cpus;
687 # endif /* UMAX */
688
689 # if !defined (LDAV_DONE) && defined (DGUX)
690 # define LDAV_DONE
691 /* This call can return -1 for an error, but with good args
692 it's not supposed to fail. The first argument is for no
693 apparent reason of type `long int *'. */
694 dg_sys_info ((long int *) &load_info,
695 DG_SYS_INFO_LOAD_INFO_TYPE,
696 DG_SYS_INFO_LOAD_VERSION_0);
697
698 if (nelem > 0)
699 loadavg[elem++] = load_info.one_minute;
700 if (nelem > 1)
701 loadavg[elem++] = load_info.five_minute;
702 if (nelem > 2)
703 loadavg[elem++] = load_info.fifteen_minute;
704 # endif /* DGUX */
705
706 # if !defined (LDAV_DONE) && defined (apollo)
707 # define LDAV_DONE
708 /* Apollo code from lisch@mentorg.com (Ray Lischner).
709
710 This system call is not documented. The load average is obtained as
711 three long integers, for the load average over the past minute,
712 five minutes, and fifteen minutes. Each value is a scaled integer,
713 with 16 bits of integer part and 16 bits of fraction part.
714
715 I'm not sure which operating system first supported this system call,
716 but I know that SR10.2 supports it. */
717
718 extern void proc1_$get_loadav ();
719 unsigned long load_ave[3];
720
721 proc1_$get_loadav (load_ave);
722
723 if (nelem > 0)
724 loadavg[elem++] = load_ave[0] / 65536.0;
725 if (nelem > 1)
726 loadavg[elem++] = load_ave[1] / 65536.0;
727 if (nelem > 2)
728 loadavg[elem++] = load_ave[2] / 65536.0;
729 # endif /* apollo */
730
731 # if !defined (LDAV_DONE) && defined (OSF_MIPS)
732 # define LDAV_DONE
733
734 struct tbl_loadavg load_ave;
735 table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
736 loadavg[elem++]
737 = (load_ave.tl_lscale == 0
738 ? load_ave.tl_avenrun.d[0]
739 : (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale));
740 # endif /* OSF_MIPS */
741
742 # if !defined (LDAV_DONE) && (defined (__MSDOS__) || defined (WINDOWS32))
743 # define LDAV_DONE
744
745 /* A faithful emulation is going to have to be saved for a rainy day. */
746 for ( ; elem < nelem; elem++)
747 {
748 loadavg[elem] = 0.0;
749 }
750 # endif /* __MSDOS__ || WINDOWS32 */
751
752 # if !defined (LDAV_DONE) && defined (OSF_ALPHA)
753 # define LDAV_DONE
754
755 struct tbl_loadavg load_ave;
756 table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
757 for (elem = 0; elem < nelem; elem++)
758 loadavg[elem]
759 = (load_ave.tl_lscale == 0
760 ? load_ave.tl_avenrun.d[elem]
761 : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale));
762 # endif /* OSF_ALPHA */
763
764 # if !defined (LDAV_DONE) && defined (VMS)
765 /* VMS specific code -- read from the Load Ave driver. */
766
767 LOAD_AVE_TYPE load_ave[3];
768 static int getloadavg_initialized = 0;
769 # ifdef eunice
770 struct
771 {
772 int dsc$w_length;
773 char *dsc$a_pointer;
774 } descriptor;
775 # endif
776
777 /* Ensure that there is a channel open to the load ave device. */
778 if (!getloadavg_initialized)
779 {
780 /* Attempt to open the channel. */
781 # ifdef eunice
782 descriptor.dsc$w_length = 18;
783 descriptor.dsc$a_pointer = "$$VMS_LOAD_AVERAGE";
784 # else
785 $DESCRIPTOR (descriptor, "LAV0:");
786 # endif
787 if (sys$assign (&descriptor, &channel, 0, 0) & 1)
788 getloadavg_initialized = 1;
789 }
790
791 /* Read the load average vector. */
792 if (getloadavg_initialized
793 && !(sys$qiow (0, channel, IO$_READVBLK, 0, 0, 0,
794 load_ave, 12, 0, 0, 0, 0) & 1))
795 {
796 sys$dassgn (channel);
797 getloadavg_initialized = 0;
798 }
799
800 if (!getloadavg_initialized)
801 return -1;
802 # endif /* VMS */
803
804 # if !defined (LDAV_DONE) && defined(LOAD_AVE_TYPE) && !defined(VMS)
805
806 /* UNIX-specific code -- read the average from /dev/kmem. */
807
808 # define LDAV_PRIVILEGED /* This code requires special installation. */
809
810 LOAD_AVE_TYPE load_ave[3];
811
812 /* Get the address of LDAV_SYMBOL. */
813 if (offset == 0)
814 {
815 # ifndef sgi
816 # ifndef NLIST_STRUCT
817 strcpy (nl[0].n_name, LDAV_SYMBOL);
818 strcpy (nl[1].n_name, "");
819 # else /* NLIST_STRUCT */
820 # ifdef NLIST_NAME_UNION
821 nl[0].n_un.n_name = LDAV_SYMBOL;
822 nl[1].n_un.n_name = 0;
823 # else /* not NLIST_NAME_UNION */
824 nl[0].n_name = LDAV_SYMBOL;
825 nl[1].n_name = 0;
826 # endif /* not NLIST_NAME_UNION */
827 # endif /* NLIST_STRUCT */
828
829 # ifndef SUNOS_5
830 if (
831 # if !(defined (_AIX) && !defined (ps2))
832 nlist (KERNEL_FILE, nl)
833 # else /* _AIX */
834 knlist (nl, 1, sizeof (nl[0]))
835 # endif
836 >= 0)
837 /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i. */
838 {
839 # ifdef FIXUP_KERNEL_SYMBOL_ADDR
840 FIXUP_KERNEL_SYMBOL_ADDR (nl);
841 # endif
842 offset = nl[0].n_value;
843 }
844 # endif /* !SUNOS_5 */
845 # else /* sgi */
846 int ldav_off;
847
848 ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN);
849 if (ldav_off != -1)
850 offset = (long) ldav_off & 0x7fffffff;
851 # endif /* sgi */
852 }
853
854 /* Make sure we have /dev/kmem open. */
855 if (!getloadavg_initialized)
856 {
857 # ifndef SUNOS_5
858 channel = open ("/dev/kmem", 0);
859 if (channel >= 0)
860 {
861 /* Set the channel to close on exec, so it does not
862 litter any child's descriptor table. */
863 # ifdef F_SETFD
864 # ifndef FD_CLOEXEC
865 # define FD_CLOEXEC 1
866 # endif
867 (void) fcntl (channel, F_SETFD, FD_CLOEXEC);
868 # endif
869 getloadavg_initialized = 1;
870 }
871 # else /* SUNOS_5 */
872 /* We pass 0 for the kernel, corefile, and swapfile names
873 to use the currently running kernel. */
874 kd = kvm_open (0, 0, 0, O_RDONLY, 0);
875 if (kd != 0)
876 {
877 /* nlist the currently running kernel. */
878 kvm_nlist (kd, nl);
879 offset = nl[0].n_value;
880 getloadavg_initialized = 1;
881 }
882 # endif /* SUNOS_5 */
883 }
884
885 /* If we can, get the load average values. */
886 if (offset && getloadavg_initialized)
887 {
888 /* Try to read the load. */
889 # ifndef SUNOS_5
890 if (lseek (channel, offset, 0) == -1L
891 || read (channel, (char *) load_ave, sizeof (load_ave))
892 != sizeof (load_ave))
893 {
894 close (channel);
895 getloadavg_initialized = 0;
896 }
897 # else /* SUNOS_5 */
898 if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave))
899 != sizeof (load_ave))
900 {
901 kvm_close (kd);
902 getloadavg_initialized = 0;
903 }
904 # endif /* SUNOS_5 */
905 }
906
907 if (offset == 0 || !getloadavg_initialized)
908 return -1;
909 # endif /* LOAD_AVE_TYPE and not VMS */
910
911 # if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) /* Including VMS. */
912 if (nelem > 0)
913 loadavg[elem++] = LDAV_CVT (load_ave[0]);
914 if (nelem > 1)
915 loadavg[elem++] = LDAV_CVT (load_ave[1]);
916 if (nelem > 2)
917 loadavg[elem++] = LDAV_CVT (load_ave[2]);
918
919 # define LDAV_DONE
920 # endif /* !LDAV_DONE && LOAD_AVE_TYPE */
921
922 # ifdef LDAV_DONE
923 return elem;
924 # else
925 /* Set errno to zero to indicate that there was no particular error;
926 this function just can't work at all on this system. */
927 errno = 0;
928 return -1;
929 # endif
930 }
931
932 #endif /* !HAVE_GETLOADAVG */
933
934 module load_module;
935
load_get_system_load(void)936 static double load_get_system_load(void) {
937 int res;
938 double loadavg = -1.0;
939
940 /* It is necessary on some platforms (such as Solaris) to have root
941 * privs when doing this, as the information is determined by reading
942 * the image of the running kernel (yikes!)
943 */
944 PRIVS_ROOT
945 res = getloadavg(&loadavg, 1);
946 PRIVS_RELINQUISH
947
948 /* Return the default value if we did not receive the expected number
949 * of elements from getloadavg().
950 */
951 if (res != 1)
952 return -1.0;
953
954 return loadavg;
955 }
956
957 /* Configuration handlers
958 */
959
960 /* usage: MaxLoad max [mesg] */
set_maxload(cmd_rec * cmd)961 MODRET set_maxload(cmd_rec *cmd) {
962 double loadval = 0.0;
963 config_rec *c = NULL;
964
965 if (cmd->argc-1 < 1 || cmd->argc-1 > 2)
966 CONF_ERROR(cmd, "incorrect number of parameters");
967
968 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
969
970 if (strcasecmp(cmd->argv[1], "none") == 0)
971 loadval = -1.0;
972 else {
973 loadval = atof(cmd->argv[1]);
974 if (loadval < 0.0)
975 CONF_ERROR(cmd, "positive load limit required");
976 }
977
978 c = add_config_param(cmd->argv[0], cmd->argc-1, NULL);
979 c->argv[0] = pcalloc(c->pool, sizeof(double));
980
981 if (loadval < 0.0)
982 c->argv[0] = NULL;
983
984 else
985 *((double *) c->argv[0]) = loadval;
986
987 if (cmd->argc-1 == 2) {
988 c->argv[1] = pcalloc(c->pool, sizeof(char *));
989 c->argv[1] = pstrdup(c->pool, cmd->argv[2]);
990 }
991
992 return PR_HANDLED(cmd);
993 }
994
995 /* Initialization functions
996 */
997
load_sess_init(void)998 static int load_sess_init(void) {
999 config_rec *c = NULL;
1000 double max_load = 0.0, curr_load = 0.0;
1001 char curr_load_str[16], max_load_str[16];
1002
1003 /* Lookup any configured load limit. */
1004 c = find_config(main_server->conf, CONF_PARAM, "MaxLoad", FALSE);
1005 if (!c)
1006 return 0;
1007
1008 /* If the config_rec is present, but argv[0] is NULL, do nothing */
1009 if (!c->argv[0])
1010 return 0;
1011 max_load = *((double *) c->argv[0]);
1012
1013 curr_load = load_get_system_load();
1014 if (curr_load < 0) {
1015 pr_log_pri(PR_LOG_NOTICE,
1016 "notice: unable to determine system load average: %s", strerror(errno));
1017 return 0;
1018 }
1019
1020 pr_log_debug(DEBUG5, MOD_LOAD_VERSION ": current system load: %.2f",
1021 curr_load);
1022
1023 if (curr_load >= max_load) {
1024 pr_log_pri(PR_LOG_NOTICE, MOD_LOAD_VERSION
1025 ": MaxLoad (%.2f) reached: connection denied", max_load);
1026
1027 if (c->argc == 2) {
1028 pr_response_send(R_421, "%s", (const char *) c->argv[1]);
1029
1030 } else {
1031 pr_response_send(R_421, _("System busy, try again later"));
1032 }
1033
1034 pr_session_disconnect(&load_module, PR_SESS_DISCONNECT_MODULE_ACL,
1035 "MaxLoad");
1036 }
1037
1038 /* Register some Variable entries for showing the system load. */
1039 memset(curr_load_str, '\0', sizeof(curr_load_str));
1040 pr_snprintf(curr_load_str, sizeof(curr_load_str)-1, "%.2f", curr_load);
1041 if (pr_var_set(session.pool, "%{mod_load.curr_load}",
1042 "Current system load average", PR_VAR_TYPE_STR, curr_load_str, NULL,
1043 0) < 0) {
1044 pr_log_debug(DEBUG1, MOD_LOAD_VERSION
1045 ": error setting %%{mod_load.curr_load} variable: %s", strerror(errno));
1046 }
1047
1048 memset(max_load_str, '\0', sizeof(max_load_str));
1049 pr_snprintf(max_load_str, sizeof(max_load_str)-1, "%.2f", max_load);
1050 if (pr_var_set(session.pool, "%{mod_load.max_load}",
1051 "Maximum system load average", PR_VAR_TYPE_STR, max_load_str, NULL,
1052 0) < 0) {
1053 pr_log_debug(DEBUG1, MOD_LOAD_VERSION
1054 ": error setting %%{mod_load.max_load} variable: %s", strerror(errno));
1055 }
1056
1057 return 0;
1058 }
1059
1060 /* Module API tables
1061 */
1062
1063 static conftable load_conftab[] = {
1064 { "MaxLoad", set_maxload, NULL },
1065 { NULL }
1066 };
1067
1068 module load_module = {
1069 NULL, NULL,
1070
1071 /* Module API version 2.0 */
1072 0x20,
1073
1074 /* Module name */
1075 "load",
1076
1077 /* Module configuration handler table */
1078 load_conftab,
1079
1080 /* Module command table */
1081 NULL,
1082
1083 /* Module authentication handler table */
1084 NULL,
1085
1086 /* Module initialization function */
1087 NULL,
1088
1089 /* Session initialization function */
1090 load_sess_init,
1091
1092 /* Module version */
1093 MOD_LOAD_VERSION
1094 };
1095