xref: /minix3/minix/tests/common.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1433d6423SLionel Sambuc /* Utility routines for Minix tests.
2433d6423SLionel Sambuc  * This is designed to be #includ'ed near the top of test programs.  It is
3433d6423SLionel Sambuc  * self-contained except for max_error.
4433d6423SLionel Sambuc  */
5433d6423SLionel Sambuc 
6433d6423SLionel Sambuc #include <errno.h>
7*0a6a1f1dSLionel Sambuc #include <paths.h>
8433d6423SLionel Sambuc #include <stdlib.h>
9433d6423SLionel Sambuc #include <string.h>
10433d6423SLionel Sambuc #include <unistd.h>
1117fbdaf5SErik van der Kouwe #include <stdarg.h>
12433d6423SLionel Sambuc #include <stdio.h>
13433d6423SLionel Sambuc #include <sys/statvfs.h>
14433d6423SLionel Sambuc #include <sys/syslimits.h>
15*0a6a1f1dSLionel Sambuc #include <sys/wait.h>
16433d6423SLionel Sambuc 
17433d6423SLionel Sambuc #include "common.h"
18433d6423SLionel Sambuc 
19433d6423SLionel Sambuc int common_test_nr = -1, errct = 0, subtest;
20433d6423SLionel Sambuc int quietflag = 1, bigflag = 0;
21433d6423SLionel Sambuc 
22433d6423SLionel Sambuc /* provide a default max_error symbol as Max_error with a value
23433d6423SLionel Sambuc  * of 5. The test program can override it wit its own max_error
24433d6423SLionel Sambuc  * symbol if it wants that this code will then use instead.
25433d6423SLionel Sambuc  */
26433d6423SLionel Sambuc __weak_alias(max_error,Max_error);
27433d6423SLionel Sambuc int Max_error = 5;
28433d6423SLionel Sambuc extern int max_error;
29433d6423SLionel Sambuc 
start(test_nr)30433d6423SLionel Sambuc void start(test_nr)
31433d6423SLionel Sambuc int test_nr;
32433d6423SLionel Sambuc {
33433d6423SLionel Sambuc   char buf[64];
34433d6423SLionel Sambuc   int i;
35433d6423SLionel Sambuc 
36433d6423SLionel Sambuc   /* if this variable is set, specify to tests we are running
37433d6423SLionel Sambuc    * in 'overnight' mode
38433d6423SLionel Sambuc    */
39433d6423SLionel Sambuc   bigflag = !!getenv(BIGVARNAME);
40433d6423SLionel Sambuc 
41433d6423SLionel Sambuc   common_test_nr = test_nr;
42433d6423SLionel Sambuc   printf("Test %2d ", test_nr);
43433d6423SLionel Sambuc   fflush(stdout);		/* since stdout is probably line buffered */
44433d6423SLionel Sambuc   sync();
45433d6423SLionel Sambuc   rm_rf_dir(test_nr);
46433d6423SLionel Sambuc   sprintf(buf, "mkdir DIR_%02d", test_nr);
47433d6423SLionel Sambuc   if (system(buf) != 0) {
48433d6423SLionel Sambuc 	e(666);
49433d6423SLionel Sambuc 	quit();
50433d6423SLionel Sambuc   }
51433d6423SLionel Sambuc   sprintf(buf, "DIR_%02d", test_nr);
52433d6423SLionel Sambuc   if (chdir(buf) != 0) {
53433d6423SLionel Sambuc 	e(6666);
54433d6423SLionel Sambuc 	quit();
55433d6423SLionel Sambuc   }
56433d6423SLionel Sambuc 
57433d6423SLionel Sambuc   for (i = 3; i < OPEN_MAX; ++i) {
58433d6423SLionel Sambuc 	/* Close all files except stdin, stdout, and stderr */
59433d6423SLionel Sambuc 	(void) close(i);
60433d6423SLionel Sambuc   }
61433d6423SLionel Sambuc }
62433d6423SLionel Sambuc 
does_fs_truncate(void)63433d6423SLionel Sambuc int does_fs_truncate(void)
64433d6423SLionel Sambuc {
65433d6423SLionel Sambuc   struct statvfs stvfs;
66433d6423SLionel Sambuc   int does_truncate = 0;
67433d6423SLionel Sambuc   char cwd[PATH_MAX];		/* Storage for path to current working dir */
68433d6423SLionel Sambuc 
69433d6423SLionel Sambuc   if (realpath(".", cwd) == NULL) e(7777);	/* Get current working dir */
70433d6423SLionel Sambuc   if (statvfs(cwd, &stvfs) != 0) e(7778);	/* Get FS information */
71433d6423SLionel Sambuc   /* Depending on how an FS handles too long file names, we have to adjust our
72433d6423SLionel Sambuc    * error checking. If an FS does not truncate file names, it should generate
73433d6423SLionel Sambuc    * an ENAMETOOLONG error when we provide too long a file name.
74433d6423SLionel Sambuc    */
75433d6423SLionel Sambuc   if (!(stvfs.f_flag & ST_NOTRUNC)) does_truncate = 1;
76433d6423SLionel Sambuc 
77433d6423SLionel Sambuc   return(does_truncate);
78433d6423SLionel Sambuc }
79433d6423SLionel Sambuc 
name_max(char * path)80433d6423SLionel Sambuc int name_max(char *path)
81433d6423SLionel Sambuc {
82433d6423SLionel Sambuc   struct statvfs stvfs;
83433d6423SLionel Sambuc 
84433d6423SLionel Sambuc   if (statvfs(path, &stvfs) != 0) e(7779);
85433d6423SLionel Sambuc   return(stvfs.f_namemax);
86433d6423SLionel Sambuc }
87433d6423SLionel Sambuc 
88433d6423SLionel Sambuc 
rm_rf_dir(test_nr)89433d6423SLionel Sambuc void rm_rf_dir(test_nr)
90433d6423SLionel Sambuc int test_nr;
91433d6423SLionel Sambuc {
92433d6423SLionel Sambuc   char buf[128];
93433d6423SLionel Sambuc 
94433d6423SLionel Sambuc   sprintf(buf, "rm -rf DIR_%02d >/dev/null 2>&1", test_nr);
95*0a6a1f1dSLionel Sambuc   if (system_p(buf) != 0) printf("Warning: system(\"%s\") failed\n", buf);
96433d6423SLionel Sambuc }
97433d6423SLionel Sambuc 
rm_rf_ppdir(test_nr)98433d6423SLionel Sambuc void rm_rf_ppdir(test_nr)
99433d6423SLionel Sambuc int test_nr;
100433d6423SLionel Sambuc {
101433d6423SLionel Sambuc /* Attempt to remove everything in the test directory (== the current dir). */
102433d6423SLionel Sambuc 
103433d6423SLionel Sambuc   char buf[128];
104433d6423SLionel Sambuc 
105433d6423SLionel Sambuc   sprintf(buf, "chmod 777 ../DIR_%02d/* ../DIR_%02d/*/* >/dev/null 2>&1",
106433d6423SLionel Sambuc 	  test_nr, test_nr);
107433d6423SLionel Sambuc   (void) system(buf);
108433d6423SLionel Sambuc   sprintf(buf, "rm -rf ../DIR_%02d >/dev/null 2>&1", test_nr);
109433d6423SLionel Sambuc   if (system(buf) != 0) printf("Warning: system(\"%s\") failed\n", buf);
110433d6423SLionel Sambuc }
111433d6423SLionel Sambuc 
e_f(char * file,int line,int n)112433d6423SLionel Sambuc void e_f(char *file, int line, int n)
113433d6423SLionel Sambuc {
114433d6423SLionel Sambuc   int err_number;
115433d6423SLionel Sambuc   err_number = errno;	/* Store before printf can clobber it */
116433d6423SLionel Sambuc   if (errct == 0) printf("\n");	/* finish header */
117433d6423SLionel Sambuc   printf("%s:%d: Subtest %d,  error %d,  errno %d: %s\n",
118433d6423SLionel Sambuc 	file, line, subtest, n, err_number, strerror(err_number));
119433d6423SLionel Sambuc   if (++errct > max_error) {
120433d6423SLionel Sambuc 	printf("Too many errors; test aborted\n");
121433d6423SLionel Sambuc 	cleanup();
122433d6423SLionel Sambuc 	exit(1);
123433d6423SLionel Sambuc   }
124433d6423SLionel Sambuc   errno = err_number;
125433d6423SLionel Sambuc }
126433d6423SLionel Sambuc 
cleanup()127433d6423SLionel Sambuc void cleanup()
128433d6423SLionel Sambuc {
129433d6423SLionel Sambuc   if (chdir("..") == 0 && common_test_nr != -1) rm_rf_dir(common_test_nr);
130433d6423SLionel Sambuc }
131433d6423SLionel Sambuc 
fail_printf(const char * file,const char * func,int line,const char * fmt,...)13217fbdaf5SErik van der Kouwe void fail_printf(const char *file, const char *func, int line,
13317fbdaf5SErik van der Kouwe 	const char *fmt, ...) {
13417fbdaf5SErik van der Kouwe 	va_list ap;
13517fbdaf5SErik van der Kouwe 	char buf[1024];
13617fbdaf5SErik van der Kouwe 	size_t len;
13717fbdaf5SErik van der Kouwe 
13817fbdaf5SErik van der Kouwe 	len = snprintf(buf, sizeof(buf), "[%s:%s:%d] ", file, func, line);
13917fbdaf5SErik van der Kouwe 
14017fbdaf5SErik van der Kouwe 	va_start(ap, fmt);
14117fbdaf5SErik van der Kouwe 	len += vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
14217fbdaf5SErik van der Kouwe 	va_end(ap);
14317fbdaf5SErik van der Kouwe 
14417fbdaf5SErik van der Kouwe 	snprintf(buf + len, sizeof(buf) - len, " errno=%d error=%s",
14517fbdaf5SErik van der Kouwe 		errno, strerror(errno));
14617fbdaf5SErik van der Kouwe 
14717fbdaf5SErik van der Kouwe 	em(line, buf);
14817fbdaf5SErik van der Kouwe }
14917fbdaf5SErik van der Kouwe 
quit()150433d6423SLionel Sambuc void quit()
151433d6423SLionel Sambuc {
152433d6423SLionel Sambuc   cleanup();
153433d6423SLionel Sambuc   if (errct == 0) {
154433d6423SLionel Sambuc 	printf("ok\n");
155433d6423SLionel Sambuc 	exit(0);
156433d6423SLionel Sambuc   } else {
157433d6423SLionel Sambuc 	printf("%d errors\n", errct);
158433d6423SLionel Sambuc 	exit(1);
159433d6423SLionel Sambuc   }
160433d6423SLionel Sambuc }
161433d6423SLionel Sambuc 
162433d6423SLionel Sambuc void
printprogress(char * msg,int i,int max)163433d6423SLionel Sambuc printprogress(char *msg, int i, int max)
164433d6423SLionel Sambuc {
165433d6423SLionel Sambuc         int use_i = i + 1;
166433d6423SLionel Sambuc         static time_t start_time, prev_time;
167433d6423SLionel Sambuc         static int prev_i;
168433d6423SLionel Sambuc         time_t now;
169433d6423SLionel Sambuc 
170433d6423SLionel Sambuc 	if(quietflag) return;
171433d6423SLionel Sambuc 
172433d6423SLionel Sambuc         time(&now);
173433d6423SLionel Sambuc         if(prev_i >= i) start_time = now;
174433d6423SLionel Sambuc 
175433d6423SLionel Sambuc         if(now > start_time && prev_time < now) {
176433d6423SLionel Sambuc                 double i_per_sec = i / (now - start_time);
177433d6423SLionel Sambuc                 int remain_secs;
178433d6423SLionel Sambuc 
179433d6423SLionel Sambuc                 remain_secs = (int)((max-i) / i_per_sec);
180433d6423SLionel Sambuc 
181433d6423SLionel Sambuc                 fprintf(stderr, "%-35s  %7d/%7d  %3d%%  ETA %3ds\r", msg,
182433d6423SLionel Sambuc                       use_i, (max), use_i*100/(max), remain_secs);
183433d6423SLionel Sambuc                 fflush(stderr);
184433d6423SLionel Sambuc         }
185433d6423SLionel Sambuc 
186433d6423SLionel Sambuc         if(use_i >= max) {
187433d6423SLionel Sambuc                 fprintf(stderr, "%-35s  done                                      \n", msg);
188433d6423SLionel Sambuc         }
189433d6423SLionel Sambuc 
190433d6423SLionel Sambuc         prev_i = i;
191433d6423SLionel Sambuc         prev_time = now;
192433d6423SLionel Sambuc }
193433d6423SLionel Sambuc 
getmem(uint32_t * total,uint32_t * free,uint32_t * cached)194c4182e08SErik van der Kouwe void getmem(uint32_t *total, uint32_t *free, uint32_t *cached)
195433d6423SLionel Sambuc {
196c4182e08SErik van der Kouwe         uint32_t pagesize, largest;
197433d6423SLionel Sambuc         FILE *f = fopen("/proc/meminfo", "r");
198433d6423SLionel Sambuc         if(!f) return;
199433d6423SLionel Sambuc         if(fscanf(f, "%u %u %u %u %u", &pagesize, total, free,
200433d6423SLionel Sambuc                 &largest, cached) != 5) {
201433d6423SLionel Sambuc 		fprintf(stderr, "fscanf of meminfo failed\n");
202433d6423SLionel Sambuc 		exit(1);
203433d6423SLionel Sambuc 	}
204433d6423SLionel Sambuc         fclose(f);
205433d6423SLionel Sambuc }
206433d6423SLionel Sambuc 
get_setting(const char * name,int def)2073433559cSErik van der Kouwe static int get_setting(const char *name, int def)
2083433559cSErik van der Kouwe {
2093433559cSErik van der Kouwe 	const char *value;
2103433559cSErik van der Kouwe 
2113433559cSErik van der Kouwe 	value = getenv(name);
2123433559cSErik van der Kouwe 	if (!value || !*value) return def;
2133433559cSErik van der Kouwe 	if (strcmp(value, "yes") == 0) return 1;
2143433559cSErik van der Kouwe 	if (strcmp(value, "no") == 0) return 0;
2153433559cSErik van der Kouwe 
2163433559cSErik van der Kouwe 	fprintf(stderr, "warning: invalid $%s value: %s\n", name, value);
2173433559cSErik van der Kouwe 	return 0;
2183433559cSErik van der Kouwe }
2193433559cSErik van der Kouwe 
get_setting_use_network(void)2203433559cSErik van der Kouwe int get_setting_use_network(void)
2213433559cSErik van der Kouwe {
2223433559cSErik van der Kouwe 	/* set $USENETWORK to "yes" or "no" to indicate whether
2233433559cSErik van der Kouwe 	 * an internet connection is to be expected; defaults to "no"
2243433559cSErik van der Kouwe 	 */
2253433559cSErik van der Kouwe 	return get_setting("USENETWORK", 0);
2263433559cSErik van der Kouwe }
227*0a6a1f1dSLionel Sambuc 
228*0a6a1f1dSLionel Sambuc int
system_p(const char * command)229*0a6a1f1dSLionel Sambuc system_p(const char *command)
230*0a6a1f1dSLionel Sambuc {
231*0a6a1f1dSLionel Sambuc 	extern char **environ;
232*0a6a1f1dSLionel Sambuc 	pid_t pid;
233*0a6a1f1dSLionel Sambuc 	int pstat;
234*0a6a1f1dSLionel Sambuc 	const char *argp[] = {"sh", "-c", "-p", NULL, NULL};
235*0a6a1f1dSLionel Sambuc 	argp[3] = command;
236*0a6a1f1dSLionel Sambuc 
237*0a6a1f1dSLionel Sambuc 	switch(pid = vfork()) {
238*0a6a1f1dSLionel Sambuc 	case -1:			/* error */
239*0a6a1f1dSLionel Sambuc 		return -1;
240*0a6a1f1dSLionel Sambuc 	case 0:				/* child */
241*0a6a1f1dSLionel Sambuc 		execve(_PATH_BSHELL, __UNCONST(argp), environ);
242*0a6a1f1dSLionel Sambuc 		_exit(127);
243*0a6a1f1dSLionel Sambuc 	}
244*0a6a1f1dSLionel Sambuc 
245*0a6a1f1dSLionel Sambuc 	while (waitpid(pid, &pstat, 0) == -1) {
246*0a6a1f1dSLionel Sambuc 		if (errno != EINTR) {
247*0a6a1f1dSLionel Sambuc 			pstat = -1;
248*0a6a1f1dSLionel Sambuc 			break;
249*0a6a1f1dSLionel Sambuc 		}
250*0a6a1f1dSLionel Sambuc 	}
251*0a6a1f1dSLionel Sambuc 
252*0a6a1f1dSLionel Sambuc 	return (pstat);
253*0a6a1f1dSLionel Sambuc }
254*0a6a1f1dSLionel Sambuc 
255