From 4c4466e455fd6940700125f8c21b326564915913 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Fri, 6 Oct 2023 09:46:04 +0000 Subject: finalize DragonFlyBSD support require_bsd and require_mods(':fcntl_lock') are now supported in TestCommon to make it easier to maintain than a big list of regexps. getsockopt for SO_ACCEPTFILTER seems to always succeed, even if the retrieved struct is all zeroes. --- install/os.perl | 7 ++++--- lib/PublicInbox/Daemon.pm | 4 ++-- lib/PublicInbox/IPC.pm | 1 + lib/PublicInbox/MboxLock.pm | 10 +++++++--- lib/PublicInbox/POP3D.pm | 4 ++-- lib/PublicInbox/TestCommon.pm | 19 +++++++++++++++++-- t/ds-kqxs.t | 5 +++-- t/kqnotify.t | 28 +++++++++++++++++++++++++++- t/pop3d-limit.t | 4 +--- t/pop3d.t | 6 ++---- t/search.t | 2 +- xt/pop3d-mpop.t | 5 ++--- 12 files changed, 69 insertions(+), 26 deletions(-) diff --git a/install/os.perl b/install/os.perl index 4fcbcbe4..bf5c55c2 100644 --- a/install/os.perl +++ b/install/os.perl @@ -40,7 +40,7 @@ EOM last if $ID ne '' && $VERSION_ID ne ''; } $ID = 'linux' if $ID eq ''; # cf. os-release(5) -} elsif ($^O =~ m!\A(?:free|net|open)bsd\z!) { # TODO: net? dragonfly? +} elsif ($^O =~ m!\A(?:free|net|open)bsd\z! || $^O eq 'dragonfly') { $ID = $^O; require POSIX; (undef, undef, $release, $version) = POSIX::uname(); @@ -50,7 +50,8 @@ EOM die "$^O unsupported"; } $VERSION_ID //= 0; # numeric? could be 'sid', actually... -my %MIN_VER = (freebsd => v11, openbsd => v7.3, netbsd => v9.3); +my %MIN_VER = (freebsd => v11, openbsd => v7.3, netbsd => v9.3, + dragonfly => v6.4); if (defined(my $min_ver = $MIN_VER{$^O})) { my $vid = $VERSION_ID; @@ -63,7 +64,7 @@ EOM } sub pkg_fmt () { - if ($ID eq 'freebsd') { 'pkg' } + if ($ID =~ /\A(?:freebsd|dragonfly)\z/) { 'pkg' } # *shrug*, as long as the (Net|Open)BSD names don't conflict w/ FreeBSD elsif ($ID eq 'netbsd') { 'pkgin' } elsif ($ID eq 'openbsd') { 'pkg_add' } diff --git a/lib/PublicInbox/Daemon.pm b/lib/PublicInbox/Daemon.pm index a4c99cca..520cef72 100644 --- a/lib/PublicInbox/Daemon.pm +++ b/lib/PublicInbox/Daemon.pm @@ -634,9 +634,9 @@ sub defer_accept ($$) { my $sec = unpack('i', $x); return if $sec > 0; # systemd users may set a higher value setsockopt($s, IPPROTO_TCP, $TCP_DEFER_ACCEPT, 1); - } elsif ($^O =~ /\A(?:freebsd|netbsd)\z/) { + } elsif ($^O =~ /\A(?:freebsd|netbsd|dragonfly)\z/) { my $x = getsockopt($s, SOL_SOCKET, $SO_ACCEPTFILTER); - return if defined $x; # don't change if set + return if ($x // "\0") =~ /[^\0]/s; # don't change if set my $accf_arg = pack('a16a240', $af_name, ''); setsockopt($s, SOL_SOCKET, $SO_ACCEPTFILTER, $accf_arg); } diff --git a/lib/PublicInbox/IPC.pm b/lib/PublicInbox/IPC.pm index 839281b2..068c5623 100644 --- a/lib/PublicInbox/IPC.pm +++ b/lib/PublicInbox/IPC.pm @@ -437,6 +437,7 @@ sub DESTROY { my %NPROCESSORS_ONLN = ( linux => 84, freebsd => 58, + dragonfly => 58, openbsd => 503, netbsd => 1002 ); diff --git a/lib/PublicInbox/MboxLock.pm b/lib/PublicInbox/MboxLock.pm index 95aa9862..9d7d4a32 100644 --- a/lib/PublicInbox/MboxLock.pm +++ b/lib/PublicInbox/MboxLock.pm @@ -12,9 +12,13 @@ use PublicInbox::DS qw(now); # ugh... use autodie qw(chdir opendir unlink); our $TMPL = do { - if ($^O eq 'linux') { \'s @32' } - elsif ($^O =~ /bsd/) { \'@20 s @256' } # n.b. @32 may be enough... - else { eval { require File::FcntlLock; 1 } } + if ($^O eq 'linux') { + \'s @32' + } elsif ($^O =~ /bsd/ || $^O eq 'dragonfly') { + \'@20 s @256' # n.b. @32 may be enough... + } else { + eval { require File::FcntlLock; 1 } + } }; # This order matches Debian policy on Linux systems. diff --git a/lib/PublicInbox/POP3D.pm b/lib/PublicInbox/POP3D.pm index 2a9ccfdd..38e982ee 100644 --- a/lib/PublicInbox/POP3D.pm +++ b/lib/PublicInbox/POP3D.pm @@ -15,7 +15,7 @@ use File::Temp 0.19 (); # 0.19 for ->newdir use Fcntl qw(F_SETLK F_UNLCK F_WRLCK SEEK_SET); my ($FLOCK_TMPL, @FLOCK_ORDER); # are all BSDs the same "struct flock"? tested Free+Net+Open... -if ($^O eq 'linux' || $^O =~ /bsd/) { +if ($^O =~ /\A(?:linux|dragonfly)\z/ || $^O =~ /bsd/) { require Config; my $off_t; my $sz = $Config::Config{lseeksize}; @@ -28,7 +28,7 @@ if ($^O eq 'linux' || $^O =~ /bsd/) { if ($^O eq 'linux') { $FLOCK_TMPL = "ss\@8$off_t$off_t\@32"; @FLOCK_ORDER = qw(l_type l_whence l_start l_len); - } elsif ($^O =~ /bsd/) { # @32 may be enough + } else { # *bsd including dragonfly $FLOCK_TMPL = "${off_t}${off_t}lss\@256"; @FLOCK_ORDER = qw(l_start l_len l_pid l_type l_whence); } diff --git a/lib/PublicInbox/TestCommon.pm b/lib/PublicInbox/TestCommon.pm index 32213fde..323152b4 100644 --- a/lib/PublicInbox/TestCommon.pm +++ b/lib/PublicInbox/TestCommon.pm @@ -23,7 +23,7 @@ BEGIN { @EXPORT = qw(tmpdir tcp_server tcp_connect require_git require_mods run_script start_script key2sub xsys xsys_e xqx eml_load tick have_xapian_compact json_utf8 setup_public_inboxes create_inbox - create_coderepo no_scm_rights + create_coderepo require_bsd quit_waiter_pipe wait_for_eof tcp_host_port test_lei lei lei_ok $lei_out $lei_err $lei_opt test_httpd xbail require_cmd is_xdeeply tail_f @@ -35,6 +35,15 @@ BEGIN { push @EXPORT, @methods; } +sub require_bsd (;$) { + state $ok = ($^O =~ m!\A(?:free|net|open)bsd\z! || + $^O eq 'dragonfly'); + return 1 if $ok; + return if defined(wantarray); + my $m = "$0 is BSD-only (\$^O=$^O)"; + @_ ? skip($m) : plan(skip_all => $m); +} + sub xbail (@) { BAIL_OUT join(' ', map { ref() ? (explain($_)) : ($_) } @_) } sub eml_load ($) { @@ -136,7 +145,8 @@ my %IPv6_VERSION = ( sub need_accept_filter ($) { my ($af) = @_; return if $^O eq 'netbsd'; # since NetBSD 5.0 - skip 'SO_ACCEPTFILTER is FreeBSD/NetBSD-only' if $^O ne 'freebsd'; + $^O =~ /\A(?:freebsd|dragonfly)\z/ or + skip 'SO_ACCEPTFILTER is FreeBSD/NetBSD/Dragonfly-only so far'; state $tried = {}; ($tried->{$af} //= system("kldstat -m $af >/dev/null")) and skip "$af not loaded: kldload $af"; @@ -175,6 +185,11 @@ sub require_mods { push @need, $msg; next; } + } elsif ($mod eq ':fcntl_lock') { + next if $^O eq 'linux' || require_bsd; + diag "untested platform: $^O, ". + "requiring File::FcntlLock..."; + push @mods, 'File::FcntlLock'; } elsif ($mod =~ /\A\+(accf_.*)\z/) { need_accept_filter($1); next diff --git a/t/ds-kqxs.t b/t/ds-kqxs.t index 57acb53f..87f7199d 100644 --- a/t/ds-kqxs.t +++ b/t/ds-kqxs.t @@ -6,8 +6,9 @@ use v5.12; use Test::More; unless (eval { require IO::KQueue }) { - my $m = $^O !~ /bsd/ ? 'DSKQXS is only for *BSD systems' - : "no IO::KQueue, skipping $0: $@"; + my $m = ($^O =~ /bsd/ || $^O eq 'dragonfly') ? + "no IO::KQueue, skipping $0: $@" : + 'DSKQXS is only for *BSD systems'; plan skip_all => $m; } diff --git a/t/kqnotify.t b/t/kqnotify.t index edecf2e1..cf32b633 100644 --- a/t/kqnotify.t +++ b/t/kqnotify.t @@ -7,7 +7,7 @@ use v5.12; use PublicInbox::TestCommon; use autodie; -plan skip_all => 'KQNotify is only for *BSD systems' if $^O !~ /bsd/; +require_bsd; require_mods('IO::KQueue'); use_ok 'PublicInbox::KQNotify'; my ($tmpdir, $for_destroy) = tmpdir(); @@ -33,9 +33,35 @@ $hit = [ grep(m!/link$!, @read) ]; is_deeply($hit, ["$tmpdir/new/link"], 'link(2) detected (via NOTE_WRITE)') or diag explain(\@read); +{ + my $d = "$tmpdir/new/ANOTHER"; + mkdir $d; + $hit = [ map { $_->fullname } $kqn->read ]; + is_xdeeply($hit, [ $d ], 'mkdir detected'); + rmdir $d; + # TODO: should we always watch for directory removals? +} + $w->cancel; link("$tmpdir/new/tst", "$tmpdir/new/link2"); $hit = [ map { $_->fullname } $kqn->read ]; is_deeply($hit, [], 'link(2) not detected after cancel'); +# rearm: +my $GONE = PublicInbox::KQNotify::NOTE_DELETE() | + PublicInbox::KQNotify::NOTE_REVOKE() | + PublicInbox::KQNotify::NOTE_ATTRIB() | + PublicInbox::KQNotify::NOTE_WRITE() | + PublicInbox::KQNotify::NOTE_RENAME(); +$w = $kqn->watch("$tmpdir/new", $mask|$GONE); +my @unlink = sort glob("$tmpdir/new/*"); +unlink(@unlink); +$hit = [ sort(map { $_->fullname } $kqn->read) ]; +is_xdeeply($hit, \@unlink, 'unlinked files match'); + +# this is unreliable on Dragonfly tmpfs (fixed post-6.4) +rmdir "$tmpdir/new"; +$hit = [ sort(map { $_->fullname } $kqn->read) ]; +is(scalar(@$hit), 1, 'detected self removal'); + done_testing; diff --git a/t/pop3d-limit.t b/t/pop3d-limit.t index 00da477d..79e320af 100644 --- a/t/pop3d-limit.t +++ b/t/pop3d-limit.t @@ -3,9 +3,7 @@ # License: AGPL-3.0+ use v5.12; use PublicInbox::TestCommon; -require_mods(qw(DBD::SQLite Net::POP3)); -$^O =~ /\A(?:linux|(?:free|net|open)bsd)\z/ or - require_mods(qw(File::FcntlLock)); +require_mods(qw(DBD::SQLite Net::POP3 :fcntl_lock)); use autodie; my ($tmpdir, $for_destroy) = tmpdir(); mkdir("$tmpdir/p3state"); diff --git a/t/pop3d.t b/t/pop3d.t index fce4a788..ee19f2d7 100644 --- a/t/pop3d.t +++ b/t/pop3d.t @@ -12,10 +12,8 @@ unless (-r $key && -r $cert) { } # Net::POP3 is part of the standard library, but distros may split it off... -require_mods(qw(DBD::SQLite Net::POP3 IO::Socket::SSL)); -require_git('2.6'); # for v2 -$^O =~ /\A(?:linux|(?:free|net|open)bsd)\z/ or - require_mods(qw(File::FcntlLock)); +require_mods(qw(DBD::SQLite Net::POP3 IO::Socket::SSL :fcntl_lock)); +require_git(v2.6); # for v2 use_ok 'IO::Socket::SSL'; use_ok 'PublicInbox::TLS'; my ($tmpdir, $for_destroy) = tmpdir(); diff --git a/t/search.t b/t/search.t index 636dc5cf..282ae586 100644 --- a/t/search.t +++ b/t/search.t @@ -440,7 +440,7 @@ my $dir_mask = 02770; # FreeBSD, OpenBSD and NetBSD do not allow non-root users to set S_ISGID, # so git doesn't set it, either (see DIR_HAS_BSD_GROUP_SEMANTICS in git.git) # Presumably all *BSDs behave the same way. -if ($^O =~ /\A.+bsd\z/i) { +if (require_bsd) { $all_mask = 0777; $dir_mask = 0770; } diff --git a/xt/pop3d-mpop.t b/xt/pop3d-mpop.t index 9da1050c..ff8bb5dc 100644 --- a/xt/pop3d-mpop.t +++ b/xt/pop3d-mpop.t @@ -12,9 +12,8 @@ my $inboxdir = $ENV{GIANT_INBOX_DIR}; plan skip_all => "bad characters in $inboxdir" if $inboxdir =~ m![^\w\.\-/]!; my $uuidgen = require_cmd('uuidgen'); my $mpop = require_cmd('mpop'); -require_mods(qw(DBD::SQLite)); -require_git('2.6'); # for v2 -require_mods(qw(File::FcntlLock)) if $^O !~ /\A(?:linux|freebsd)\z/; +require_mods(qw(DBD::SQLite :fcntl_lock)); +require_git(v2.6); # for v2 my ($tmpdir, $for_destroy) = tmpdir(); my $cfg = "$tmpdir/cfg"; -- cgit v1.2.3-24-ge0c7