Merge pull request #2044 from RincewindsHat/fix/fedora-rpm-build
[monitoring-plugins.git] / plugins / check_users.c
blobf1e1c39d850b4846bafc9be8fbc135811f1d9365
1 /*****************************************************************************
3 * Monitoring check_users plugin
5 * License: GPL
6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
8 * Description:
10 * This file contains the check_users plugin
12 * This plugin checks the number of users currently logged in on the local
13 * system and generates an error if the number exceeds the thresholds
14 * specified.
17 * This program is free software: you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation, either version 3 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 *****************************************************************************/
33 const char *progname = "check_users";
34 const char *copyright = "2000-2024";
35 const char *email = "devel@monitoring-plugins.org";
37 #include "common.h"
38 #include "utils.h"
40 #if HAVE_WTSAPI32_H
41 # include <windows.h>
42 # include <wtsapi32.h>
43 # undef ERROR
44 # define ERROR -1
45 #elif HAVE_UTMPX_H
46 # include <utmpx.h>
47 #else
48 # include "popen.h"
49 #endif
51 #ifdef HAVE_LIBSYSTEMD
52 # include <systemd/sd-daemon.h>
53 # include <systemd/sd-login.h>
54 #endif
56 #define possibly_set(a, b) ((a) == 0 ? (b) : 0)
58 static int process_arguments(int, char **);
59 static void print_help(void);
60 void print_usage(void);
62 static char *warning_range = NULL;
63 static char *critical_range = NULL;
64 static thresholds *thlds = NULL;
66 int main(int argc, char **argv) {
67 int users = -1;
68 int result = STATE_UNKNOWN;
69 #if HAVE_WTSAPI32_H
70 WTS_SESSION_INFO *wtsinfo;
71 DWORD wtscount;
72 DWORD index;
73 #elif HAVE_UTMPX_H
74 struct utmpx *putmpx;
75 #else
76 char input_buffer[MAX_INPUT_BUFFER];
77 #endif
79 setlocale(LC_ALL, "");
80 bindtextdomain(PACKAGE, LOCALEDIR);
81 textdomain(PACKAGE);
83 /* Parse extra opts if any */
84 argv = np_extra_opts(&argc, argv, progname);
86 if (process_arguments(argc, argv) == ERROR)
87 usage4(_("Could not parse arguments"));
89 users = 0;
91 #ifdef HAVE_LIBSYSTEMD
92 if (sd_booted() > 0)
93 users = sd_get_sessions(NULL);
94 else {
95 #endif
96 #if HAVE_WTSAPI32_H
97 if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &wtsinfo, &wtscount)) {
98 printf(_("Could not enumerate RD sessions: %d\n"), GetLastError());
99 return STATE_UNKNOWN;
102 for (index = 0; index < wtscount; index++) {
103 LPTSTR username;
104 DWORD size;
105 int len;
107 if (!WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, wtsinfo[index].SessionId, WTSUserName, &username, &size))
108 continue;
110 len = lstrlen(username);
112 WTSFreeMemory(username);
114 if (len == 0)
115 continue;
117 if (wtsinfo[index].State == WTSActive || wtsinfo[index].State == WTSDisconnected)
118 users++;
121 WTSFreeMemory(wtsinfo);
122 #elif HAVE_UTMPX_H
123 /* get currently logged users from utmpx */
124 setutxent();
126 while ((putmpx = getutxent()) != NULL)
127 if (putmpx->ut_type == USER_PROCESS)
128 users++;
130 endutxent();
131 #else
132 /* run the command */
133 child_process = spopen(WHO_COMMAND);
134 if (child_process == NULL) {
135 printf(_("Could not open pipe: %s\n"), WHO_COMMAND);
136 return STATE_UNKNOWN;
139 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
140 if (child_stderr == NULL)
141 printf(_("Could not open stderr for %s\n"), WHO_COMMAND);
143 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
144 /* increment 'users' on all lines except total user count */
145 if (input_buffer[0] != '#') {
146 users++;
147 continue;
150 /* get total logged in users */
151 if (sscanf(input_buffer, _("# users=%d"), &users) == 1)
152 break;
155 /* check STDERR */
156 if (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr))
157 result = possibly_set(result, STATE_UNKNOWN);
158 (void)fclose(child_stderr);
160 /* close the pipe */
161 if (spclose(child_process))
162 result = possibly_set(result, STATE_UNKNOWN);
163 #endif
164 #ifdef HAVE_LIBSYSTEMD
166 #endif
168 /* check the user count against warning and critical thresholds */
169 result = get_status((double)users, thlds);
171 if (result == STATE_UNKNOWN)
172 printf("%s\n", _("Unable to read output"));
173 else {
174 printf(_("USERS %s - %d users currently logged in |%s\n"), state_text(result), users,
175 sperfdata_int("users", users, "", warning_range, critical_range, true, 0, false, 0));
178 return result;
181 /* process command-line arguments */
182 int process_arguments(int argc, char **argv) {
183 static struct option longopts[] = {{"critical", required_argument, 0, 'c'},
184 {"warning", required_argument, 0, 'w'},
185 {"version", no_argument, 0, 'V'},
186 {"help", no_argument, 0, 'h'},
187 {0, 0, 0, 0}};
189 if (argc < 2)
190 usage("\n");
192 int option_char;
193 while (true) {
194 int option = 0;
195 option_char = getopt_long(argc, argv, "+hVvc:w:", longopts, &option);
197 if (option_char == -1 || option_char == EOF || option_char == 1)
198 break;
200 switch (option_char) {
201 case '?': /* print short usage statement if args not parsable */
202 usage5();
203 case 'h': /* help */
204 print_help();
205 exit(STATE_UNKNOWN);
206 case 'V': /* version */
207 print_revision(progname, NP_VERSION);
208 exit(STATE_UNKNOWN);
209 case 'c': /* critical */
210 critical_range = optarg;
211 break;
212 case 'w': /* warning */
213 warning_range = optarg;
214 break;
218 option_char = optind;
220 if (warning_range == NULL && argc > option_char)
221 warning_range = argv[option_char++];
223 if (critical_range == NULL && argc > option_char)
224 critical_range = argv[option_char++];
226 /* this will abort in case of invalid ranges */
227 set_thresholds(&thlds, warning_range, critical_range);
229 if (!thlds->warning) {
230 usage4(_("Warning threshold must be a valid range expression"));
233 if (!thlds->critical) {
234 usage4(_("Critical threshold must be a valid range expression"));
237 return OK;
240 void print_help(void) {
241 print_revision(progname, NP_VERSION);
243 printf("Copyright (c) 1999 Ethan Galstad\n");
244 printf(COPYRIGHT, copyright, email);
246 printf("%s\n", _("This plugin checks the number of users currently logged in on the local"));
247 printf("%s\n", _("system and generates an error if the number exceeds the thresholds specified."));
249 printf("\n\n");
251 print_usage();
253 printf(UT_HELP_VRSN);
254 printf(UT_EXTRA_OPTS);
256 printf(" %s\n", "-w, --warning=RANGE_EXPRESSION");
257 printf(" %s\n", _("Set WARNING status if number of logged in users violates RANGE_EXPRESSION"));
258 printf(" %s\n", "-c, --critical=RANGE_EXPRESSION");
259 printf(" %s\n", _("Set CRITICAL status if number of logged in users violates RANGE_EXPRESSION"));
261 printf(UT_SUPPORT);
264 void print_usage(void) {
265 printf("%s\n", _("Usage:"));
266 printf("%s -w <users> -c <users>\n", progname);