xref: /minix3/minix/tests/common.c (revision 7c48de6cc4c6d56f2277d378dba01dbac8a8c3b9)
1 /* Utility routines for Minix tests.
2  * This is designed to be #includ'ed near the top of test programs.  It is
3  * self-contained except for max_error.
4  */
5 
6 #include <errno.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <stdarg.h>
11 #include <stdio.h>
12 #include <sys/statvfs.h>
13 #include <sys/syslimits.h>
14 
15 #include "common.h"
16 
17 int common_test_nr = -1, errct = 0, subtest;
18 int quietflag = 1, bigflag = 0;
19 
20 /* provide a default max_error symbol as Max_error with a value
21  * of 5. The test program can override it wit its own max_error
22  * symbol if it wants that this code will then use instead.
23  */
24 __weak_alias(max_error,Max_error);
25 int Max_error = 5;
26 extern int max_error;
27 
28 void start(test_nr)
29 int test_nr;
30 {
31   char buf[64];
32   int i;
33 
34   /* if this variable is set, specify to tests we are running
35    * in 'overnight' mode
36    */
37   bigflag = !!getenv(BIGVARNAME);
38 
39   common_test_nr = test_nr;
40   printf("Test %2d ", test_nr);
41   fflush(stdout);		/* since stdout is probably line buffered */
42   sync();
43   rm_rf_dir(test_nr);
44   sprintf(buf, "mkdir DIR_%02d", test_nr);
45   if (system(buf) != 0) {
46 	e(666);
47 	quit();
48   }
49   sprintf(buf, "DIR_%02d", test_nr);
50   if (chdir(buf) != 0) {
51 	e(6666);
52 	quit();
53   }
54 
55   for (i = 3; i < OPEN_MAX; ++i) {
56 	/* Close all files except stdin, stdout, and stderr */
57 	(void) close(i);
58   }
59 }
60 
61 int does_fs_truncate(void)
62 {
63   struct statvfs stvfs;
64   int does_truncate = 0;
65   char cwd[PATH_MAX];		/* Storage for path to current working dir */
66 
67   if (realpath(".", cwd) == NULL) e(7777);	/* Get current working dir */
68   if (statvfs(cwd, &stvfs) != 0) e(7778);	/* Get FS information */
69   /* Depending on how an FS handles too long file names, we have to adjust our
70    * error checking. If an FS does not truncate file names, it should generate
71    * an ENAMETOOLONG error when we provide too long a file name.
72    */
73   if (!(stvfs.f_flag & ST_NOTRUNC)) does_truncate = 1;
74 
75   return(does_truncate);
76 }
77 
78 int name_max(char *path)
79 {
80   struct statvfs stvfs;
81 
82   if (statvfs(path, &stvfs) != 0) e(7779);
83   return(stvfs.f_namemax);
84 }
85 
86 
87 void rm_rf_dir(test_nr)
88 int test_nr;
89 {
90   char buf[128];
91 
92   sprintf(buf, "rm -rf DIR_%02d >/dev/null 2>&1", test_nr);
93   if (system(buf) != 0) printf("Warning: system(\"%s\") failed\n", buf);
94 }
95 
96 void rm_rf_ppdir(test_nr)
97 int test_nr;
98 {
99 /* Attempt to remove everything in the test directory (== the current dir). */
100 
101   char buf[128];
102 
103   sprintf(buf, "chmod 777 ../DIR_%02d/* ../DIR_%02d/*/* >/dev/null 2>&1",
104 	  test_nr, test_nr);
105   (void) system(buf);
106   sprintf(buf, "rm -rf ../DIR_%02d >/dev/null 2>&1", test_nr);
107   if (system(buf) != 0) printf("Warning: system(\"%s\") failed\n", buf);
108 }
109 
110 void e_f(char *file, int line, int n)
111 {
112   int err_number;
113   err_number = errno;	/* Store before printf can clobber it */
114   if (errct == 0) printf("\n");	/* finish header */
115   printf("%s:%d: Subtest %d,  error %d,  errno %d: %s\n",
116 	file, line, subtest, n, err_number, strerror(err_number));
117   if (++errct > max_error) {
118 	printf("Too many errors; test aborted\n");
119 	cleanup();
120 	exit(1);
121   }
122   errno = err_number;
123 }
124 
125 void cleanup()
126 {
127   if (chdir("..") == 0 && common_test_nr != -1) rm_rf_dir(common_test_nr);
128 }
129 
130 void fail_printf(const char *file, const char *func, int line,
131 	const char *fmt, ...) {
132 	va_list ap;
133 	char buf[1024];
134 	size_t len;
135 
136 	len = snprintf(buf, sizeof(buf), "[%s:%s:%d] ", file, func, line);
137 
138 	va_start(ap, fmt);
139 	len += vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
140 	va_end(ap);
141 
142 	snprintf(buf + len, sizeof(buf) - len, " errno=%d error=%s",
143 		errno, strerror(errno));
144 
145 	em(line, buf);
146 }
147 
148 void quit()
149 {
150   cleanup();
151   if (errct == 0) {
152 	printf("ok\n");
153 	exit(0);
154   } else {
155 	printf("%d errors\n", errct);
156 	exit(1);
157   }
158 }
159 
160 void
161 printprogress(char *msg, int i, int max)
162 {
163         int use_i = i + 1;
164         static time_t start_time, prev_time;
165         static int prev_i;
166         time_t now;
167 
168 	if(quietflag) return;
169 
170         time(&now);
171         if(prev_i >= i) start_time = now;
172 
173         if(now > start_time && prev_time < now) {
174                 double i_per_sec = i / (now - start_time);
175                 int remain_secs;
176 
177                 remain_secs = (int)((max-i) / i_per_sec);
178 
179                 fprintf(stderr, "%-35s  %7d/%7d  %3d%%  ETA %3ds\r", msg,
180                       use_i, (max), use_i*100/(max), remain_secs);
181                 fflush(stderr);
182         }
183 
184         if(use_i >= max) {
185                 fprintf(stderr, "%-35s  done                                      \n", msg);
186         }
187 
188         prev_i = i;
189         prev_time = now;
190 }
191 
192 void getmem(uint32_t *total, uint32_t *free, uint32_t *cached)
193 {
194         uint32_t pagesize, largest;
195         FILE *f = fopen("/proc/meminfo", "r");
196         if(!f) return;
197         if(fscanf(f, "%u %u %u %u %u", &pagesize, total, free,
198                 &largest, cached) != 5) {
199 		fprintf(stderr, "fscanf of meminfo failed\n");
200 		exit(1);
201 	}
202         fclose(f);
203 }
204 
205 static int get_setting(const char *name, int def)
206 {
207 	const char *value;
208 
209 	value = getenv(name);
210 	if (!value || !*value) return def;
211 	if (strcmp(value, "yes") == 0) return 1;
212 	if (strcmp(value, "no") == 0) return 0;
213 
214 	fprintf(stderr, "warning: invalid $%s value: %s\n", name, value);
215 	return 0;
216 }
217 
218 int get_setting_use_network(void)
219 {
220 	/* set $USENETWORK to "yes" or "no" to indicate whether
221 	 * an internet connection is to be expected; defaults to "no"
222 	 */
223 	return get_setting("USENETWORK", 0);
224 }
225