1 /* Copyright (C) 2002-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <getopt.h>
21 #include <signal.h>
22 #include <stdlib.h>
23 #include <semaphore.h>
24 #include <sys/mman.h>
25 
26 #include <support/check.h>
27 #include <support/support.h>
28 #include <support/temp_file.h>
29 #include <support/xstdio.h>
30 #include <support/xunistd.h>
31 #include <support/xthread.h>
32 
33 static const char *command;
34 static const char *pidfile;
35 static const char *semfile;
36 static char *pidfilename;
37 static char *semfilename;
38 
39 static sem_t *sem;
40 
41 static void *
tf(void * arg)42 tf (void *arg)
43 {
44   char *cmd = xasprintf ("%s --direct --sem %s --pidfile %s",
45 			 command, semfilename, pidfilename);
46   system (cmd);
47   /* This call should never return.  */
48   return NULL;
49 }
50 
51 static void
sl(void)52 sl (void)
53 {
54   FILE *f = xfopen (pidfile, "w");
55 
56   fprintf (f, "%lld\n", (long long) getpid ());
57   fflush (f);
58 
59   if (sem_post (sem) != 0)
60     FAIL_EXIT1 ("sem_post: %m");
61 
62   struct flock fl =
63     {
64       .l_type = F_WRLCK,
65       .l_start = 0,
66       .l_whence = SEEK_SET,
67       .l_len = 1
68     };
69   if (fcntl (fileno (f), F_SETLK, &fl) != 0)
70     FAIL_EXIT1 ("fcntl (F_SETFL): %m");
71 
72   sigset_t ss;
73   sigfillset (&ss);
74   sigsuspend (&ss);
75   exit (0);
76 }
77 
78 
79 static void
do_prepare(int argc,char * argv[])80 do_prepare (int argc, char *argv[])
81 {
82   int semfd;
83   if (semfile == NULL)
84     semfd = create_temp_file ("tst-cancel7.", &semfilename);
85   else
86     semfd = open (semfile, O_RDWR);
87   TEST_VERIFY_EXIT (semfd != -1);
88 
89   sem = xmmap (NULL, sizeof (sem_t), PROT_READ | PROT_WRITE, MAP_SHARED,
90 	       semfd);
91   TEST_VERIFY_EXIT (sem != SEM_FAILED);
92   if (semfile == NULL)
93     {
94       xftruncate (semfd, sizeof (sem_t));
95       TEST_VERIFY_EXIT (sem_init (sem, 1, 0) != -1);
96     }
97 
98   if (command == NULL)
99     command = argv[0];
100 
101   if (pidfile)
102     sl ();
103 
104   int fd = create_temp_file ("tst-cancel7-pid-", &pidfilename);
105   if (fd == -1)
106     FAIL_EXIT1 ("create_temp_file failed: %m");
107 
108   xwrite (fd, " ", 1);
109   xclose (fd);
110 }
111 
112 
113 static int
do_test(void)114 do_test (void)
115 {
116   pthread_t th = xpthread_create (NULL, tf, NULL);
117 
118   /* Wait to cancel until after the pid is written.  */
119   if (sem_wait (sem) != 0)
120     FAIL_EXIT1 ("sem_wait: %m");
121 
122   xpthread_cancel (th);
123   void *r = xpthread_join (th);
124 
125   FILE *f = xfopen (pidfilename, "r+");
126 
127   long long ll;
128   if (fscanf (f, "%lld\n", &ll) != 1)
129     FAIL_EXIT1 ("fscanf: %m");
130 
131   struct flock fl =
132     {
133       .l_type = F_WRLCK,
134       .l_start = 0,
135       .l_whence = SEEK_SET,
136       .l_len = 1
137     };
138   if (fcntl (fileno (f), F_GETLK, &fl) != 0)
139     FAIL_EXIT1 ("fcntl: %m");
140 
141   if (fl.l_type != F_UNLCK)
142     {
143       printf ("child %lld still running\n", (long long) fl.l_pid);
144       if (fl.l_pid == ll)
145 	kill (fl.l_pid, SIGKILL);
146 
147       return 1;
148     }
149 
150   xfclose (f);
151 
152   return r != PTHREAD_CANCELED;
153 }
154 
155 static void
do_cleanup(void)156 do_cleanup (void)
157 {
158   FILE *f = fopen (pidfilename, "r+");
159   long long ll;
160 
161   if (f != NULL && fscanf (f, "%lld\n", &ll) == 1)
162     {
163       struct flock fl =
164 	{
165 	  .l_type = F_WRLCK,
166 	  .l_start = 0,
167 	  .l_whence = SEEK_SET,
168 	  .l_len = 1
169 	};
170       if (fcntl (fileno (f), F_GETLK, &fl) == 0 && fl.l_type != F_UNLCK
171 	  && fl.l_pid == ll)
172 	kill (fl.l_pid, SIGKILL);
173 
174       fclose (f);
175     }
176 }
177 
178 #define OPT_COMMAND	10000
179 #define OPT_PIDFILE	10001
180 #define OPT_SEMFILE	10002
181 #define CMDLINE_OPTIONS \
182   { "command", required_argument, NULL, OPT_COMMAND },	\
183   { "pidfile", required_argument, NULL, OPT_PIDFILE },  \
184   { "sem",     required_argument, NULL, OPT_SEMFILE },
185 static void
cmdline_process(int c)186 cmdline_process (int c)
187 {
188   switch (c)
189     {
190     case OPT_COMMAND:
191       command = optarg;
192       break;
193     case OPT_PIDFILE:
194       pidfile = optarg;
195       break;
196     case OPT_SEMFILE:
197       semfile = optarg;
198       break;
199     }
200 }
201 #define CMDLINE_PROCESS cmdline_process
202 #define CLEANUP_HANDLER do_cleanup
203 #define PREPARE do_prepare
204 #include <support/test-driver.c>
205