1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
|
#!/usr/bin/perl
use strict;
use warnings;
my( $errorto ) = 'jrayhawk+piny.be@omgwallhack.org'; # Email address to send horrible errors to.
my( $reponame, $email, @errors, $wikilisttempfile, $cgitrctempfile, $description );
if ( ( ! scalar $ARGV[0] ) or ( scalar $ARGV[1] ) or ( $ARGV[0] !~ /^[a-z0-9][a-z0-9+.-]+$/ ) ) {
print( "Usage: newrepo REPONAME\n" );
print( " REPONAME must consist only of lower case letters (a-z), digits (0-9), plus (+) and minus (-) signs, and periods (.).\n" );
print( " REPONAME must be at least two characters long and must start with an alphanumeric character.\n" );
exit( 1 );
} else {
$reponame = $ARGV[0];
};
# We want to check to see if
# 1) $reponame already exists in some form so we don't try to create it, and
# 2) $reponame is only partially created, in which case we want to email someone who can sanity check and fix it.
open (PASSWD, '/etc/passwd');
while(<PASSWD>) {
if( $_ =~ /^$ENV{SUDO_USER}:.+?:.+?:.+?:(.+?):/ ) { $email = $1; }; # While we're here, may as well grab the email address.
if( $_ =~ /^ikiwiki-$reponame:/ ) { push( @errors, "user ikiwiki-$reponame already exists!\n"); };
};
close(PASSWD);
open (GROUP, '/etc/group');
while(<GROUP>) {
if( $_ =~ /^git-$reponame:/ ) { push( @errors, "group git-$reponame already exists!\n"); };
};
close(GROUP);
if( -d "/srv/git/$reponame.git" ) { push( @errors, "/srv/git/$reponame.git already exists!\n"); };
if( -d "/srv/ikiwiki/$reponame" ) { push( @errors, "/srv/ikiwiki/$reponame already exists!\n"); };
if( -d "/srv/www/piny.be/$reponame" ) { push( @errors, "/srv/www/piny.svcs.cs.pdx.edu/$reponame already exists!\n"); };
if( -d "/srv/www/secure.piny.be/repos/$reponame" ) { push( @errors, "/srv/www/cgi.piny.be/repos/$reponame already exists!\n"); };
if( -f "/etc/ikiwiki/piny/$reponame.setup" ) { push( @errors, "/etc/ikiwiki/piny/$reponame.setup already exists!\n"); };
if( -f "/etc/ikiwiki/wikilist.d/$reponame" ) { push( @errors, "/etc/ikiwiki/wikilist.d/$reponame already exists!\n"); };
if( -f "/etc/apache2/piny-available/$reponame" ) { push( @errors, "/etc/apache2/piny-available/$reponame already exists!\n"); };
if( -f "/etc/cgitrc.d/$reponame" ) { push( @errors, "/etc/cgitrc.d/$reponame already exists!\n"); };
if( @errors ) {
if( @errors == 10 ) { # Everything's fine, nothing is broken
print( "$reponame already exists!\n" );
} else { # IT'S ARMAGEDDON
open ( MAIL, "|/usr/lib/sendmail -t" );
print( MAIL "To: $errorto\n" );
print( MAIL "From: newrepo\@piny.be\n" );
print( MAIL "Subject: Piny error: $ENV{SUDO_USER} found inconsistent $reponame in the creation process!\n" );
print( MAIL "MIME-Version: 1.0\n" );
print( MAIL "Content-Type: text/plain; charset=us-ascii\n" );
print( MAIL "\n" );
print( MAIL "@errors\n" );
close( MAIL );
print( "$reponame already exists but is in an inconsistent state! The Piny admins probably screwed up; they have been notified and will take a look at it.\n" );
};
exit( 2 );
};
while( 1 ) {
print( "Provide a one-line description to be used in repo listings, the shorter the better:\n" );
chomp( $description = <STDIN> );
if( $description !~ /^[\x{0020}-\x{FDCF}\x{FDF0}-\x{FFFD}]{1,80}$/ ) { # everything but control characters and unicode-defined non-characters
print( "Must be 1-80 characters long; control characters (including tab) not allowed.\n" );
next;
};
print( "Okay! Working, please wait...\n" );
last;
};
# CREATE USER/GROUPS
unless( system( "mkdir /srv/git/$reponame.git" ) == 0 ) { # We need a locking or atomic operation as our first to check against simultaneous execution.
print( "Somebody else has created the same repo as you in the course of executing this program!\n" );
exit( 3 );
};
system( "/usr/sbin/addgroup --quiet git-$reponame" );
system( "/usr/sbin/adduser --quiet --system --group --gecos $reponame ikiwiki-$reponame" );
system( "/usr/sbin/adduser --quiet ikiwiki-$reponame git-$reponame | grep -v 'Adding user'" );
system( "/usr/sbin/adduser --quiet $ENV{SUDO_USER} git-$reponame | grep -v 'Adding user '" );
# CREATE REPO
system( "GIT_DIR=/srv/git/$reponame.git /usr/bin/git init --template=/srv/git-template.git --quiet --shared" );
open ( DESC, ">/srv/git/$reponame.git/description" );
print( DESC "$description" );
close( DESC );
# ln -f post-receive /srv/git/$reponame.git/hooks/ # turn on e-mail commit notices
system( "/bin/chown -R $ENV{SUDO_USER}.git-$reponame /srv/git/$reponame.git/" );
system( "/bin/chown -R ikiwiki-$reponame.ikiwiki-$reponame /srv/git/$reponame.git/hooks/" );
system( "/bin/touch /srv/git/$reponame.git/git-daemon-export-ok" );
# WRITE IKIWIKI SETUP FILE
open ( SETUP, ">/etc/ikiwiki/piny/$reponame.setup" );
print( SETUP
'#!/usr/bin/perl
# Configuration file for ikiwiki.
# Passing this to ikiwiki --setup will make ikiwiki generate wrappers and
# build the wiki.
#
# Remember to re-run ikiwiki --setup any time you edit this file.
use IkiWiki::Setup::Standard {
wikiname => \'' . $reponame . '\', # PINY
adminemail => \'' . $email . '\', # PINY
srcdir => \'/srv/ikiwiki/' . $reponame . '\', # PINY
destdir => \'/srv/www/piny.be/' . $reponame . '\', # PINY
url => \'http://piny.be/' . $reponame . '\', # PINY
cgiurl => \'https://secure.piny.be/repos/' . $reponame . '/ikiwiki.cgi\', # PINY
historyurl => \'https://secure.piny.be/cgit/' . $reponame . '/log/[[file]]\', # PINY
diffurl => \'https://secure.piny.be/cgit/' . $reponame . '/diff/?id=[[sha1_commit]]\', # PINY
templatedir => "/srv/templates",
underlaydir => "/etc/ikiwiki/share/underlay",
rcs => "git",
gitorigin_branch => "origin",
gitmaster_branch => "master",
wrappers => [
{
cgi => 1,
wrapper => \'/srv/www/secure.piny.be/repos/' . $reponame . '/ikiwiki.cgi\', # PINY
wrappermode => "06755",
wrappergroup => \'git-' . $reponame . '\', # PINY
},
{
wrapper => \'/srv/git/' . $reponame . '.git/hooks/post-update\', # PINY
wrappermode => "06755",
wrappergroup => \'git-' . $reponame . '\', # PINY
notify => 0,
},
],
# Generate rss feeds for blogs?
rss => 1,
# Generate atom feeds for blogs?
atom => 0,
# Include discussion links on all pages?
discussion => 0,
# To exclude files matching a regexp from processing. This adds to
# the default exclude list.
#exclude => qr/*\.wav/,
# To change the extension used for generated html files.
#htmlext => "htm",
# Time format (for strftime)
#timeformat => "%c",
# Locale to use. Must be a UTF-8 locale.
#locale => "en_US.UTF-8",
# Only send cookies over SSL connections.
sslcookie => 1,
# Logging settings:
verbose => 0,
syslog => 1,
# To link to user pages in a subdirectory of the wiki.
#userdir => "users",
# To create output files named page.html rather than page/index.html.
usedirs => 1,
# Simple spam prevention: require an account-creation password.
#account_creation_password => "example",
# Use new "!"-prefixed preprocessor directive syntax
prefix_directives => 1,
httpauth => 1,
# To add plugins, list them here.
add_plugins => [qw{sidebar toc meta table tag httpauth attachment rename remove autoindex map teximg version edittemplate}],
disable_plugins => [qw{openid passwordauth}],
teximg_prefix => \'\\documentclass{scrartcl}
\\usepackage[version=3]{mhchem}
\\usepackage{amsmath}
\\usepackage{amsfonts}
\\usepackage{amssymb}
\\pagestyle{empty}
\\newcommand{\unit}[1]{\\ensuremath{\\, \\mathrm{#1}}}
\\begin{document}\',
teximg_dvipng => 1,
# For use with the tag plugin, make all tags be located under a
# base page.
tagbase => "tag",
# For use with the search plugin if your estseek.cgi is located
# somewhere else.
#estseek => "/usr/lib/estraier/estseek.cgi",
}');
close( SETUP );
open ( WIKILIST, '>>/etc/ikiwiki/wikilist' );
print( WIKILIST "ikiwiki-$reponame /etc/ikiwiki/piny/$reponame.setup\n" );
close( WIKILIST );
# WRITE APACHE CONFIG
open ( APACHE, ">/etc/apache2/piny-available/$reponame" );
print( APACHE '<Directory /srv/www/secure.piny.be/repos/' . $reponame . '>
AuthPAM_Enabled on
AuthGROUP_Enabled on
AuthPAM_FallThrough off
AuthBasicAuthoritative off
AuthType Basic
AuthName "User access to ' . $reponame . ' repository needed."
Require group git-' . $reponame . '
</Directory>' );
close( APACHE );
link( "/etc/apache2/piny-available/$reponame", "/etc/apache2/piny-enabled/$reponame");
system( '/etc/init.d/apache2 reload | grep -v "Reloading web server config: apache2."' );
# CREATE IKIWIKI WORKING DIR
system( "/usr/bin/git clone --quiet /srv/git/$reponame /srv/ikiwiki/$reponame" );
mkdir( "/srv/www/piny.be/$reponame" );
mkdir( "/srv/www/secure.piny.be/repos/$reponame" );
system( "/bin/chown -R ikiwiki-$reponame /srv/ikiwiki/$reponame /srv/www/piny.be/$reponame /srv/www/secure.piny.be/repos/$reponame" );
open ( WIKILIST, ">/etc/ikiwiki/wikilist.d/$reponame" ); # Maybe someday ikiwiki will support wikilist.d.
print( WIKILIST "ikiwiki-$reponame /etc/ikiwiki/piny/$reponame.setup\n" ); # In the meantime, we fake it.
close( WIKILIST );
$wikilisttempfile = `/bin/mktemp`;
chomp( $wikilisttempfile );
chmod ( 0644, $wikilisttempfile );
system( "/bin/cat /etc/ikiwiki/wikilist.d/* > $wikilisttempfile" );
system( "/bin/mv $wikilisttempfile /etc/ikiwiki/wikilist" ); # This is marginally racy, but the consequences are probably ignorable.
open ( CGITRC, ">/etc/cgitrc.d/$reponame" ); # Maybe someday cgit will support cgitrc.d.
print( CGITRC # In the meantime, we fake it.
"repo.url=$reponame
repo.path=/srv/git/$reponame.git
repo.desc=$description
repo.owner=$email
" ); # cgit already escapes HTML, so we don't need to do it on $description
close( CGITRC );
$cgitrctempfile = `/bin/mktemp`;
chomp( $cgitrctempfile );
chmod ( 0644, $cgitrctempfile );
system( "/bin/cat /etc/cgitrc.d/* > $cgitrctempfile" );
system( "/bin/mv $cgitrctempfile /etc/cgitrepos" ); # This is marginally racy, but the consequences are minor.
# COMPILE
system( "/usr/bin/sudo -u ikiwiki-$reponame /usr/bin/ikiwiki --setup /etc/ikiwiki/piny/$reponame.setup | grep -v 'successfully generated'" );
print( "Web interface: http://piny.be/$reponame/\n" );
print( "Repo information: https://secure.piny.be/cgit/$reponame/\n" );
|