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 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 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 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 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 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 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 127 void cleanup() 128 { 129 if (chdir("..") == 0 && common_test_nr != -1) rm_rf_dir(common_test_nr); 130 } 131 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 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 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 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 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 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 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