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