File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / tests / ftp.pm
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:16 2020 UTC (5 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    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>