ftp.pm 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. #***************************************************************************
  2. # _ _ ____ _
  3. # Project ___| | | | _ \| |
  4. # / __| | | | |_) | |
  5. # | (__| |_| | _ <| |___
  6. # \___|\___/|_| \_\_____|
  7. #
  8. # Copyright (C) 1998 - 2010, 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 http://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. use strict;
  23. use warnings;
  24. use serverhelp qw(
  25. servername_id
  26. mainsockf_pidfilename
  27. datasockf_pidfilename
  28. );
  29. #######################################################################
  30. # pidfromfile returns the pid stored in the given pidfile. The value
  31. # of the returned pid will never be a negative value. It will be zero
  32. # on any file related error or if a pid can not be extracted from the
  33. # given file.
  34. #
  35. sub pidfromfile {
  36. my $pidfile = $_[0];
  37. my $pid = 0;
  38. if(-f $pidfile && -s $pidfile && open(PIDFH, "<$pidfile")) {
  39. $pid = 0 + <PIDFH>;
  40. close(PIDFH);
  41. $pid = 0 unless($pid > 0);
  42. }
  43. return $pid;
  44. }
  45. #######################################################################
  46. # processexists checks if a process with the pid stored in the given
  47. # pidfile exists and is alive. This will return 0 on any file related
  48. # error or if a pid can not be extracted from the given file. When a
  49. # process with the same pid as the one extracted from the given file
  50. # is currently alive this returns that positive pid. Otherwise, when
  51. # the process is not alive, will return the negative value of the pid.
  52. #
  53. sub processexists {
  54. use POSIX ":sys_wait_h";
  55. my $pidfile = $_[0];
  56. # fetch pid from pidfile
  57. my $pid = pidfromfile($pidfile);
  58. if($pid > 0) {
  59. # verify if currently alive
  60. if(kill(0, $pid)) {
  61. return $pid;
  62. }
  63. else {
  64. # get rid of the certainly invalid pidfile
  65. unlink($pidfile) if($pid == pidfromfile($pidfile));
  66. # reap its dead children, if not done yet
  67. waitpid($pid, &WNOHANG);
  68. # negative return value means dead process
  69. return -$pid;
  70. }
  71. }
  72. return 0;
  73. }
  74. #######################################################################
  75. # killpid attempts to gracefully stop processes in the given pid list
  76. # with a SIGTERM signal and SIGKILLs those which haven't died on time.
  77. #
  78. sub killpid {
  79. use POSIX ":sys_wait_h";
  80. my ($verbose, $pidlist) = @_;
  81. my @requested;
  82. my @signalled;
  83. my @reapchild;
  84. # The 'pidlist' argument is a string of whitespace separated pids.
  85. return if(not defined($pidlist));
  86. # Make 'requested' hold the non-duplicate pids from 'pidlist'.
  87. @requested = split(' ', $pidlist);
  88. return if(not @requested);
  89. if(scalar(@requested) > 2) {
  90. @requested = sort({$a <=> $b} @requested);
  91. }
  92. for(my $i = scalar(@requested) - 2; $i >= 0; $i--) {
  93. if($requested[$i] == $requested[$i+1]) {
  94. splice @requested, $i+1, 1;
  95. }
  96. }
  97. # Send a SIGTERM to processes which are alive to gracefully stop them.
  98. foreach my $tmp (@requested) {
  99. chomp $tmp;
  100. if($tmp =~ /^(\d+)$/) {
  101. my $pid = $1;
  102. if($pid > 0) {
  103. if(kill(0, $pid)) {
  104. print("RUN: Process with pid $pid signalled to die\n")
  105. if($verbose);
  106. kill("TERM", $pid);
  107. push @signalled, $pid;
  108. }
  109. else {
  110. print("RUN: Process with pid $pid already dead\n")
  111. if($verbose);
  112. # if possible reap its dead children
  113. waitpid($pid, &WNOHANG);
  114. push @reapchild, $pid;
  115. }
  116. }
  117. }
  118. }
  119. # Allow all signalled processes five seconds to gracefully die.
  120. if(@signalled) {
  121. my $twentieths = 5 * 20;
  122. while($twentieths--) {
  123. for(my $i = scalar(@signalled) - 1; $i >= 0; $i--) {
  124. my $pid = $signalled[$i];
  125. if(!kill(0, $pid)) {
  126. print("RUN: Process with pid $pid gracefully died\n")
  127. if($verbose);
  128. splice @signalled, $i, 1;
  129. # if possible reap its dead children
  130. waitpid($pid, &WNOHANG);
  131. push @reapchild, $pid;
  132. }
  133. }
  134. last if(not scalar(@signalled));
  135. select(undef, undef, undef, 0.05);
  136. }
  137. }
  138. # Mercilessly SIGKILL processes still alive.
  139. if(@signalled) {
  140. foreach my $pid (@signalled) {
  141. if($pid > 0) {
  142. print("RUN: Process with pid $pid forced to die with SIGKILL\n")
  143. if($verbose);
  144. kill("KILL", $pid);
  145. # if possible reap its dead children
  146. waitpid($pid, &WNOHANG);
  147. push @reapchild, $pid;
  148. }
  149. }
  150. }
  151. # Reap processes dead children for sure.
  152. if(@reapchild) {
  153. foreach my $pid (@reapchild) {
  154. if($pid > 0) {
  155. waitpid($pid, 0);
  156. }
  157. }
  158. }
  159. }
  160. #######################################################################
  161. # killsockfilters kills sockfilter processes for a given server.
  162. #
  163. sub killsockfilters {
  164. my ($proto, $ipvnum, $idnum, $verbose, $which) = @_;
  165. my $server;
  166. my $pidfile;
  167. my $pid;
  168. return if($proto !~ /^(ftp|imap|pop3|smtp)$/);
  169. die "unsupported sockfilter: $which"
  170. if($which && ($which !~ /^(main|data)$/));
  171. $server = servername_id($proto, $ipvnum, $idnum) if($verbose);
  172. if(!$which || ($which eq 'main')) {
  173. $pidfile = mainsockf_pidfilename($proto, $ipvnum, $idnum);
  174. $pid = processexists($pidfile);
  175. if($pid > 0) {
  176. printf("* kill pid for %s-%s => %d\n", $server,
  177. ($proto eq 'ftp')?'ctrl':'filt', $pid) if($verbose);
  178. kill("KILL", $pid);
  179. waitpid($pid, 0);
  180. }
  181. unlink($pidfile) if(-f $pidfile);
  182. }
  183. return if($proto ne 'ftp');
  184. if(!$which || ($which eq 'data')) {
  185. $pidfile = datasockf_pidfilename($proto, $ipvnum, $idnum);
  186. $pid = processexists($pidfile);
  187. if($pid > 0) {
  188. printf("* kill pid for %s-data => %d\n", $server,
  189. $pid) if($verbose);
  190. kill("KILL", $pid);
  191. waitpid($pid, 0);
  192. }
  193. unlink($pidfile) if(-f $pidfile);
  194. }
  195. }
  196. #######################################################################
  197. # killallsockfilters kills sockfilter processes for all servers.
  198. #
  199. sub killallsockfilters {
  200. my $verbose = $_[0];
  201. for my $proto (('ftp', 'imap', 'pop3', 'smtp')) {
  202. for my $ipvnum (('4', '6')) {
  203. for my $idnum (('1', '2')) {
  204. killsockfilters($proto, $ipvnum, $idnum, $verbose);
  205. }
  206. }
  207. }
  208. }
  209. sub set_advisor_read_lock {
  210. my ($filename) = @_;
  211. if(open(FILEH, ">$filename")) {
  212. close(FILEH);
  213. return;
  214. }
  215. printf "Error creating lock file $filename error: $!";
  216. }
  217. sub clear_advisor_read_lock {
  218. my ($filename) = @_;
  219. if(-f $filename) {
  220. unlink($filename);
  221. }
  222. }
  223. 1;