1 /* Check that closing a pipe with a nonempty buffer works.
2 #notarget: cris*-*-elf
3 #output: got: a\ngot: b\nexit: 0\n
4 */
5 
6 
7 #include <stddef.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <limits.h>
11 #include <unistd.h>
12 #include <sched.h>
13 #include <signal.h>
14 #include <errno.h>
15 #include <sys/types.h>
16 #include <sys/wait.h>
17 #include <string.h>
18 int pip[2];
19 
20 int pipemax;
21 
22 int
process(void * arg)23 process (void *arg)
24 {
25   char *s = arg;
26   int lots = pipemax + 256;
27   char *buf = malloc (lots);
28   int ret;
29 
30   if (buf == NULL)
31     abort ();
32 
33   *buf = *s;
34 
35   /* The first write should go straight through.  */
36   if (write (pip[1], buf, 1) != 1)
37     abort ();
38 
39   *buf = s[1];
40 
41   /* The second write may or may not be successful for the whole
42      write, but should be successful for at least the pipemax part.
43      As linux/limits.h clamps PIPE_BUF to 4096, but the page size is
44      actually 8k, we can get away with that much.  There should be no
45      error, though.  Doing this on host shows that for
46      x86_64-unknown-linux-gnu (2.6.14-1.1656_FC4) pipemax * 10 can be
47      successfully written, perhaps for similar reasons.  */
48   ret = write (pip[1], buf, lots);
49   if (ret < pipemax)
50     {
51       fprintf (stderr, "ret: %d, %s, %d\n", ret, strerror (errno), pipemax);
52       fflush (0);
53       abort ();
54     }
55 
56   return 0;
57 }
58 
59 int
main(void)60 main (void)
61 {
62   int retcode;
63   int pid;
64   int st = 0;
65   long stack[16384];
66   char buf[1];
67 
68   /* We need to turn this off because we don't want (to have to model) a
69      SIGPIPE resulting from the close.  */
70   if (signal (SIGPIPE, SIG_IGN) != SIG_DFL)
71     abort ();
72 
73   retcode = pipe (pip);
74 
75   if (retcode != 0)
76     {
77       fprintf (stderr, "Bad pipe %d\n", retcode);
78       abort ();
79     }
80 
81 #ifdef PIPE_MAX
82   pipemax = PIPE_MAX;
83 #else
84   pipemax = fpathconf (pip[1], _PC_PIPE_BUF);
85 #endif
86 
87   if (pipemax <= 0)
88     {
89       fprintf (stderr, "Bad pipemax %d\n", pipemax);
90       abort ();
91     }
92 
93   pid = clone (process, (char *) stack + sizeof (stack) - 64,
94 	       (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND)
95 	       | SIGCHLD, "ab");
96   if (pid <= 0)
97     {
98       fprintf (stderr, "Bad clone %d\n", pid);
99       abort ();
100     }
101 
102   while ((retcode = read (pip[0], buf, 1)) == 0)
103     ;
104 
105   if (retcode != 1)
106     {
107       fprintf (stderr, "Bad read 1: %d\n", retcode);
108       abort ();
109     }
110 
111   printf ("got: %c\n", buf[0]);
112 
113   /* Need to read out something from the second write too before
114      closing, or the writer can get EPIPE. */
115   while ((retcode = read (pip[0], buf, 1)) == 0)
116     ;
117 
118   if (retcode != 1)
119     {
120       fprintf (stderr, "Bad read 2: %d\n", retcode);
121       abort ();
122     }
123 
124   printf ("got: %c\n", buf[0]);
125 
126   if (close (pip[0]) != 0)
127     {
128       perror ("pip close");
129       abort ();
130     }
131 
132   retcode = waitpid (pid, &st, __WALL);
133 
134   if (retcode != pid || !WIFEXITED (st))
135     {
136       fprintf (stderr, "Bad wait %d:%d %x\n", pid, retcode, st);
137       perror ("errno");
138       abort ();
139     }
140 
141   printf ("exit: %d\n", WEXITSTATUS (st));
142   return 0;
143 }
144