X-Git-Url: https://sipb.mit.edu/gitweb.cgi/ikiwiki.git/blobdiff_plain/ccd3a7e2c2fb5307b84abc79e7d0b897621e2850..312b7d05f82045f400931c8e110efb7d76b69eed:/ikiwiki-mass-rebuild diff --git a/ikiwiki-mass-rebuild b/ikiwiki-mass-rebuild index 7ec41e98f..f13033e7f 100755 --- a/ikiwiki-mass-rebuild +++ b/ikiwiki-mass-rebuild @@ -1,29 +1,115 @@ -#!/bin/sh -set -e +#!/usr/bin/perl +use warnings; +use strict; -action="$@" +sub supplemental_groups { + my $user=shift; -wikilist=/etc/ikiwiki/wikilist + my @list; + while (my @fields=getgrent()) { + if (grep { $_ eq $user } split(' ', $fields[3])) { + push @list, $fields[2]; + } + } -processline () { - user="$1" - setup="$2" - - if [ -z "$user" ] || [ -z "$setup" ]; then - echo "parse failure in /etc/ikiwiki/wikilist, line: '$user $setup'" >&2 - exit 1 - fi + return @list; +} + +sub samelists { + my %a=map { $_ => 1 } split(' ', shift()); + my %b=map { $_ => 1 } split(' ', shift()); + + foreach my $i (keys %b) { + if (! exists $a{$i}) { + return 0; + } + } + foreach my $i (keys %a) { + if (! exists $b{$i}) { + return 0; + } + } + return 1; +} + +sub processline { + my $user=shift; + my $setup=shift; - if [ ! -f "$setup" ]; then - echo "warning: $setup specified in /etc/ikiwiki/wikilist does not exist, skipping" >&2 - else - echo "Processing $setup as user $user ..." - su "$user" -c "ikiwiki -setup $setup $action" - fi + if (! getpwnam("$user")) { + print STDERR "warning: user $user does not exist\n"; + return + } + if (! -f "$setup") { + print STDERR "warning: $setup does not exist, skipping\n"; + return; + } + print "Processing $setup as user $user ...\n"; + # su is not used because it passes arguments through the shell, + # which is not safe for untrusted setup file names. + defined(my $pid = fork) or die "Can’t fork: $!"; + if (! $pid) { + my ($uuid, $ugid) = (getpwnam($user))[2, 3]; + my $grouplist=join(" ", $ugid, sort {$a <=> $b} $ugid, supplemental_groups($user)); + if (! samelists(($)=$grouplist), $grouplist)) { + die "failed to set egid $grouplist (got back $))"; + } + $(=$ugid; + $<=$uuid; + $>=$uuid; + if ($< != $uuid || $> != $uuid || $( != $ugid) { + die "failed to drop permissions to $user"; + } + %ENV=( + PATH => $ENV{PATH}, + HOME => (getpwnam($user))[7], + ); + exec("ikiwiki", "-setup", $setup, @ARGV); + die "failed to run ikiwiki: $!"; + } + waitpid($pid,0); + if ($?) { + print STDERR "Processing $setup as user $user failed with code $?\n"; + } +} + +sub processlist { + my $file=shift; + my $forceuser=shift; + + my $list; + open ($list, "<$file") || die "$file: $!"; + while (<$list>) { + chomp; + s/^\s+//; + s/\s+$//; + next if /^#/ || ! length; + + if (/^([^\s]+)\s+([^\s]+)$/) { + my $user=$1; + my $setup=$2; + if (defined $forceuser && $forceuser ne $user) { + print STDERR "warning: in $file line $., attempt to set user to $user, but user forced to $forceuser. Skipping\n"; + } + processline($user, $setup); + } + elsif (/^([^\s]+)$/) { + my $user=$1; + my $home=(getpwnam($user))[7]; + if (defined $home && -d $home) { + my $dotfile="$home/.ikiwiki/wikilist"; + if (-e $dotfile) { + processlist($dotfile, $user); + } + } + } + } + close $list; +} + +my $wikilist="/etc/ikiwiki/wikilist"; + +if (-e $wikilist) { + processlist($wikilist); } -if [ -e "$wikilist" ]; then - grep -v '^#' $wikilist | grep -v '^$' | while read line; do - processline $line - done -fi