Merge remote-tracking branch 'intrigeri/po'
[ikiwiki] / ikiwiki-mass-rebuild
1 #!/usr/bin/perl
2 use warnings;
3 use strict;
4
5 sub supplemental_groups {
6         my $user=shift;
7
8         my @list;
9         while (my @fields=getgrent()) {
10                 if (grep { $_ eq $user } split(' ', $fields[3])) {
11                         push @list, $fields[2];
12                 }
13         }
14
15         return @list;
16 }
17
18 sub samelists {
19         my %a=map { $_ => 1 } split(' ', shift());
20         my %b=map { $_ => 1 } split(' ', shift());
21
22         foreach my $i (keys %b) {
23                 if (! exists $a{$i}) {
24                         return 0;
25                 }
26         }
27         foreach my $i (keys %a) {
28                 if (! exists $b{$i}) {
29                         return 0;
30                 }
31         }
32         return 1;
33 }
34
35 sub processline {
36         my $user=shift;
37         my $setup=shift;
38         
39         if (! getpwnam("$user")) {
40                 print STDERR "warning: user $user does not exist\n";
41                 return
42         }
43         if (! -f "$setup") {
44                 print STDERR "warning: $setup does not exist, skipping\n";
45                 return;
46         }
47         print "Processing $setup as user $user ...\n";
48         # su is not used because it passes arguments through the shell,
49         # which is not safe for untrusted setup file names.
50         defined(my $pid = fork) or die "Can’t fork: $!";
51         if (! $pid) {
52                 my ($uuid, $ugid) = (getpwnam($user))[2, 3];
53                 my $grouplist=join(" ", $ugid, sort {$a <=> $b} $ugid, supplemental_groups($user));
54                 if (! samelists(($)=$grouplist), $grouplist)) {
55                         die "failed to set egid $grouplist (got back $))";
56                 }
57                 $(=$ugid;
58                 $<=$uuid;
59                 $>=$uuid;
60                 if ($< != $uuid || $> != $uuid || $( != $ugid) {
61                         die "failed to drop permissions to $user";
62                 }
63                 %ENV=(
64                         PATH => $ENV{PATH},
65                         HOME => (getpwnam($user))[7],
66                 );
67                 exec("ikiwiki", "-setup", $setup, @ARGV);
68                 die "failed to run ikiwiki: $!";
69         }
70         waitpid($pid,0);
71         if ($?) {
72                 print STDERR "Processing $setup as user $user failed with code $?\n";
73         }
74 }
75
76 sub processlist {
77         my $file=shift;
78         my $forceuser=shift;
79
80         my $list;
81         open ($list, "<$file") || die "$file: $!";
82         while (<$list>) {
83                 chomp;
84                 s/^\s+//;
85                 s/\s+$//;
86                 next if /^#/ || ! length;
87
88                 if (/^([^\s]+)\s+([^\s]+)$/) {
89                         my $user=$1;
90                         my $setup=$2;
91                         if (defined $forceuser && $forceuser ne $user) {
92                                 print STDERR "warning: in $file line $., attempt to set user to $user, but user forced to $forceuser. Skipping\n";
93                         }
94                         processline($user, $setup);
95                 }
96                 elsif (/^([^\s]+)$/) {
97                         my $user=$1;
98                         my $home=(getpwnam($user))[7];
99                         if (defined $home && -d $home) {
100                                 my $dotfile="$home/.ikiwiki/wikilist";
101                                 if (-e $dotfile) {
102                                         processlist($dotfile, $user);
103                                 }
104                         }
105                 }
106         }
107         close $list;
108 }
109
110 my $wikilist="/etc/ikiwiki/wikilist";
111
112 if (-e $wikilist) {
113         processlist($wikilist);
114 }
115