xref: /minix/minix/tests/test18.c (revision 7f5f010b)
1 /* test 18 */
2 
3 /* Comment on usage and program: ark!/mnt/rene/prac/os/unix/comment.changes */
4 
5 /* "const.h", created by Rene Montsma and Menno Wilcke */
6 
7 #include <sys/types.h>		/* needed in struct stat */
8 #include <sys/stat.h>		/* struct stat */
9 #include <sys/wait.h>
10 #include <errno.h>		/* the error-numbers */
11 #include <fcntl.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <string.h>
15 #include <stdio.h>
16 #include <limits.h>
17 #include <assert.h>
18 #include <sys/uio.h>
19 
20 #define NOCRASH 1		/* test11(), 2nd pipe */
21 #define PDPNOHANG  1		/* test03(), write_standards() */
22 #define MAXERR 5
23 
24 #define USER_ID   12
25 #define GROUP_ID   1
26 #define FF        3		/* first free filedes. */
27 #define USER      1		/* uid */
28 #define GROUP     0		/* gid */
29 
30 #define ARSIZE   256		/* array size */
31 #define PIPESIZE 3584		/* maxnumber of bytes to be written on pipe */
32 #define MAXOPEN  (OPEN_MAX-3)	/* maximum number of extra open files */
33 #define MAXLINK 0177		/* maximum number of links per file */
34 #define MASK    0777		/* selects lower nine bits */
35 #define READ_EOF 0		/* returned by read-call at eof */
36 
37 #define OK      0
38 #define FAIL   -1
39 
40 #define R       0		/* read (open-call) */
41 #define W       1		/* write (open-call) */
42 #define RW      2		/* read & write (open-call) */
43 
44 #define RWX     7		/* read & write & execute (mode) */
45 
46 #define NIL     ""
47 #define UMASK   "umask"
48 #define CREAT   "creat"
49 #define WRITE   "write"
50 #define WRITEV  "writev"
51 #define READ    "read"
52 #define READV   "readv"
53 #define OPEN    "open"
54 #define CLOSE   "close"
55 #define LSEEK   "lseek"
56 #define ACCESS  "access"
57 #define CHDIR   "chdir"
58 #define CHMOD   "chmod"
59 #define LINK    "link"
60 #define UNLINK  "unlink"
61 #define PIPE    "pipe"
62 #define STAT    "stat"
63 #define FSTAT   "fstat"
64 #define DUP     "dup"
65 #define UTIME   "utime"
66 
67 int max_error = 2;
68 #include "common.h"
69 
70 
71 /* "decl.c", created by Rene Montsma and Menno Wilcke */
72 
73 /* Used in open_alot, close_alot */
74 char *file[MAXOPEN];
75 char *fnames[8] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"},
76 	*dir[8] = {"d---", "d--x", "d-w-", "d-wx", "dr--", "dr-x", "drw-", "drwx"};
77 
78  /* Needed for easy creating and deleting of directories */
79 
80 /* "test.c", created by Rene Montsma and Menno Wilcke */
81 
82 
83 int main(int argc, char **argv);
84 void test(void);
85 void test01(void);
86 void test02(void);
87 void test03(void);
88 void write_standards(int filedes, char a []);
89 void test04(void);
90 void read_standards(int filedes, char a []);
91 void read_more(int filedes, char a []);
92 void test05(void);
93 void try_open(char *fname, int mode, int test);
94 void test06(void);
95 void test07(void);
96 void access_standards(void);
97 void test08(void);
98 static int iovec_is_equal(struct iovec *x, struct iovec *y, size_t
99 	size);
100 static size_t iovec_setup(int pattern, struct iovec *iovec, char
101 	*buffer, int count);
102 static int power(int base, int exponent);
103 void try_access(char *fname, int mode, int test);
104 void make_and_fill_dirs(void);
105 void put_file_in_dir(char *dirname, int mode);
106 void init_array(char *a);
107 void clear_array(char *b);
108 int comp_array(char *a, char *b, int range);
109 void try_close(int filedes, char *name);
110 void try_unlink(char *fname);
111 void Remove(int fdes, char *fname);
112 int get_mode(char *name);
113 void check(char *scall, int number);
114 void put(int nr);
115 int open_alot(void);
116 int close_alot(int number);
117 void clean_up_the_mess(void);
118 void chmod_8_dirs(int sw);
119 
120 /*****************************************************************************
121  *                              TEST                                         *
122  ****************************************************************************/
123 int main(int argc, char **argv)
124 {
125   int n, i;
126   pid_t child;
127 
128   start(18);
129 
130   /* Create filenames for MAXOPEN files, the *file[] array. */
131   for(i = 0; i < MAXOPEN; i++) {
132         if(asprintf(&file[i], "file%d", i) == -1) {
133                 fprintf(stderr, "asprintf failed\n");
134                 quit();
135         }
136   }
137 
138   subtest = 0;
139   child = fork();
140   if (child == -1) {
141 	e(1);
142 	quit();
143   } else if (child == 0) {
144 	test();
145 	return(0);
146   } else {
147 	wait(&n);
148 	clean_up_the_mess();
149 	quit();
150   }
151 
152   return(-1);
153 }
154 
155 void test()
156 {
157   umask(0);			/* not honest, but i always forget */
158 
159   test01();
160   make_and_fill_dirs();
161   test02();
162   test03();
163   test04();
164   test05();
165   test06();
166   test07();
167   test08();
168   umask(022);
169 }				/* test */
170 
171 /* "t1.c" created by Rene Montsma and Menno Wilcke */
172 
173 /*****************************************************************************
174  *                              test UMASK                                   *
175  ****************************************************************************/
176 void test01()
177 {
178   int oldvalue, newvalue, tempvalue;
179   int nr;
180 
181   subtest = 1;
182 
183   if ((oldvalue = umask(0777)) != 0) e(1);
184 
185   /* Special test: only the lower 9 bits (protection bits) may part- *
186    * icipate. ~0777 means: 111 000 000 000. Giving this to umask must*
187    * not change any value.                                           */
188 
189   if ((newvalue = umask(~0777)) != 0777) e(2);
190   if (oldvalue == newvalue) e(3);
191 
192   if ((tempvalue = umask(0)) != 0) e(4);
193 
194   /* Now test all possible modes of umask on a file */
195   for (newvalue = MASK; newvalue >= 0; newvalue -= 0111) {
196 	tempvalue = umask(newvalue);
197 	if (tempvalue != oldvalue) {
198 		e(5);
199 		break;		/* no use trying more */
200 	} else if ((nr = creat("file01", 0777)) < 0)
201 		e(6);
202 	else {
203 		try_close(nr, "'file01'");
204 		if (get_mode("file01") != (MASK & ~newvalue)) e(7);
205 		try_unlink("file01");
206 	}
207 	oldvalue = newvalue;
208   }
209 
210   /* The loop has terminated with umask(0) */
211   if ((tempvalue = umask(0)) != 0) e(8);
212 }				/* test01 */
213 
214 /*****************************************************************************
215  *                              test CREAT                                   *
216  ****************************************************************************/
217 void test02()
218 {
219   int n, n1, mode;
220   char a[ARSIZE], b[ARSIZE];
221   struct stat stbf1;
222 
223   subtest = 2;
224   mode = 0;
225   /* Create MAXOPEN files, check filedes */
226   for (n = 0; n < MAXOPEN; n++) {
227 	if (creat(file[n], mode) != FF + n)
228 		e(1);
229 	else {
230 		if (get_mode(file[n]) != mode) e(2);
231 
232 		/* Change  mode of file to standard mode, we want to *
233 		 * use a lot (20) of files to be opened later, see   *
234 		 * open_alot(), close_alot().                        */
235 		if (chmod(file[n], 0700) != OK) e(3);
236 
237 	}
238 	mode = (mode + 0100) % 01000;
239   }
240 
241   /* Already twenty files opened; opening another has to fail */
242   if (creat("file02", 0777) != FAIL) e(4);
243   else
244 	if (errno != EMFILE) e(5);;
245 
246 
247   /* Close all files: seems blunt, but it isn't because we've  *
248    * checked all fd's already                                  */
249   if ((n = close_alot(MAXOPEN)) < MAXOPEN) e(6);
250 
251   /* Creat 1 file twice; check */
252   if ((n = creat("file02", 0777)) < 0) e(7);
253   else {
254 	init_array(a);
255 	if (write(n, a, ARSIZE) != ARSIZE) e(8);
256 
257 	if ((n1 = creat("file02", 0755)) < 0) e(9);
258 	else {
259 		/* Fd should be at the top after recreation */
260 		if (lseek(n1, 0L, SEEK_END) != 0) e(10);
261 		else {
262 			/* Try to write on recreated file */
263 			clear_array(b);
264 
265 			if (lseek(n1, 0L, SEEK_SET) != 0) e(11);
266 			if (write(n1, a, ARSIZE) != ARSIZE) e(12);
267 
268 			/* In order to read we've to close and open again */
269 			try_close(n1, "'file02'  (2nd creation)");
270 			if ((n1 = open("file02", RW)) < 0) e(13);
271 
272 			/* Continue */
273 			if (lseek(n1, 0L, SEEK_SET) != 0) e(14);
274 			if (read(n1, b, ARSIZE) != ARSIZE) e(15);
275 
276 			if (comp_array(a, b, ARSIZE) != OK) e(16);
277 		}
278 		if (get_mode("file02") != 0777) e(17);
279 		try_close(n1, "recreated 'file02'");
280 
281 	}
282 	Remove(n, "file02");
283   }
284 
285   /* Give 'creat' wrong input: dir not searchable */
286   if (creat("drw-/file02", 0777) != FAIL) e(18);
287   else
288 	if (errno != EACCES) e(19);
289 
290   /* Dir not writable */
291   if (creat("dr-x/file02", 0777) != FAIL) e(20);
292   else
293 	if (errno != EACCES) e(21);
294 
295   /* File not writable */
296   if (creat("drwx/r-x", 0777) != FAIL) e(22);
297   else
298   	if (errno != EACCES) e(23);
299 
300   /* Try to creat a dir */
301   if ((n = creat("dir", 040777)) != FAIL) {
302 	if (fstat(n, &stbf1) != OK) e(24);
303 	else if (stbf1.st_mode != (mode_t) 0100777)
304 				/* Cast because mode is negative :-(.
305 				 * HACK DEBUG FIXME: this appears to duplicate
306 				 * code in test17.c.
307 				 */
308 		e(25);
309 	Remove(n, "dir");
310   }
311 
312   /* We don't consider it to be a bug when creat * does not accept
313    * tricky modes                */
314 
315   /* File is an existing dir */
316   if (creat("drwx", 0777) != FAIL) e(26);
317   else
318 	if (errno != EISDIR) e(27);
319 }				/* test02 */
320 
321 /*****************************************************************************
322  *                              test WRITE                                   *
323  ****************************************************************************/
324 void test03()
325 {
326   int n, n1;
327   int fd[2];
328   char a[ARSIZE];
329 
330   subtest = 3;
331   init_array(a);
332 
333   /* Test write after a CREAT */
334   if ((n = creat("file03", 0700)) != FF) e(1);
335   else {
336 	write_standards(n, a);	/* test simple writes, wrong input too */
337 	try_close(n, "'file03'");
338   }
339 
340   /* Test write after an OPEN */
341   if ((n = open("file03", W)) < 0) e(2);
342   else
343 	write_standards(n, a);	/* test simple writes, wrong input too */
344 
345   /* Test write after a DUP */
346   if ((n1 = dup(n)) < 0) e(3);
347   else {
348 	write_standards(n1, a);
349 	try_close(n1, "duplicated fd 'file03'");
350   }
351 
352   /* Remove testfile */
353   Remove(n, "file03");
354 
355   /* Test write after a PIPE */
356   if (pipe(fd) < 0) e(4);
357   else {
358 	write_standards(fd[1], a);
359 	try_close(fd[0], "'fd[0]'");
360 	try_close(fd[1], "'fd[1]'");
361   }
362 
363   /* Last test: does write check protections ? */
364   if ((n = open("drwx/r--", R)) < 0) e(5);
365   else {
366 	if (write(n, a, ARSIZE) != FAIL) e(6);
367 	else
368 		if (errno != EBADF) e(7);
369 	try_close(n, "'drwx/r--'");
370   }
371 }				/* test03 */
372 
373 void write_standards(filedes, a)
374 int filedes;
375 char a[];
376 {
377 
378   /* Write must return written account of numbers */
379   if (write(filedes, a, ARSIZE) != ARSIZE) e(80);
380 
381   /* Try giving 'write' wrong input */
382   /* Wrong filedes */
383   if (write(-1, a, ARSIZE) != FAIL) e(81);
384   else
385 	if (errno != EBADF) e(82);
386 
387   /* Wrong length (illegal) */
388 #ifndef PDPNOHANG
389   if (write(filedes, a, -ARSIZE) != FAIL) e(83);
390   else
391 	if (errno != EINVAL) e(84);
392 #endif
393 }				/* write_standards */
394 
395 
396 /*****************************************************************************
397  *                              test READ                                    *
398  ****************************************************************************/
399 void test04()
400 {
401   int n, n1, fd[2];
402   char a[ARSIZE];
403 
404   subtest = 4;
405 
406   /* Test read after creat */
407   if ((n = creat("file04", 0700)) != FF) e(1);
408   else {
409 	/* Closing and opening needed before writing */
410 	try_close(n, "'file04'");
411 	if ((n = open("file04", RW)) < 0) e(2);
412 
413 	init_array(a);
414 
415 	if (write(n, a, ARSIZE) != ARSIZE) e(3);
416 	else {
417 		if (lseek(n, 0L, SEEK_SET) != 0) e(4);
418 		read_standards(n, a);
419 		read_more(n, a);
420 	}
421 	try_close(n, "'file04'");
422   }
423 
424   /* Test read after OPEN */
425   if ((n = open("file04", R)) < 0) e(5);
426   else {
427 	read_standards(n, a);
428 	read_more(n, a);
429 	try_close(n, "'file04'");
430   }
431 
432   /* Test read after DUP */
433   if ((n = open("file04", R)) < 0) e(6);
434   if ((n1 = dup(n)) < 0) e(7);
435   else {
436 	read_standards(n1, a);
437 	read_more(n1, a);
438 	try_close(n1, "duplicated fd 'file04'");
439   }
440 
441   /* Remove testfile */
442   Remove(n, "file04");
443 
444   /* Test read after pipe */
445   if (pipe(fd) < 0) e(8);
446   else {
447 	if (write(fd[1], a, ARSIZE) != ARSIZE) {
448 		e(9);
449 		try_close(fd[1], "'fd[1]'");
450 	} else {
451 		try_close(fd[1], "'fd[1]'");
452 		read_standards(fd[0], a);
453 	}
454 	try_close(fd[0], "'fd[0]'");
455   }
456 
457   /* Last test: try to read a read-protected file */
458   if ((n = open("drwx/-wx", W)) < 0) e(10);
459   else {
460 	if (read(n, a, ARSIZE) != FAIL) e(11);
461 	else
462 		if (errno != EBADF) e(12);
463 	try_close(n, "'/drwx/-wx'");
464   }
465 }				/* test04 */
466 
467 void read_standards(filedes, a)
468 int filedes;
469 char a[];
470 {
471   char b[ARSIZE];
472 
473   clear_array(b);
474   if (read(filedes, b, ARSIZE) != ARSIZE) e(85);
475   else if (comp_array(a, b, ARSIZE) != OK) e(86);
476   else if (read(filedes, b, ARSIZE) != READ_EOF) e(87);
477 
478   /* Try giving read wrong input: wrong filedes */
479   if (read(FAIL, b, ARSIZE) != FAIL) e(88);
480   else
481 	if (errno != EBADF) e(89);
482 
483   /* Wrong length */
484   if (read(filedes, b, -ARSIZE) != FAIL) e(90);
485   else
486 	if (errno != EINVAL) e(91);
487 }				/* read_standards */
488 
489 void read_more(filedes, a)
490 int filedes;
491 char a[];
492  /* Separated from read_standards() because the PIPE test * would fail.                                           */
493 {
494   int i;
495   char b[ARSIZE];
496 
497   if (lseek(filedes, (long) (ARSIZE / 2), SEEK_SET) != ARSIZE / 2) e(92);
498 
499   clear_array(b);
500   if (read(filedes, b, ARSIZE) != ARSIZE / 2) e(93);
501 
502   for (i = 0; i < ARSIZE / 2; i++)
503 	if (b[i] != a[(ARSIZE / 2) + i]) e(94);
504 }
505 
506 /*****************************************************************************
507  *                              test OPEN/CLOSE                              *
508  ****************************************************************************/
509 void test05()
510 {
511   int n, n1, mode, fd[2];
512   char b[ARSIZE];
513 
514   subtest = 5;
515   /* Test open after CREAT */
516   if ((n = creat("file05", 0700)) != FF) e(1);
517   else {
518 	if ((n1 = open("file05", RW)) != FF + 1) e(2);
519 	try_close(n1, "'file05' (open after creation)");
520 
521 	try_close(n, "'file05'");
522 	if ((n = open("file05", R)) != FF) e(3);
523 	else
524 		try_close(n, "'file05' (open after closing)");
525 
526 	/* Remove testfile */
527 	try_unlink("file05");
528   }
529 
530   /* Test all possible modes, try_open not only opens file (sometimes) *
531    * but closes files too (when opened)                                */
532   if ((n = creat("file05", 0700)) < 0) e(6);
533   else {
534 	try_close(n, "file05");
535 	for (mode = 0; mode <= 0700; mode += 0100) {
536 		if (chmod("file05", mode) != OK) e(7);
537 
538 		if (mode <= 0100) {
539 			try_open("file05", R, FAIL);
540 			try_open("file05", W, FAIL);
541 			try_open("file05", RW, FAIL);
542 		} else if (mode >= 0200 && mode <= 0300) {
543 			try_open("file05", R, FAIL);
544 			try_open("file05", W, FF);
545 			try_open("file05", RW, FAIL);
546 		} else if (mode >= 0400 && mode <= 0500) {
547 			try_open("file05", R, FF);
548 			try_open("file05", W, FAIL);
549 			try_open("file05", RW, FAIL);
550 		} else {
551 			try_open("file05", R, FF);
552 			try_open("file05", W, FF);
553 			try_open("file05", RW, FF);
554 		}
555 	}
556   }
557 
558   /* Test opening existing file */
559   if ((n = open("drwx/rwx", R)) < 0) e(8);
560   else {			/* test close after DUP */
561 	if ((n1 = dup(n)) < 0) e(9);
562 	else {
563 		try_close(n1, "duplicated fd 'drwx/rwx'");
564 
565 		if (read(n1, b, ARSIZE) != FAIL) e(10);
566 		else
567 			if (errno != EBADF) e(11);
568 
569 		if (read(n, b, ARSIZE) == FAIL)	e(12);/* should read an eof */
570 	}
571 	try_close(n, "'drwx/rwx'");
572   }
573 
574   /* Test close after PIPE */
575   if (pipe(fd) < 0) e(13);
576   else {
577 	try_close(fd[1], "duplicated fd 'fd[1]'");
578 
579 	/* Fd[1] really should be closed now; check */
580 	clear_array(b);
581 	if (read(fd[0], b, ARSIZE) != READ_EOF) e(14);
582 	try_close(fd[0], "duplicated fd 'fd[0]'");
583   }
584 
585   /* Try to open a non-existing file */
586   if (open("non-file", R) != FAIL) e(15);
587   else
588 	if (errno != ENOENT) e(16);
589 
590   /* Dir does not exist */
591   if (open("dzzz/file05", R) != FAIL) e(17);
592   else
593 	if (errno !=  ENOENT) e(18);
594 
595   /* Dir is not searchable */
596   if ((n = open("drw-/rwx", R)) != FAIL) e(19);
597   else
598 	if (errno != EACCES) e(20);
599 
600   /* Unlink testfile */
601   try_unlink("file05");
602 
603   /* File is not readable */
604   if (open("drwx/-wx", R) != FAIL) e(21);
605   else
606 	if (errno != EACCES) e(22);
607 
608   /* File is not writable */
609   if (open("drwx/r-x", W) != FAIL) e(23);
610   else
611 	if (errno != EACCES) e(24);
612 
613   /* Try opening more than MAXOPEN  ('extra' (19-8-85)) files */
614   if ((n = open_alot()) != MAXOPEN) e(25);
615   else
616 	/* Maximum # of files opened now, another open should fail
617 	 * because * all filedescriptors have already been used.                      */
618   if (open("drwx/rwx", RW) != FAIL) e(26);
619   else
620 	if (errno != EMFILE) e(27);
621   if (close_alot(n) != n) e(28);
622 
623   /* Can close make mistakes ? */
624   if (close(-1) != FAIL) e(29);
625   else
626 	if (errno != EBADF) e(30);
627 }				/* test05 */
628 
629 void try_open(fname, mode, test)
630 int mode, test;
631 char *fname;
632 {
633   int n;
634 
635   if ((n = open(fname, mode)) != test) e(95);
636   if (n != FAIL) try_close(n, fname);	/* cleanup */
637 }				/* try_open */
638 
639 /*****************************************************************************
640  *                              test LSEEK                                   *
641  ****************************************************************************/
642 void test06()
643 {
644   char a[ARSIZE], b[ARSIZE];
645   int fd;
646 
647   subtest = 6;
648 
649   if ((fd = open("drwx/rwx", RW)) != FF) e(1);
650   else {
651 	init_array(a);
652 	if (write(fd, a, 10) != 10) e(2);
653 	else {
654 		/* Lseek back to begin file */
655 		if (lseek(fd, 0L, SEEK_SET) != 0) e(3);
656 		else if (read(fd, b, 10) != 10) e(4);
657 		else if (comp_array(a, b, 10) != OK) e(5);
658 
659 		/* Lseek to endoffile */
660 		if (lseek(fd, 0L, SEEK_END) != 10) e(6);
661 		else if (read(fd, b, 1) != READ_EOF) e(7);
662 
663 		/* Lseek beyond file */
664 		if (lseek(fd, 10L, SEEK_CUR) != 20) e(8);
665 		else if (write(fd, a, 10) != 10) e(9);
666 		else {
667 			/* Lseek to begin second write */
668 			if (lseek(fd, 20L, SEEK_SET) != 20) e(10);
669 			if (read(fd, b, 10) != 10) e(11);
670 			else if (comp_array(a, b, 10) != OK) e(12);
671 		}
672 	}
673 
674 	/* Lseek to position before begin of file */
675 	if (lseek(fd, -1L, 0) != FAIL) e(13);
676 
677 	try_close(fd, "'drwx/rwx'");
678   }
679 
680   /* Lseek on invalid filediscriptor */
681   if (lseek(-1, 0L, SEEK_SET) != FAIL) e(14);
682   else
683 	if (errno != EBADF) e(15);
684 
685 }
686 
687 /*****************************************************************************
688  *                              test ACCESS                                  *
689  ****************************************************************************/
690 void test07()
691 {
692   subtest = 7;
693 
694   /* Check with proper parameters */
695   if (access("drwx/rwx", RWX) != OK) e(1);
696 
697   if (access("./././drwx/././rwx", 0) != OK) e(2);
698 
699   /* Check 8 files with 8 different modes on 8 accesses  */
700   if (chdir("drwx") != OK) e(3);
701 
702   access_standards();
703 
704   if (chdir("..") != OK) e(4);
705 
706   /* Check several wrong combinations */
707   /* File does not exist */
708   if (access("non-file", 0) != FAIL) e(5);
709   else
710 	if (errno != ENOENT) e(6);
711 
712   /* Non-searchable dir */
713   if (access("drw-/rwx", 0) != FAIL) e(7);
714   else
715 	if (errno != EACCES) e(8);
716 
717   /* Searchable dir, but wrong file-mode */
718   if (access("drwx/--x", RWX) != FAIL) e(9);
719   else
720 	if (errno != EACCES) e(10);
721 
722 }				/* test07 */
723 
724 void access_standards()
725 {
726   int i, mode = 0;
727 
728   for (i = 0; i < 8; i++)
729 	if (i == 0)
730 		try_access(fnames[mode], i, OK);
731 	else
732 		try_access(fnames[mode], i, FAIL);
733   mode++;
734 
735   for (i = 0; i < 8; i++)
736 	if (i < 2)
737 		try_access(fnames[mode], i, OK);
738 	else
739 		try_access(fnames[mode], i, FAIL);
740   mode++;
741 
742   for (i = 0; i < 8; i++)
743 	if (i == 0 || i == 2)
744 		try_access(fnames[mode], i, OK);
745 	else
746 		try_access(fnames[mode], i, FAIL);
747   mode++;
748 
749   for (i = 0; i < 8; i++)
750 	if (i < 4)
751 		try_access(fnames[mode], i, OK);
752 	else
753 		try_access(fnames[mode], i, FAIL);
754   mode++;
755 
756   for (i = 0; i < 8; i++)
757 	if (i == 0 || i == 4)
758 		try_access(fnames[mode], i, OK);
759 	else
760 		try_access(fnames[mode], i, FAIL);
761   mode++;
762 
763   for (i = 0; i < 8; i++)
764 	if (i == 0 || i == 1 || i == 4 || i == 5)
765 		try_access(fnames[mode], i, OK);
766 	else
767 		try_access(fnames[mode], i, FAIL);
768   mode++;
769 
770   for (i = 0; i < 8; i++)
771 	if (i % 2 == 0)
772 		try_access(fnames[mode], i, OK);
773 	else
774 		try_access(fnames[mode], i, FAIL);
775   mode++;
776 
777   for (i = 0; i < 8; i++) try_access(fnames[mode], i, OK);
778 }				/* access_standards */
779 
780 void try_access(fname, mode, test)
781 int mode, test;
782 char *fname;
783 {
784   if (access(fname, mode) != test) e(96);
785 }				/* try_access */
786 
787 
788 /* Err, make_and_fill_dirs, init_array, clear_array, comp_array,
789    try_close, try_unlink, Remove, get_mode, check, open_alot,
790    close_alot, clean_up_the_mess.
791 */
792 
793 /*****************************************************************************
794  *                              test READV/WRITEV                            *
795  ****************************************************************************/
796 #define TEST8_BUFSZCOUNT 3
797 #define TEST8_BUFSZMAX 65536
798 #define TEST8_IOVCOUNT 4
799 
800 void test08()
801 {
802   char buffer_read[TEST8_IOVCOUNT * TEST8_BUFSZMAX];
803   char buffer_write[TEST8_IOVCOUNT * TEST8_BUFSZMAX];
804   struct iovec iovec_read[TEST8_IOVCOUNT];
805   struct iovec iovec_write[TEST8_IOVCOUNT];
806   int fd, i, j, k, l, m;
807   ssize_t sz_read, sz_write;
808   size_t sz_read_exp, sz_read_sum, sz_write_sum;
809 
810   subtest = 8;
811 
812   /* try various combinations of buffer sizes */
813   for (i = 0; i <= TEST8_IOVCOUNT; i++)
814   for (j = 0; j < power(TEST8_BUFSZCOUNT, i); j++)
815   for (k = 0; k <= TEST8_IOVCOUNT; k++)
816   for (l = 0; l < power(TEST8_BUFSZCOUNT, k); l++)
817   {
818 	/* put data in the buffers */
819 	for (m = 0; m < sizeof(buffer_write); m++)
820 	{
821 		buffer_write[m] = m ^ (m >> 8);
822 		buffer_read[m] = ~buffer_write[m];
823 	}
824 
825 	/* set up the vectors to point to the buffers */
826 	sz_read_sum = iovec_setup(j, iovec_read, buffer_read, i);
827 	sz_write_sum = iovec_setup(l, iovec_write, buffer_write, k);
828 	sz_read_exp = (sz_read_sum < sz_write_sum) ?
829 		sz_read_sum : sz_write_sum;
830 
831 	/* test reading and writing */
832 	if ((fd = open("file08", O_RDWR | O_CREAT | O_TRUNC, 0644)) < 0) e(1);
833 	else {
834 		sz_write = writev(fd, iovec_write, k);
835 		if (sz_write != sz_write_sum) e(2);
836 		if (lseek(fd, 0, SEEK_SET) != 0) e(3);
837 		sz_read = readv(fd, iovec_read, i);
838 		if (sz_read != sz_read_exp)  e(4);
839 		else {
840 			if (!iovec_is_equal(iovec_read, iovec_write, sz_read))
841 				e(5);
842 		}
843 
844   		/* Remove testfile */
845  		Remove(fd, "file08");
846 	}
847   }
848 }				/* test08 */
849 
850 static int iovec_is_equal(struct iovec *x, struct iovec *y, size_t size)
851 {
852   int xpos = 0, xvec = 0, ypos = 0, yvec = 0;
853 
854   /* compare byte by byte */
855   while (size-- > 0)
856   {
857 	/* skip over zero-byte buffers and those that have been completed */
858 	while (xpos >= x[xvec].iov_len)
859 	{
860 		xpos -= x[xvec++].iov_len;
861 		assert(xvec < TEST8_IOVCOUNT);
862 	}
863 	while (ypos >= y[yvec].iov_len)
864 	{
865 		ypos -= y[yvec++].iov_len;
866 		assert(yvec < TEST8_IOVCOUNT);
867 	}
868 
869 	/* compare */
870 	if (((char *) x[xvec].iov_base)[xpos++] !=
871 		((char *) y[yvec].iov_base)[ypos++])
872 		return 0;
873   }
874 
875   /* no difference found */
876   return 1;
877 }
878 
879 static size_t iovec_setup(int pattern, struct iovec *iovec, char *buffer, int count)
880 {
881 	static const size_t bufsizes[TEST8_BUFSZCOUNT] = { 0, 1, TEST8_BUFSZMAX };
882 	int i;
883 	size_t sum = 0;
884 
885 	/* the pattern specifies each buffer */
886 	for (i = 0; i < TEST8_IOVCOUNT; i++)
887 	{
888 		iovec->iov_base = buffer;
889 		sum += iovec->iov_len = bufsizes[pattern % TEST8_BUFSZCOUNT];
890 
891 		iovec++;
892 		buffer += TEST8_BUFSZMAX;
893 		pattern /= TEST8_BUFSZCOUNT;
894 	}
895 
896 	return sum;
897 }
898 
899 static int power(int base, int exponent)
900 {
901 	int result = 1;
902 
903 	/* compute base^exponent */
904 	while (exponent-- > 0)
905 		result *= base;
906 
907 	return result;
908 }
909 
910 
911 /*****************************************************************************
912 *                                                                            *
913 *                          MAKE_AND_FILL_DIRS                                *
914 *                                                                            *
915 *****************************************************************************/
916 
917 void make_and_fill_dirs()
918  /* Create 8 dir.'s: "d---", "d--x", "d-w-", "d-wx", "dr--", "dr-x",     *
919   * "drw-", "drwx".                                     * Then create 8 files
920   * in "drwx", and some needed files in other dirs.  */
921 {
922   int mode, i;
923 
924   for (i = 0; i < 8; i++) {
925 	mkdir(dir[i], 0700);
926 	chown(dir[i], USER_ID, GROUP_ID);
927   }
928   setuid(USER_ID);
929   setgid(GROUP_ID);
930 
931   for (mode = 0; mode < 8; mode++) put_file_in_dir("drwx", mode);
932 
933   put_file_in_dir("d-wx", RWX);
934   put_file_in_dir("dr-x", RWX);
935   put_file_in_dir("drw-", RWX);
936 
937   chmod_8_dirs(8);		/* 8 means; 8 different modes */
938 
939 }				/* make_and_fill_dirs */
940 
941 void put_file_in_dir(dirname, mode)
942 char *dirname;
943 int mode;
944  /* Fill directory 'dirname' with file with mode 'mode'.   */
945 {
946   int nr;
947 
948   if (chdir(dirname) != OK) e(97);
949   else {
950 	/* Creat the file */
951 	if ((nr = creat(fnames[mode], mode * 0100)) < 0) e(98);
952 	else
953 		try_close(nr, fnames[mode]);
954 
955 	if (chdir("..") != OK) e(99);
956   }
957 }				/* put_file_in_dir */
958 
959 /*****************************************************************************
960 *                                                                            *
961 *                               MISCELLANEOUS                                *
962 *                                                                            *
963 *(all about arrays, 'try_close', 'try_unlink', 'Remove', 'get_mode')         *
964 *                                                                            *
965 *****************************************************************************/
966 
967 void init_array(a)
968 char *a;
969 {
970   int i;
971 
972   i = 0;
973   while (i++ < ARSIZE) *a++ = 'a' + (i % 26);
974 }				/* init_array */
975 
976 void clear_array(b)
977 char *b;
978 {
979   int i;
980 
981   i = 0;
982   while (i++ < ARSIZE) *b++ = '0';
983 
984 }				/* clear_array */
985 
986 int comp_array(a, b, range)
987 char *a, *b;
988 int range;
989 {
990   assert(range >= 0 && range <= ARSIZE);
991 
992   while (range-- && (*a++ == *b++));
993   if (*--a == *--b)
994 	return(OK);
995   else
996 	return(FAIL);
997 }				/* comp_array */
998 
999 void try_close(filedes, name)
1000 int filedes;
1001 char *name;
1002 {
1003   if (close(filedes) != OK) e(100);
1004 }				/* try_close */
1005 
1006 void try_unlink(fname)
1007 char *fname;
1008 {
1009   if (unlink(fname) != 0) e(101);
1010 }				/* try_unlink */
1011 
1012 void Remove(fdes, fname)
1013 int fdes;
1014 char *fname;
1015 {
1016   try_close(fdes, fname);
1017   try_unlink(fname);
1018 }				/* Remove */
1019 
1020 int get_mode(name)
1021 char *name;
1022 {
1023   struct stat stbf1;
1024 
1025   if (stat(name, &stbf1) != OK) {
1026 	e(102);
1027 	return(stbf1.st_mode);	/* return a mode which will cause *
1028 				 * error in the calling function  *
1029 				 * (file/dir bit)                 */
1030   } else
1031 	return(stbf1.st_mode & 07777);	/* take last 4 bits */
1032 }				/* get_mode */
1033 
1034 
1035 /*****************************************************************************
1036 *                                                                            *
1037 *                                ALOT-functions                              *
1038 *                                                                            *
1039 *****************************************************************************/
1040 
1041 int open_alot()
1042 {
1043   int i;
1044 
1045   for (i = 0; i < MAXOPEN; i++)
1046 	if (open(file[i], R) == FAIL) break;
1047 
1048   if (i == 0)
1049   	e(103);
1050   return(i);
1051 }				/* open_alot */
1052 
1053 int close_alot(number)
1054 int number;
1055 {
1056   int i, count = 0;
1057 
1058   if (number > MAXOPEN) e(104);
1059   else
1060 	for (i = FF; i < number + FF; i++)
1061 		if (close(i) != OK) count++;
1062 
1063   return(number - count);	/* return number of closed files */
1064 }				/* close_alot */
1065 
1066 /*****************************************************************************
1067 *                                                                            *
1068 *                         CLEAN UP THE MESS                                  *
1069 *                                                                            *
1070 *****************************************************************************/
1071 
1072 void clean_up_the_mess()
1073 {
1074   int i;
1075   char dirname[6];
1076 
1077   /* First remove 'alot' files */
1078   for (i = 0; i < MAXOPEN; i++) try_unlink(file[i]);
1079 
1080   /* Unlink the files in dir 'drwx' */
1081   if (chdir("drwx") != OK) e(105);
1082   else {
1083 	for (i = 0; i < 8; i++) try_unlink(fnames[i]);
1084 	if (chdir("..") != OK) e(106);
1085   }
1086 
1087   /* Before unlinking files in some dirs, make them writable */
1088   chmod_8_dirs(RWX);
1089 
1090   /* Unlink files in other dirs */
1091   try_unlink("d-wx/rwx");
1092   try_unlink("dr-x/rwx");
1093   try_unlink("drw-/rwx");
1094 
1095   /* Unlink dirs */
1096   for (i = 0; i < 8; i++) {
1097 	strcpy(dirname, "d");
1098 	strcat(dirname, fnames[i]);
1099 	/* 'dirname' contains the directoryname */
1100 	rmdir(dirname);
1101   }
1102 
1103   /* FINISH */
1104 }				/* clean_up_the_mess */
1105 
1106 void chmod_8_dirs(sw)
1107 int sw;				/* if switch == 8, give all different
1108 			 * mode,else the same mode */
1109 {
1110   int mode;
1111   int i;
1112 
1113   if (sw == 8)
1114 	mode = 0;
1115   else
1116 	mode = sw;
1117 
1118   for (i = 0; i < 8; i++) {
1119 	chmod(dir[i], 040000 + mode * 0100);
1120 	if (sw == 8) mode++;
1121   }
1122 }
1123 
1124