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>