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 * |
42 | tf (void *arg) |
43 | { |
44 | char *cmd = xasprintf (format: "%s --direct --sem %s --pidfile %s" , |
45 | command, semfilename, pidfilename); |
46 | system (command: cmd); |
47 | /* This call should never return. */ |
48 | return NULL; |
49 | } |
50 | |
51 | static void |
52 | sl (void) |
53 | { |
54 | FILE *f = xfopen (path: pidfile, mode: "w" ); |
55 | |
56 | fprintf (f, "%lld\n" , (long long) getpid ()); |
57 | fflush (f); |
58 | |
59 | if (sem_post (sem: 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 (fd: fileno (f), F_SETLK, &fl) != 0) |
70 | FAIL_EXIT1 ("fcntl (F_SETFL): %m" ); |
71 | |
72 | sigset_t ss; |
73 | sigfillset (&ss); |
74 | sigsuspend (set: &ss); |
75 | exit (0); |
76 | } |
77 | |
78 | |
79 | static void |
80 | do_prepare (int argc, char *argv[]) |
81 | { |
82 | int semfd; |
83 | if (semfile == NULL) |
84 | semfd = create_temp_file (base: "tst-cancel7." , filename: &semfilename); |
85 | else |
86 | semfd = open (file: semfile, O_RDWR); |
87 | TEST_VERIFY_EXIT (semfd != -1); |
88 | |
89 | sem = xmmap (NULL, length: sizeof (sem_t), PROT_READ | PROT_WRITE, MAP_SHARED, |
90 | fd: semfd); |
91 | TEST_VERIFY_EXIT (sem != SEM_FAILED); |
92 | if (semfile == NULL) |
93 | { |
94 | xftruncate (fd: semfd, length: 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 (base: "tst-cancel7-pid-" , filename: &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 |
114 | do_test (void) |
115 | { |
116 | pthread_t th = xpthread_create (NULL, thread_func: tf, NULL); |
117 | |
118 | /* Wait to cancel until after the pid is written. */ |
119 | if (sem_wait (sem: sem) != 0) |
120 | FAIL_EXIT1 ("sem_wait: %m" ); |
121 | |
122 | xpthread_cancel (thr: th); |
123 | void *r = xpthread_join (thr: th); |
124 | |
125 | FILE *f = xfopen (path: pidfilename, mode: "r+" ); |
126 | |
127 | long long ll; |
128 | if (fscanf (stream: f, format: "%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 (fd: fileno (f), F_GETLK, &fl) != 0) |
139 | FAIL_EXIT1 ("fcntl: %m" ); |
140 | |
141 | if (fl.l_type != F_UNLCK) |
142 | { |
143 | printf (format: "child %lld still running\n" , (long long) fl.l_pid); |
144 | if (fl.l_pid == ll) |
145 | kill (pid: fl.l_pid, SIGKILL); |
146 | |
147 | return 1; |
148 | } |
149 | |
150 | xfclose (f); |
151 | |
152 | return r != PTHREAD_CANCELED; |
153 | } |
154 | |
155 | static void |
156 | do_cleanup (void) |
157 | { |
158 | FILE *f = fopen (pidfilename, "r+" ); |
159 | long long ll; |
160 | |
161 | if (f != NULL && fscanf (stream: f, format: "%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 (fd: fileno (f), F_GETLK, &fl) == 0 && fl.l_type != F_UNLCK |
171 | && fl.l_pid == ll) |
172 | kill (pid: 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 |
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 | |