summaryrefslogtreecommitdiffstats
path: root/lex.cgi
diff options
context:
space:
mode:
authorSadeep Madurange <sadeep@asciimx.com>2026-08-12 23:29:03 +0800
committerSadeep Madurange <sadeep@asciimx.com>2026-08-12 23:29:03 +0800
commit5a86c7a637da1467c9890d31aaccdf4c428dd87d (patch)
treeacf0748a7e644e3bff5fa25807befbfdf6996773 /lex.cgi
parentdd2989b86b1a23469165048865945d48a2fd9e7b (diff)
downloadlex-5a86c7a637da1467c9890d31aaccdf4c428dd87d.tar.gz
Lock-file semaphore for CGI script.
Diffstat (limited to 'lex.cgi')
-rwxr-xr-xlex.cgi42
1 files changed, 39 insertions, 3 deletions
diff --git a/lex.cgi b/lex.cgi
index 9c11b28..797fa1c 100755
--- a/lex.cgi
+++ b/lex.cgi
@@ -2,13 +2,14 @@
use strict;
use warnings;
+use Email::MIME;
+use Fcntl qw(:flock);
use File::Spec;
use File::Find;
use File::Path qw(make_path);
-use Time::HiRes qw(time);
-use Email::MIME;
use OpenBSD::Pledge;
use OpenBSD::Unveil;
+use Time::HiRes qw(time);
my $start_time = time();
@@ -43,8 +44,9 @@ unveil("/dev/null", "rw") or die "unveil /dev/null failed: $!";
unveil($base_dir, "rwc") or die "unveil $base_dir failed: $!";
unveil() or die "unveil lock failed: $!";
-pledge('stdio rpath wpath cpath') or die "pledge failed: $!";
+pledge('stdio rpath wpath cpath flock') or die "pledge failed: $!";
+my $dop = 5;
my $log_file = "$base_dir/debug.log";
my $max_log_bytes = 1024 * 1024; # 1 MB cap
@@ -107,6 +109,40 @@ sub verify_pgp_signature {
return $verified ? 1 : 0;
}
+sub acquire_lock {
+ my ($max_slots) = @_;
+ my $lock_dir = "$base_dir/locks";
+
+ unless (-d $lock_dir) {
+ make_path($lock_dir) or do {
+ log_msg("ERROR: Failed to create lock dir $lock_dir: $!");
+ return undef;
+ };
+ }
+
+ for my $i (1 .. $max_slots) {
+ my $slot_file = "$lock_dir/slot_$i.lock";
+ my $fh;
+
+ unless (open($fh, '>>', $slot_file)) {
+ next;
+ }
+
+ if (flock($fh, LOCK_EX | LOCK_NB)) {
+ return $fh;
+ }
+ close($fh);
+ }
+
+ return undef; # All slots full
+}
+
+my $lock_fh = acquire_lock($dop);
+unless ($lock_fh) {
+ log_msg("WARN: Concurrency limit ($dop) reached. Dropping request.");
+ respond_ok();
+}
+
my $content_type = $ENV{'CONTENT_TYPE'} // '';
my $content_length = $ENV{'CONTENT_LENGTH'} // 0;