]> granicus.if.org Git - sysstat/blob - systest.c
Merge pull request from GHSA-q8r6-g56f-9w7x
[sysstat] / systest.c
1 /*
2  * sysstat test functions.
3  * (C) 2019-2022 by Sebastien GODARD (sysstat <at> orange.fr)
4  *
5  ***************************************************************************
6  * This program is free software; you can redistribute it and/or modify it *
7  * under the terms of the GNU General Public License as published  by  the *
8  * Free Software Foundation; either version 2 of the License, or (at  your *
9  * option) any later version.                                              *
10  *                                                                         *
11  * This program is distributed in the hope that it  will  be  useful,  but *
12  * WITHOUT ANY WARRANTY; without the implied warranty  of  MERCHANTABILITY *
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
14  * for more details.                                                       *
15  *                                                                         *
16  * You should have received a copy of the GNU General Public License along *
17  * with this program; if not, write to the Free Software Foundation, Inc., *
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA              *
19  ***************************************************************************
20  */
21
22 #ifdef TEST
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <time.h>
29 #include <unistd.h>
30 #include <dirent.h>
31 #include <pwd.h>
32 #include <sys/stat.h>
33 #include <sys/utsname.h>
34 #include <sys/statvfs.h>
35 #include <sys/time.h>
36 #include <sys/types.h>
37
38 #include "systest.h"
39
40 time_t __unix_time = 0;
41 int __env = 0;
42
43 extern long interval;
44 extern int sigint_caught;
45
46 /*
47  ***************************************************************************
48  * Test mode: Instead of reading system time, use time given on the command
49  * line.
50  *
51  * RETURNS:
52  * Number of seconds since the epoch, as given on the command line.
53  ***************************************************************************
54  */
55 time_t get_unix_time(time_t *t)
56 {
57         return __unix_time;
58 }
59
60 /*
61  ***************************************************************************
62  * Test mode: Get time of the day using __unix_time variable contents.
63  *
64  * OUT:
65  * @tv  Number of seconds since the Epoch.
66  ***************************************************************************
67  */
68 void get_day_time(struct timeval *tv)
69 {
70         __unix_time += interval;
71         tv->tv_sec = __unix_time;
72         tv->tv_usec = 0;
73 }
74
75 /*
76  ***************************************************************************
77  * Test mode: Send bogus information about current kernel.
78  *
79  * OUT:
80  * @h   Structure with kernel information.
81  ***************************************************************************
82  */
83 void get_uname(struct utsname *h)
84 {
85         strcpy(h->sysname, "Linux");
86         strcpy(h->nodename, "SYSSTAT.TEST");
87         strcpy(h->release, "1.2.3-TEST");
88         strcpy(h->machine, "x86_64");
89 }
90
91 /*
92  ***************************************************************************
93  * Test mode: Send bogus information about current filesystem.
94  *
95  * OUT:
96  * @buf Structure with filesystem information.
97  ***************************************************************************
98  */
99 int get_fs_stat(char *c, struct statvfs *buf)
100 {
101         static int p = 0;
102         /*
103          * f_bfree, f_blocks and f_bavail used to be unsigned long.
104          * So don't use values greater then UINT_MAX to make sure that values
105          * won't overflow on 32-bit systems.
106          */
107         unsigned long long bfree[4]  = {739427840, 286670336, 1696156672, 2616732672};
108         unsigned long long blocks[4] = {891291136, 502345216, 1829043712, 3502345216};
109         unsigned long long bavail[4] = {722675712, 241253120, 1106515456, 1871315456};
110         unsigned long long files[4]  = {6111232, 19202048, 1921360, 19202048};
111         unsigned long long ffree[4]  = {6008414, 19201593, 1621550, 19051710};
112
113         buf->f_bfree = bfree[p];
114         buf->f_blocks = blocks[p];
115         buf->f_bavail = bavail[p];
116         buf->f_frsize = 1;
117         buf->f_files = files[p];
118         buf->f_ffree = ffree[p];
119
120         p = (p + 1) & 0x3;
121
122         return 0;
123 }
124
125 /*
126  ***************************************************************************
127  * Test mode: Ignore environment variable value.
128  ***************************************************************************
129  */
130 char *get_env_value(const char *c)
131 {
132         if (!__env)
133                 return NULL;
134
135         fprintf(stderr, "Reading contents of %s\n", c);
136         return getenv(c);
137 }
138
139 /*
140  ***************************************************************************
141  * Test mode: Go to next time period.
142  ***************************************************************************
143  */
144 void next_time_step(void)
145 {
146         int root_nr = 1;
147         char rootf[64], testf[128];
148         char *resolved_name;
149
150         __unix_time += interval;
151
152         /* Get root directory name (root1, root2, etc.) at which the "root" symlink points */
153         if ((resolved_name = realpath(ROOTDIR, NULL)) != NULL) {
154                 if (strlen(resolved_name) > 4) {
155                         /* Set root_nr to the root directory number (1, 2, etc.) */
156                         root_nr = atoi(resolved_name + strlen(resolved_name) - 1);
157                 }
158                 free(resolved_name);
159         }
160         if ((unlink(ROOTDIR) < 0) && (errno != ENOENT)) {
161                 perror("unlink");
162                 exit(1);
163         }
164
165         /* Set next root directory name (root2, root3, etc.). Directories like root1b are unreachable */
166         snprintf(rootf, sizeof(rootf), "%s%d", ROOTFILE, ++root_nr);
167         rootf[sizeof(rootf) - 1] = '\0';
168         snprintf(testf, sizeof(testf), "%s/%s", TESTDIR, rootf);
169         testf[sizeof(testf) - 1] = '\0';
170
171         /* Make sure that new root directory exists */
172         if (access(testf, F_OK) < 0) {
173                 if (errno == ENOENT) {
174                         /* No more root directories: Simulate a Ctrl/C */
175                         int_handler(0);
176                         return;
177                 }
178         }
179
180         /* Create "root" symlink pointing at the new root directory */
181         if (symlink(rootf, ROOTDIR) < 0) {
182                 perror("link");
183                 exit(1);
184         }
185 }
186
187 /*
188  ***************************************************************************
189  * If current file is considered as a virtual one ("virtualhd"), then set
190  * its device ID (major 253, minor 2, corresponding here to dm-2) in the
191  * stat structure normally filled by the stat() system call.
192  * Otherwise, open file and read its major and minor numbers.
193  *
194  * IN:
195  * @name        Pathname to file.
196  *
197  * OUT:
198  * @statbuf     Structure containing device ID.
199  *
200  * RETURNS:
201  * 0 if it actually was the virtual device, 1 otherwise, and -1 on failure.
202  ***************************************************************************
203  */
204 int virtual_stat(const char *name, struct stat *statbuf)
205 {
206         FILE *fp;
207         char line[128];
208         int major, minor;
209
210         if (!strcmp(name, VIRTUALHD)) {
211                 statbuf->st_rdev = (253 << MINORBITS) + 2;
212                 return 0;
213         }
214
215         statbuf->st_rdev = 0;
216
217         if ((fp = fopen(name, "r")) == NULL)
218                 return -1;
219
220         if (fgets(line, sizeof(line), fp) != NULL) {
221                 sscanf(line, "%d %d", &major, &minor);
222                 statbuf->st_rdev = (major << MINORBITS) + minor;
223         }
224
225         fclose(fp);
226
227         return 1;
228 }
229
230 /*
231  ***************************************************************************
232  * Open a "_list" file containing a list of files enumerated in a known
233  * order contained in current directory.
234  *
235  * IN:
236  * @name        Pathname to directory containing the "_list" file.
237  *
238  * RETURNS:
239  * A pointer on current "_list" file.
240  ***************************************************************************
241  */
242 DIR *open_list(const char *name)
243 {
244         FILE *fp;
245         char filename[1024];
246
247         snprintf(filename, sizeof(filename), "%s/%s", name, _LIST);
248         filename[sizeof(filename) - 1] = '\0';
249
250         if ((fp = fopen(filename, "r")) == NULL)
251                 return NULL;
252
253         return (DIR *) fp;
254 }
255
256 /*
257  ***************************************************************************
258  * Read next file name contained in a "_list" file.
259  *
260  * IN:
261  * @dir Pointer on current "_list" file.
262  *
263  * RETURNS:
264  * A structure containing the name of the next file to read.
265  ***************************************************************************
266  */
267 struct dirent *read_list(DIR *dir)
268 {
269         FILE *fp = (FILE *) dir;
270         static struct dirent drd;
271         char line[1024];
272
273
274         if ((fgets(line, sizeof(line), fp) != NULL) && (strlen(line) > 1) &&
275                 (strlen(line) < sizeof(drd.d_name))) {
276                 strcpy(drd.d_name, line);
277                 drd.d_name[strlen(line) - 1] = '\0';
278                 return &drd;
279         }
280
281         return NULL;
282 }
283
284 /*
285  ***************************************************************************
286  * Close a "_list" file.
287  *
288  * IN:
289  * @dir Pointer on "_list" file to close.
290  ***************************************************************************
291  */
292 void close_list(DIR *dir)
293 {
294         FILE *fp = (FILE *) dir;
295
296         fclose(fp);
297 }
298
299 /*
300  ***************************************************************************
301  * Replacement function for realpath() system call. Do nothing here.
302  *
303  * IN:
304  * @name        Pathname to process.
305  * @c           Unused here.
306  *
307  * RETURNS:
308  * Pathname (unchanged).
309  ***************************************************************************
310  */
311 char *get_realname(char *name, char *c)
312 {
313         char *resolved_name;
314
315         if ((resolved_name = (char *) malloc(1024)) == NULL) {
316                 perror("malloc");
317                 exit(4);
318         }
319         strncpy(resolved_name, name, 1024);
320         resolved_name[1023] = '\0';
321
322         return resolved_name;
323 }
324
325 /*
326  ***************************************************************************
327  * Replacement function for getpwuid() system call. Fill a dummy passwd
328  * structure containing the name of a user.
329  *
330  * IN:
331  * @uid         UID of the user
332  *
333  * RETURNS:
334  * Pointer on the passwd structure.
335  ***************************************************************************
336  */
337 struct passwd *get_usrname(uid_t uid)
338 {
339         static struct passwd pwd_ent;
340         static char pw_name[16];
341
342         pwd_ent.pw_name = pw_name;
343         if (!uid) {
344                 strcpy(pwd_ent.pw_name, "root");
345         }
346         else {
347                 strcpy(pwd_ent.pw_name, "testusr");
348         }
349
350         return &pwd_ent;
351 }
352
353 /*
354  ***************************************************************************
355  * Replacement function for fork() system call. Don't fork really but return
356  * a known PID number.
357  *
358  * RETURNS:
359  * Known PID number.
360  ***************************************************************************
361  */
362 pid_t get_known_pid(void)
363 {
364         return 8741;
365 }
366
367 #endif  /* TEST */
368