Annotation of embedaddon/curl/tests/ftp.pm, revision 1.1.1.1
1.1 misho 1: #***************************************************************************
2: # _ _ ____ _
3: # Project ___| | | | _ \| |
4: # / __| | | | |_) | |
5: # | (__| |_| | _ <| |___
6: # \___|\___/|_| \_\_____|
7: #
8: # Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
9: #
10: # This software is licensed as described in the file COPYING, which
11: # you should have received as part of this distribution. The terms
12: # are also available at https://curl.haxx.se/docs/copyright.html.
13: #
14: # You may opt to use, copy, modify, merge, publish, distribute and/or sell
15: # copies of the Software, and permit persons to whom the Software is
16: # furnished to do so, under the terms of the COPYING file.
17: #
18: # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19: # KIND, either express or implied.
20: #
21: ###########################################################################
22:
23: BEGIN {
24: # portable sleeping needs Time::HiRes
25: eval {
26: no warnings "all";
27: require Time::HiRes;
28: };
29: # portable sleeping falls back to native Sleep on Win32
30: eval {
31: no warnings "all";
32: require Win32;
33: }
34: }
35:
36: use strict;
37: use warnings;
38:
39: use serverhelp qw(
40: servername_id
41: mainsockf_pidfilename
42: datasockf_pidfilename
43: );
44:
45: use pathhelp qw(
46: os_is_win
47: );
48:
49: #######################################################################
50: # portable_sleep uses Time::HiRes::sleep if available and falls back
51: # to the classic approach of using select(undef, undef, undef, ...).
52: # even though that one is not portable due to being implemented using
53: # select on Windows: https://perldoc.perl.org/perlport.html#select
54: # Therefore it uses Win32::Sleep on Windows systems instead.
55: #
56: sub portable_sleep {
57: my ($seconds) = @_;
58:
59: if($Time::HiRes::VERSION) {
60: Time::HiRes::sleep($seconds);
61: }
62: elsif (os_is_win()) {
63: Win32::Sleep($seconds*1000);
64: }
65: else {
66: select(undef, undef, undef, $seconds);
67: }
68: }
69:
70: #######################################################################
71: # pidfromfile returns the pid stored in the given pidfile. The value
72: # of the returned pid will never be a negative value. It will be zero
73: # on any file related error or if a pid can not be extracted from the
74: # given file.
75: #
76: sub pidfromfile {
77: my $pidfile = $_[0];
78: my $pid = 0;
79:
80: if(-f $pidfile && -s $pidfile && open(PIDFH, "<$pidfile")) {
81: $pid = 0 + <PIDFH>;
82: close(PIDFH);
83: $pid = 0 unless($pid > 0);
84: }
85: return $pid;
86: }
87:
88: #######################################################################
89: # pidexists checks if a process with a given pid exists and is alive.
90: # This will return the positive pid if the process exists and is alive.
91: # This will return the negative pid if the process exists differently.
92: # This will return 0 if the process could not be found.
93: #
94: sub pidexists {
95: my $pid = $_[0];
96:
97: if($pid > 0) {
98: # verify if currently existing Windows process
99: if ($pid > 65536 && os_is_win()) {
100: $pid -= 65536;
101: if($^O ne 'MSWin32') {
102: my $filter = "PID eq $pid";
103: my $result = `tasklist -fi \"$filter\" 2>nul`;
104: if(index($result, "$pid") != -1) {
105: return -$pid;
106: }
107: return 0;
108: }
109: }
110:
111: # verify if currently existing and alive
112: if(kill(0, $pid)) {
113: return $pid;
114: }
115: }
116:
117: return 0;
118: }
119:
120: #######################################################################
121: # pidterm asks the process with a given pid to terminate gracefully.
122: #
123: sub pidterm {
124: my $pid = $_[0];
125:
126: if($pid > 0) {
127: # request the process to quit
128: if ($pid > 65536 && os_is_win()) {
129: $pid -= 65536;
130: if($^O ne 'MSWin32') {
131: my $filter = "PID eq $pid";
132: my $result = `tasklist -fi \"$filter\" 2>nul`;
133: if(index($result, "$pid") != -1) {
134: system("taskkill -fi \"$filter\" >nul 2>&1");
135: }
136: return;
137: }
138: }
139:
140: # signal the process to terminate
141: kill("TERM", $pid);
142: }
143: }
144:
145: #######################################################################
146: # pidkill kills the process with a given pid mercilessly and forcefully.
147: #
148: sub pidkill {
149: my $pid = $_[0];
150:
151: if($pid > 0) {
152: # request the process to quit
153: if ($pid > 65536 && os_is_win()) {
154: $pid -= 65536;
155: if($^O ne 'MSWin32') {
156: my $filter = "PID eq $pid";
157: my $result = `tasklist -fi \"$filter\" 2>nul`;
158: if(index($result, "$pid") != -1) {
159: system("taskkill -f -fi \"$filter\" >nul 2>&1");
160: # Windows XP Home compatibility
161: system("tskill $pid >nul 2>&1");
162: }
163: return;
164: }
165: }
166:
167: # signal the process to terminate
168: kill("KILL", $pid);
169: }
170: }
171:
172: #######################################################################
173: # pidwait waits for the process with a given pid to be terminated.
174: #
175: sub pidwait {
176: my $pid = $_[0];
177: my $flags = $_[1];
178:
179: # check if the process exists
180: if ($pid > 65536 && os_is_win()) {
181: if($flags == &WNOHANG) {
182: return pidexists($pid)?0:$pid;
183: }
184: while(pidexists($pid)) {
185: portable_sleep(0.01);
186: }
187: return $pid;
188: }
189:
190: # wait on the process to terminate
191: return waitpid($pid, $flags);
192: }
193:
194: #######################################################################
195: # processexists checks if a process with the pid stored in the given
196: # pidfile exists and is alive. This will return 0 on any file related
197: # error or if a pid can not be extracted from the given file. When a
198: # process with the same pid as the one extracted from the given file
199: # is currently alive this returns that positive pid. Otherwise, when
200: # the process is not alive, will return the negative value of the pid.
201: #
202: sub processexists {
203: use POSIX ":sys_wait_h";
204: my $pidfile = $_[0];
205:
206: # fetch pid from pidfile
207: my $pid = pidfromfile($pidfile);
208:
209: if($pid > 0) {
210: # verify if currently alive
211: if(pidexists($pid)) {
212: return $pid;
213: }
214: else {
215: # get rid of the certainly invalid pidfile
216: unlink($pidfile) if($pid == pidfromfile($pidfile));
217: # reap its dead children, if not done yet
218: pidwait($pid, &WNOHANG);
219: # negative return value means dead process
220: return -$pid;
221: }
222: }
223: return 0;
224: }
225:
226: #######################################################################
227: # killpid attempts to gracefully stop processes in the given pid list
228: # with a SIGTERM signal and SIGKILLs those which haven't died on time.
229: #
230: sub killpid {
231: use POSIX ":sys_wait_h";
232: my ($verbose, $pidlist) = @_;
233: my @requested;
234: my @signalled;
235: my @reapchild;
236:
237: # The 'pidlist' argument is a string of whitespace separated pids.
238: return if(not defined($pidlist));
239:
240: # Make 'requested' hold the non-duplicate pids from 'pidlist'.
241: @requested = split(' ', $pidlist);
242: return if(not @requested);
243: if(scalar(@requested) > 2) {
244: @requested = sort({$a <=> $b} @requested);
245: }
246: for(my $i = scalar(@requested) - 2; $i >= 0; $i--) {
247: if($requested[$i] == $requested[$i+1]) {
248: splice @requested, $i+1, 1;
249: }
250: }
251:
252: # Send a SIGTERM to processes which are alive to gracefully stop them.
253: foreach my $tmp (@requested) {
254: chomp $tmp;
255: if($tmp =~ /^(\d+)$/) {
256: my $pid = $1;
257: if($pid > 0) {
258: if(pidexists($pid)) {
259: print("RUN: Process with pid $pid signalled to die\n")
260: if($verbose);
261: pidterm($pid);
262: push @signalled, $pid;
263: }
264: else {
265: print("RUN: Process with pid $pid already dead\n")
266: if($verbose);
267: # if possible reap its dead children
268: pidwait($pid, &WNOHANG);
269: push @reapchild, $pid;
270: }
271: }
272: }
273: }
274:
275: # Allow all signalled processes five seconds to gracefully die.
276: if(@signalled) {
277: my $twentieths = 5 * 20;
278: while($twentieths--) {
279: for(my $i = scalar(@signalled) - 1; $i >= 0; $i--) {
280: my $pid = $signalled[$i];
281: if(!pidexists($pid)) {
282: print("RUN: Process with pid $pid gracefully died\n")
283: if($verbose);
284: splice @signalled, $i, 1;
285: # if possible reap its dead children
286: pidwait($pid, &WNOHANG);
287: push @reapchild, $pid;
288: }
289: }
290: last if(not scalar(@signalled));
291: portable_sleep(0.05);
292: }
293: }
294:
295: # Mercilessly SIGKILL processes still alive.
296: if(@signalled) {
297: foreach my $pid (@signalled) {
298: if($pid > 0) {
299: print("RUN: Process with pid $pid forced to die with SIGKILL\n")
300: if($verbose);
301: pidkill($pid);
302: # if possible reap its dead children
303: pidwait($pid, &WNOHANG);
304: push @reapchild, $pid;
305: }
306: }
307: }
308:
309: # Reap processes dead children for sure.
310: if(@reapchild) {
311: foreach my $pid (@reapchild) {
312: if($pid > 0) {
313: pidwait($pid, 0);
314: }
315: }
316: }
317: }
318:
319: #######################################################################
320: # killsockfilters kills sockfilter processes for a given server.
321: #
322: sub killsockfilters {
323: my ($proto, $ipvnum, $idnum, $verbose, $which) = @_;
324: my $server;
325: my $pidfile;
326: my $pid;
327:
328: return if($proto !~ /^(ftp|imap|pop3|smtp)$/);
329:
330: die "unsupported sockfilter: $which"
331: if($which && ($which !~ /^(main|data)$/));
332:
333: $server = servername_id($proto, $ipvnum, $idnum) if($verbose);
334:
335: if(!$which || ($which eq 'main')) {
336: $pidfile = mainsockf_pidfilename($proto, $ipvnum, $idnum);
337: $pid = processexists($pidfile);
338: if($pid > 0) {
339: printf("* kill pid for %s-%s => %d\n", $server,
340: ($proto eq 'ftp')?'ctrl':'filt', $pid) if($verbose);
341: pidkill($pid);
342: pidwait($pid, 0);
343: }
344: unlink($pidfile) if(-f $pidfile);
345: }
346:
347: return if($proto ne 'ftp');
348:
349: if(!$which || ($which eq 'data')) {
350: $pidfile = datasockf_pidfilename($proto, $ipvnum, $idnum);
351: $pid = processexists($pidfile);
352: if($pid > 0) {
353: printf("* kill pid for %s-data => %d\n", $server,
354: $pid) if($verbose);
355: pidkill($pid);
356: pidwait($pid, 0);
357: }
358: unlink($pidfile) if(-f $pidfile);
359: }
360: }
361:
362: #######################################################################
363: # killallsockfilters kills sockfilter processes for all servers.
364: #
365: sub killallsockfilters {
366: my $verbose = $_[0];
367:
368: for my $proto (('ftp', 'imap', 'pop3', 'smtp')) {
369: for my $ipvnum (('4', '6')) {
370: for my $idnum (('1', '2')) {
371: killsockfilters($proto, $ipvnum, $idnum, $verbose);
372: }
373: }
374: }
375: }
376:
377:
378: sub set_advisor_read_lock {
379: my ($filename) = @_;
380:
381: if(open(FILEH, ">$filename")) {
382: close(FILEH);
383: return;
384: }
385: printf "Error creating lock file $filename error: $!";
386: }
387:
388:
389: sub clear_advisor_read_lock {
390: my ($filename) = @_;
391:
392: if(-f $filename) {
393: unlink($filename);
394: }
395: }
396:
397:
398: 1;
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>