update
[nethome.git] / redhat / my / writew.c
1 #define _GNU_SOURCE 1
2 #include <dlfcn.h>
3 #include <unistd.h>
4 #include <fcntl.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <assert.h>
9
10 static int (*fputs2) (const char *s, FILE *stream) = NULL;
11 static size_t (*fwrite2) (const void *ptr, size_t size, size_t nmemb,
12                           FILE *stream);
13 static int is_gdb;
14
15 static void __attribute__((constructor))
16 init (void)
17 {
18   if (getenv ("WRITEW_IS_GDB"))
19     {
20       /* GDB */
21       unsetenv ("LD_PRELOAD");
22       is_gdb = 1;
23     }
24   else
25     {
26       /* expect */
27       setenv ("WRITEW_IS_GDB", "1", 1);
28     }
29   fputs2 = dlsym (RTLD_NEXT, "fputs");
30   assert (fputs2 != NULL);
31   fwrite2 = dlsym (RTLD_NEXT, "fwrite");
32   assert (fwrite2 != NULL);
33 }
34
35 static int
36 pid_is_sleeping (pid_t pid)
37 {
38   FILE *status_file;
39   char buf[100];
40   int retval = 0;
41
42   snprintf (buf, sizeof (buf), "/proc/%d/status", (int) pid);
43   status_file = fopen (buf, "r");
44   if (status_file != NULL)
45     {
46       int have_state = 0;
47
48       while (fgets (buf, sizeof (buf), status_file))
49         {
50           if (strncmp (buf, "State:", 6) == 0)
51             {
52               have_state = 1;
53               break;
54             }
55         }
56       if (have_state && strstr (buf, "S (sleeping)") != NULL)
57         retval = 1;
58       fclose (status_file);
59     }
60   return retval;
61 }
62
63 static void
64 delay (void)
65 {
66   pid_t expect_pid = getppid ();
67
68   do
69     usleep (1000 * 1000 / 100);
70   while (!pid_is_sleeping (expect_pid));
71 }
72
73 int
74 fputs (const char *s, FILE *stream)
75 {
76   int retval = fputs2 (s, stream);
77
78   if (is_gdb && fileno (stream) == STDOUT_FILENO && strchr (s, '\n'))
79     delay ();
80
81   return retval;
82 }
83
84 size_t
85 fwrite (const void *ptr, size_t size, size_t nmemb, FILE *stream)
86 {
87   size_t retval = fwrite2 (ptr, size, nmemb, stream);
88
89   if (is_gdb && fileno (stream) == STDOUT_FILENO
90       && memchr (ptr, '\n', size * nmemb))
91     delay ();
92
93   return retval;
94 }