summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com>2015-12-29 14:25:52 +0100
committerJeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com>2015-12-29 14:25:52 +0100
commitea191b1ada7c6c63deb097c55c81faa7f2b2ecac (patch)
tree9e5d7ea9ba7efef3d3000c914111e3e40fa56419
parentea216f3a4be8dae7ff8dc863a00b573e5c7979b4 (diff)
downloaddocker-ea191b1ada7c6c63deb097c55c81faa7f2b2ecac.tar.gz
Add twentytwo and twentythree
-rw-r--r--99-ci-twentythree/Dockerfile98
-rw-r--r--99-ci-twentythree/dbus.service16
-rwxr-xr-x99-ci-twentythree/entrypoint.sh148
-rw-r--r--99-ci-twentythree/functions.sh65
-rw-r--r--99-ci-twentythree/httpd.service4
-rw-r--r--99-ci-twentythree/sudoers.drydock-worker1
-rw-r--r--99-ci-twentythree/systemctl680
-rw-r--r--99-ci-twentythree/systemctl-socket-daemon67
-rw-r--r--99-ci-twentythree/vimrc9
-rw-r--r--99-ci-twentytwo/Dockerfile98
-rw-r--r--99-ci-twentytwo/dbus.service16
-rwxr-xr-x99-ci-twentytwo/entrypoint.sh148
-rw-r--r--99-ci-twentytwo/functions.sh65
-rw-r--r--99-ci-twentytwo/httpd.service4
-rw-r--r--99-ci-twentytwo/sudoers.drydock-worker1
-rw-r--r--99-ci-twentytwo/systemctl680
-rw-r--r--99-ci-twentytwo/systemctl-socket-daemon67
-rw-r--r--99-ci-twentytwo/vimrc9
18 files changed, 2176 insertions, 0 deletions
diff --git a/99-ci-twentythree/Dockerfile b/99-ci-twentythree/Dockerfile
new file mode 100644
index 0000000..974e3dc
--- /dev/null
+++ b/99-ci-twentythree/Dockerfile
@@ -0,0 +1,98 @@
+FROM fedora:23
+MAINTAINER Kolab Systems <vanmeeuwen@kolabsys.com>
+
+ADD http://obs.kolabsys.com/repositories/Kolab:/Development/Fedora_23/Kolab:Development.repo \
+ /etc/yum.repos.d/Kolab:Development.repo
+
+RUN echo "priority=60" >> /etc/yum.repos.d/Kolab:Development.repo
+
+RUN rpm --import https://ssl.kolabsys.com/community.asc
+
+ADD http://download.opensuse.org/repositories/openSUSE:Tools/Fedora_23/openSUSE:Tools.repo \
+ /etc/yum.repos.d/openSUSE:Tools.repo
+
+RUN rpm --import http://download.opensuse.org/repositories/openSUSE:/Tools/Fedora_23/repodata/repomd.xml.key
+
+RUN sed -i \
+ -e '/tsflags=nodocs/d' \
+ -e '/override_install_langs/d' \
+ /etc/dnf/dnf.conf
+
+RUN dnf -y reinstall \* && \
+ dnf clean all
+
+ENV IMAGE twentythree
+
+ADD /dbus.service /etc/systemd/system/dbus.service
+RUN ln -sf dbus.service /etc/systemd/system/messagebus.service
+
+ADD /httpd.service /etc/systemd/system/httpd.service
+
+ADD /systemctl /usr/bin/systemctl
+ADD /systemctl-socket-daemon /usr/bin/systemctl-socket-daemon
+
+RUN chmod -v a+rx \
+ /usr/bin/systemctl \
+ /usr/bin/systemctl-socket-daemon
+
+ADD /vimrc /root/.vimrc
+
+RUN dnf clean all && \
+ dnf -y install \
+ ant \
+ bind-utils \
+ build \
+ git \
+ lsof \
+ net-tools \
+ nmap-ncat \
+ openldap-clients \
+ osc \
+ perl-Data-Dumper \
+ perl-Digest-MD5 \
+ perl-TimeDate \
+ php-phpunit-PHPUnit-Selenium \
+ psmisc \
+ rpmdevtools \
+ screen \
+ strace \
+ sudo \
+ telnet \
+ traceroute \
+ vim-enhanced \
+ wget \
+ yum-utils && \
+ dnf clean all
+
+RUN sed -i -e '/requiretty/d' /etc/sudoers
+
+WORKDIR /srv
+RUN git clone https://github.com/google/closure-compiler.git closure-compiler.git
+WORKDIR /srv/closure-compiler.git
+RUN ant jar
+
+ADD http://mirror.kolabsys.com/pub/releases/selenium-server-standalone.jar /usr/local/lib/selenium-server-standalone.jar
+
+#WORKDIR /srv
+#RUN git clone https://github.com/SeleniumHQ/selenium.git selenium.git
+#WORKDIR /srv/selenium.git
+#RUN ./go --trace --verbose build
+#RUN ./go selenium-server-standalone
+
+WORKDIR /srv
+RUN wget http://mirror.kolabsys.com/pub/releases/phantomjs-1.9.7-linux-x86_64.tar.bz2 && \
+ tar jxvf phantomjs-1.9.7-linux-x86_64.tar.bz2 && \
+ cp phantomjs-1.9.7-linux-x86_64/bin/phantomjs /usr/local/bin/ && \
+ rm -rf phantomjs-1.9.7-linux-x86_64*
+
+#WORKDIR /srv/
+#RUN git clone https://github.com/ariya/phantomjs.git phantomjs.git
+#WORKDIR /srv/phantomjs.git
+#RUN ./build.sh --confirm
+
+ADD /functions.sh /
+ADD entrypoint.sh /
+
+RUN chmod 755 /entrypoint.sh
+
+ENTRYPOINT [ "/entrypoint.sh" ]
diff --git a/99-ci-twentythree/dbus.service b/99-ci-twentythree/dbus.service
new file mode 100644
index 0000000..0be95c4
--- /dev/null
+++ b/99-ci-twentythree/dbus.service
@@ -0,0 +1,16 @@
+[Unit]
+Description=D-Bus System Message Bus
+Requires=dbus.socket
+After=syslog.target
+
+[Service]
+PIDFile=/var/run/messagebus.pid
+ExecStartPre=/bin/mkdir -p /var/run/dbus
+ExecStartPre=/bin/chmod g+w /var/run/ /var/run/dbus/
+ExecStart=/bin/dbus-daemon --system --fork
+ExecReload=/bin/dbus-send --print-reply --system --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig
+ExecStopPost=/bin/rm -f /var/run/messagebus.pid
+OOMScoreAdjust=-900
+User=dbus
+Group=root
+PermissionsStartOnly=true
diff --git a/99-ci-twentythree/entrypoint.sh b/99-ci-twentythree/entrypoint.sh
new file mode 100755
index 0000000..a099eca
--- /dev/null
+++ b/99-ci-twentythree/entrypoint.sh
@@ -0,0 +1,148 @@
+#!/bin/bash
+
+if [ ! -d "/srv/stick.git" ]; then
+ git clone https://git.kolab.org/diffusion/QA/stick.git /srv/stick.git
+elif [ -z "${PS1}" ]; then
+ pushd /srv/stick.git
+ git remote set-url origin https://git.kolab.org/diffusion/QA/stick.git
+ git fetch origin
+ git reset --hard origin/master
+ git clean -d -f -x
+ popd
+fi
+
+source /functions.sh
+
+export TEST_BUILD=${TEST_BUILD:-0}
+export TEST_FUNCTIONAL=${TEST_FUNCTIONAL:-0}
+export TEST_INTEGRATION=${TEST_INTEGRATION:-0}
+export TEST_PERFORMANCE=${TEST_PERFORMANCE:-0}
+export TEST_UNIT=${TEST_UNIT:-0}
+export TEST_OBS=${TEST_OBS:-0}
+
+# If PS1 is set, we're interactive
+if [ ! -z "${PS1}" ]; then
+ # Set a sensible prompt
+ PS1='[\u@${IMAGE} \W]\$ '
+
+ export GIT_PS1_SHOWDIRTYSTATE=1
+ export GIT_PS1_SHOWUNTRACKEDFILES=1
+ export GIT_PS1_SHOWUPSTREAM="auto verbose"
+
+ if [ ! -f "/etc/bash_completion" ]; then
+ if [ -f "/etc/bash_completion.d/git" ]; then
+ . /etc/bash_completion.d/git
+ PS1='[\u@${IMAGE} \W$(__git_ps1 " (%s)")]\$ '
+ fi
+ else
+ PS1='[\u@${IMAGE} \W$(__git_ps1 " (%s)")]\$ '
+ fi
+
+ export PS1
+
+ PROMPT_COMMAND="echo -ne '\033]0;${IMAGE} (in ${HOSTNAME})\007'"
+
+ if [ -f "/usr/share/git-core/contrib/completion/git-prompt.sh" ]; then
+ source /usr/share/git-core/contrib/completion/git-prompt.sh
+ fi
+fi
+
+if [ ! -d "/srv/${PACKAGE}.git" ]; then
+ git clone ${RO_URI} /srv/${PACKAGE}.git
+
+ pushd /srv/${PACKAGE}.git
+
+ for branch in $(git branch -la | sed -e 's/^* //g' -e 's/ //g' -e '/remotes\/origin\/HEAD/d' -e 's|remotes/origin/||g' | sort -u); do
+ git checkout $branch
+ done
+
+ popd
+else
+ pushd /srv/${PACKAGE}.git
+
+ git remote set-url origin ${RO_URI}
+ git fetch origin
+ git reset --hard origin/master
+ git clean -d -f -x
+
+ for branch in $(git branch -la | sed -e 's/^* //g' -e '/\(detached from/d' -e 's/ //g' -e '/remotes\/origin\/HEAD/d' -e 's|remotes/origin/||g' | sort -u); do
+ git checkout $branch
+ done
+
+ popd
+fi
+
+retval=0
+
+if [ -x "$(which yum 2>/dev/null)" ]; then
+ yum clean metadata; retval=$(( ${retval} + $? ))
+ yum -y update; retval=$(( ${retval} + $? ))
+ rpmdev-setuptree; retval=$(( ${retval} + $? ))
+elif [ -x "$(which apt-get 2>/dev/null)" ]; then
+ apt-get update; retval=$(( ${retval} + $? ))
+fi
+
+pushd /srv/${PACKAGE}.git
+
+if [ ! -z "${COMMIT}" ]; then
+ git checkout ${COMMIT}; retval=$(( ${retval} + $? ))
+fi
+
+# TODO: A differential has a base commit.
+
+if [ ${retval} -ne 0 ]; then
+ _report
+ exit 1
+fi
+
+if [ -x "../stick.git/drydocker/${PACKAGE}/test_build.sh" -a ${TEST_BUILD} -eq 1 ]; then
+ retval=$(_shell ../stick.git/drydocker/${PACKAGE}/test_build.sh)
+ if [ ${retval} -ne 0 ]; then
+ _report
+ exit 1
+ fi
+fi
+
+if [ -x "../stick.git/drydocker/${PACKAGE}/test_unit.sh" -a ${TEST_UNIT} -eq 1 ]; then
+ retval=$(_shell ../stick.git/drydocker/${PACKAGE}/test_unit.sh)
+ if [ ${retval} -ne 0 ]; then
+ _report
+ exit 1
+ fi
+fi
+
+if [ -x "../stick.git/drydocker/${PACKAGE}/test_functional.sh" -a ${TEST_FUNCTIONAL} -eq 1 ]; then
+ retval=$(_shell ../stick.git/drydocker/${PACKAGE}/test_functional.sh)
+ if [ ${retval} -ne 0 ]; then
+ _report
+ exit 1
+ fi
+fi
+
+if [ -x "../stick.git/drydocker/${PACKAGE}/test_obs.sh" ]; then
+ retval=$(_shell ../stick.git/drydocker/${PACKAGE}/test_obs.sh)
+ if [ ${retval} -ne 0 ]; then
+ _report
+ exit 1
+ fi
+fi
+
+if [ -x "../stick.git/drydocker/${PACKAGE}/test_integration.sh" -a ${TEST_INTEGRATION} -eq 1 ]; then
+ retval=$(_shell ../stick.git/drydocker/${PACKAGE}/test_integration.sh)
+ if [ ${retval} -ne 0 ]; then
+ _report
+ exit 1
+ fi
+fi
+
+if [ -x "../stick.git/drydocker/${PACKAGE}/test_obs_checkin.sh" ]; then
+ retval=$(_shell ../stick.git/drydocker/${PACKAGE}/test_obs_checkin.sh)
+ if [ ${retval} -ne 0 ]; then
+ _report
+ exit 1
+ fi
+fi
+
+popd
+
+_report
diff --git a/99-ci-twentythree/functions.sh b/99-ci-twentythree/functions.sh
new file mode 100644
index 0000000..27a9d32
--- /dev/null
+++ b/99-ci-twentythree/functions.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+
+# Create 3 as an alias for 1, so the _shell function
+# can output data without the caller getting the input.
+exec 3>&1
+
+function _report {
+ echo $(printf '%0.1s' "="{1..72})
+ cat ${TMPDIR:-/tmp}/report.log
+ rm -rf ${TMPDIR:-/tmp}/report.log
+ echo $(printf '%0.1s' "="{1..72})
+}
+
+export -f _report
+
+function _report_msg {
+ printf "%*s" $(( ( ${BASH_SUBSHELL} - 1 ) * 4 )) " " >> ${TMPDIR:-/tmp}/report.log
+ echo "$@" >> ${TMPDIR:-/tmp}/report.log
+}
+
+export -f _report_msg
+
+function _shell {
+ revision=$(git rev-parse HEAD 2>/dev/null)
+ if [ -z "${revision}" ]; then
+ pushd /srv/${PACKAGE}.git >/dev/null 2>&1 3>&1
+ revision=$(git rev-parse HEAD 2>/dev/null)
+ popd >/dev/null 2>&1 3>&1
+ fi
+
+ if [ -z "${revision}" ]; then
+ revision=unknown
+ fi
+
+ echo "Running $@ ..." >&3
+ $@ >&3 2>&3 ; retval=$?
+
+ if [ ${retval} -eq 0 ]; then
+ _report_msg "Running '$@' OK (at ${revision})"
+ echo "Running $@ OK (at ${revision})" >&3
+ else
+ _report_msg "Running '$@' FAILED (at ${revision})"
+ echo "Running $@ FAILED (at ${revision})" >&3
+ fi
+
+ echo ${retval}
+}
+
+export -f _shell
+
+function _install_package {
+ if [ -x "$(which yum 2>/dev/null)" ]; then
+ yum -y install $@
+ elif [ -x "$(which apt-get 2>/dev/null)" ]; then
+ apt-get -y install $@
+ fi
+}
+
+function _install_package_builddep {
+ if [ -x "$(which yum 2>/dev/null)" ]; then
+ yum-builddep -y --disablerepo=openSUSE_Tools $@
+ elif [ -x "$(which apt-get 2>/dev/null)" ]; then
+ apt-get -y build-dep $@
+ fi
+}
diff --git a/99-ci-twentythree/httpd.service b/99-ci-twentythree/httpd.service
new file mode 100644
index 0000000..ba7ec71
--- /dev/null
+++ b/99-ci-twentythree/httpd.service
@@ -0,0 +1,4 @@
+.include /lib/systemd/system/httpd.service
+[Service]
+PIDFile=/var/run/httpd/httpd.pid
+
diff --git a/99-ci-twentythree/sudoers.drydock-worker b/99-ci-twentythree/sudoers.drydock-worker
new file mode 100644
index 0000000..489b82b
--- /dev/null
+++ b/99-ci-twentythree/sudoers.drydock-worker
@@ -0,0 +1 @@
+drydock-worker ALL=(ALL) NOPASSWD: ALL
diff --git a/99-ci-twentythree/systemctl b/99-ci-twentythree/systemctl
new file mode 100644
index 0000000..6a15c0b
--- /dev/null
+++ b/99-ci-twentythree/systemctl
@@ -0,0 +1,680 @@
+#!/usr/bin/perl
+
+# Copyright 2014 Jan Pazdziora
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+use strict;
+use warnings FATAL => 'all';
+
+use IO::File ();
+use IO::Dir ();
+use IO::Socket::UNIX ();
+use Socket ();
+use Data::Dumper ();
+use POSIX ();
+use Time::HiRes qw(sleep time);
+
+sub log_command {
+ local * LOG;
+ open(LOG, '>>', '/var/log/systemctl.log');
+ print LOG @_;
+ close LOG;
+}
+log_command("[@ARGV]\n");
+shift if @ARGV and $ARGV[0] eq '-q';
+
+for (my $i = 0; $i < @ARGV; $i++) {
+ if ($ARGV[$i] eq '--ignore-dependencies') {
+ splice @ARGV, $i, 1;
+ last;
+ }
+}
+if (@ARGV == 1 and $ARGV[0] eq 'daemon-reload') {
+ exit 0;
+}
+if (@ARGV == 2 and $ARGV[0] eq '--system' and $ARGV[1] eq 'daemon-reload') {
+ exit 0;
+}
+
+for (keys %ENV) {
+ delete $ENV{$_} unless $_ eq '_SYSTEMCTL_LITE_STARTING';
+}
+
+my $RUNNING_DIR = '/run/systemctl-lite-running';
+if (not -d $RUNNING_DIR) {
+ mkdir $RUNNING_DIR;
+}
+my $ENABLED_DIR = '/etc/systemctl-lite-enabled';
+if (@ARGV == 1) {
+ if ($ARGV[0] eq 'start-enabled' and -d $ENABLED_DIR) {
+ local * ENABLED;
+ opendir ENABLED, $ENABLED_DIR;
+ my %services;
+ while (defined(my $f = readdir ENABLED)) {
+ next if $f eq '.' or $f eq '..';
+ my $modified = (stat "$ENABLED_DIR/$f")[9];
+ if (defined $modified) {
+ $services{$f} = $modified;
+ }
+ }
+ close ENABLED;
+ for my $s (sort { $services{$a} <=> $services{$b} or $a cmp $b } keys %services) {
+ print "Starting [$s]\n";
+ system $0, 'start', $s;
+ exit ($? >> 8) if ($? >> 8);
+ }
+ }
+ if ($ARGV[0] eq 'stop-running' and -d $RUNNING_DIR) {
+ local * RUNNING;
+ opendir RUNNING, $RUNNING_DIR;
+ my %services;
+ while (defined(my $f = readdir RUNNING)) {
+ next if $f eq '.' or $f eq '..';
+ my $modified = (stat "$RUNNING_DIR/$f")[9];
+ if (defined $modified) {
+ my $trimmed = $f;
+ $trimmed =~ s/\..+$//;
+ $services{$trimmed} = $modified;
+ }
+ }
+ close RUNNING;
+ for my $s (sort { $services{$b} <=> $services{$a} or $a cmp $b } keys %services) {
+ system $0, 'stop', $s;
+ }
+ }
+ exit;
+}
+
+if (@ARGV != 2) {
+ die "Usage: $0 (start|stop|status|...) (service|target|socket thing)\n";
+}
+
+my ($COMMAND, $SERVICE) = @ARGV;
+my $TYPE = 'service';
+if ($SERVICE =~ /\.(target|socket)$/) {
+ $TYPE = $1;
+} elsif (not $SERVICE =~ /\.service$/) {
+ $SERVICE .= '.service';
+}
+
+my @PATHS = (
+ '/etc/systemd/system',
+ '/run/systemd/system',
+ '/usr/lib/systemd/system',
+);
+
+my $FULL_SERVICE = $SERVICE;
+my $INSTANCE = undef;
+
+my $file = undef;
+if ($SERVICE =~ s/\@(.+)\.service$/\@.service/) {
+ $INSTANCE = $1;
+}
+for my $p (@PATHS) {
+ if (-e "$p/$SERVICE") {
+ if (-l "$p/$SERVICE") {
+ my $new_service = readlink("$p/$SERVICE");
+ log_command("Service [$p/$SERVICE] is a symlink to [$new_service]\n");
+ $new_service =~ s!^.*/!!;
+ $SERVICE = $new_service;
+ }
+ $file = "$p/$SERVICE";
+ last;
+ }
+}
+
+if ($SERVICE =~ s/\@(.+)\.service$/\@.service/) {
+ $INSTANCE = $1;
+ for my $p (@PATHS) {
+ if (-f "$p/$SERVICE") {
+ $file = "$p/$SERVICE";
+ last;
+ }
+ }
+}
+
+if (not defined $file) {
+ if ($COMMAND eq 'is-enabled') {
+ exit 1;
+ }
+ if ($COMMAND eq 'is-active') {
+ exit 3;
+ }
+ warn "No service definition found for [$FULL_SERVICE].\n";
+ exit 2;
+}
+
+sub parse_file {
+ my ($file, $data) = @_;
+ if (-d $file) {
+ my $op;
+ if ($file =~ /\.requires$/) {
+ $op = 'Unit.Requires';
+ } elsif ($file =~ /\.wants$/) {
+ $op = 'Unit.Wants';
+ } else {
+ die "Unknown directory [$file].\n";
+ }
+ my $dh = new IO::Dir($file);
+ while (defined(my $de = $dh->read)) {
+ next if $de eq '.' or $de eq '..';
+ push @{$data->{$op}}, $de unless $de =~ /\.target$/;
+ }
+ $dh->close;
+ return;
+ }
+ my $fh = new IO::File($file);
+ my $section = 'undefined';
+ while (my $line = <$fh>) {
+ chomp $line;
+ if ($line =~ /^\[(.+)\]\s*$/) {
+ $section = $1;
+ next;
+ }
+ next if $line =~ /^\s*(#|$)/;
+ if ($line =~ /^\.include\s(.+)/) {
+ parse_file($1, $data);
+ next;
+ }
+ my ($key, $value) = split /=/, $line, 2;
+ if (defined $INSTANCE) {
+ $value =~ s/\%i/$INSTANCE/g;
+ }
+ if ($key eq 'EnvironmentFile') {
+ if ($value eq '') {
+ delete $data->{"$section.$key"};
+ } else {
+ push @{ $data->{"$section.$key"} }, $value;
+ }
+ } elsif ($key =~ /^(Wants|Requires)$/) {
+ push @{ $data->{"$section.$key"} }, $value unless $value =~ /\.target$/;
+ } elsif ($key =~ /^(ExecStart(Pre|Post)|ExecReload|ExecStop(Pre|Post)?)$/) {
+ push @{ $data->{"$section.$key"} }, $value;
+ } else {
+ $data->{"$section.$key"} = $value;
+ }
+ }
+ $fh->close;
+ if (defined $data->{'Service.ExecStart'} and not defined $data->{'Service.PIDFile'}) {
+ my ($pidfile) = grep /^\/.+\.pid$/, split /\s+/, $data->{'Service.ExecStart'};
+ if (defined $pidfile) {
+ $data->{'Service.PIDFile'} = $pidfile;
+ log_command("Guessing pid file [$data->{'Service.PIDFile'}] from ExecStart [$data->{'Service.ExecStart'}]\n");
+ }
+ }
+}
+
+my $data = {};
+parse_file($file, $data);
+for my $p (@PATHS) {
+ if (-d "$p/$SERVICE.wants") {
+ $file = "$p/$SERVICE.wants";
+ parse_file("$p/$SERVICE.wants", $data);
+ last;
+ }
+}
+
+if ($COMMAND eq 'show') {
+ print Data::Dumper::Dumper $data;
+ exit;
+}
+
+sub pidof {
+ my $command = shift;
+ my $pids = `/usr/sbin/pidof $command`;
+ chomp $pids;
+ if ($pids ne '') {
+ return split /\s+/, $pids;
+ }
+ return;
+}
+
+sub get_exec_start {
+ my $data = shift;
+ my $d = $data->{'Service.ExecStart'};
+ if (not defined $d) {
+ warn "No ExecStart value found for [$SERVICE].\n";
+ exit 3;
+ }
+ return split /\s+/, $d;
+}
+
+sub get_pid {
+ my $file = shift;
+ if (not $file =~ m!^/!) {
+ $file = "$RUNNING_DIR/$file";
+ }
+ if (-f $file) {
+ local * PIDFILE;
+ open PIDFILE, '<', $file;
+ my $pid = <PIDFILE>;
+ close PIDFILE;
+ if (defined $pid) {
+ chomp $pid;
+ return $pid;
+ }
+ }
+}
+
+sub is_running {
+ my $data = shift;
+ my $ret;
+ if (-f "$RUNNING_DIR/$FULL_SERVICE.oneshot") {
+ return 1;
+ } elsif (defined $data->{'Service.PIDFile'}) {
+ my $pid = get_pid($data->{'Service.PIDFile'});
+ if (defined $pid) {
+ $ret = kill 0, $pid;
+ }
+ } else {
+ my $path = get_pid("$FULL_SERVICE.name");
+ if (defined $path) {
+ if (pidof($path)) {
+ $ret = 1;
+ }
+ } else {
+ my $pid = get_pid("$FULL_SERVICE.pid");
+ if (defined $pid) {
+ $ret = kill 0, $pid;
+ }
+ }
+ }
+ return $ret;
+}
+if ($COMMAND eq 'is-active' or $COMMAND eq 'status') {
+ if (is_running($data)) {
+ print "active\n";
+ exit;
+ }
+ print "inactive\n";
+ exit 3;
+}
+
+sub exec_stop_pre {
+ my ($data) = @_;
+ if (defined $data->{'Socket.ExecStopPre'}) {
+ for my $x (@{ $data->{'Socket.ExecStopPre'} }) {
+ log_command("Running stop pre [$x]\n");
+ system $x;
+ }
+ }
+}
+sub exec_stop_post {
+ my ($data) = @_;
+ if (defined $data->{'Service.ExecStopPost'}) {
+ for my $x (@{ $data->{'Service.ExecStopPost'} }) {
+ log_command("Running stop post [$x]\n");
+ system $x;
+ }
+ }
+}
+
+if ($TYPE eq 'target' and not defined $data->{'Unit.Wants'} and not defined $data->{'Unit.Requires'}) {
+ warn "No Unit.Wants/.wants/Unit.Requires/.requires list for target [$SERVICE]\n";
+ exit 8;
+}
+
+if ($COMMAND eq 'restart') {
+ if ($TYPE ne 'service' or is_running($data)) {
+ system $0, 'stop', $FULL_SERVICE;
+ }
+ system $0, 'start', $FULL_SERVICE;
+ exit;
+}
+
+sub pids_went_away_timeout {
+ my $timeout = shift;
+ my $start = time;
+ while (kill 0, @_) {
+ if (time - $start > $timeout) {
+ log_command(sprintf(" ** pid(s) [%s] not killed within %d s\n", join(', ', @_), $timeout));
+ return 0;
+ }
+ sleep 0.1;
+ }
+ log_command(sprintf(" ** pid(s) [%s] got killed after %.2f s\n", join(', ', @_), time - $start));
+ return 1;
+}
+
+sub stop_pids {
+ my @pids = @_;
+ kill 15, @pids;
+ if (not pids_went_away_timeout(5, @pids)) {
+ kill 9, @pids;
+ if (not pids_went_away_timeout(5, @pids)) {
+ log_command("Failed to kill [@pids] even with 9\n");
+ warn "Failed to kill [@pids].\n";
+ return 1;
+ }
+ log_command("Killed [@pids] with 9\n");
+ } else {
+ log_command("Killed [@pids] with 15\n");
+ }
+ return 0;
+}
+
+if ($COMMAND eq 'stop') {
+ my $mainpid;
+ if (defined $data->{'Service.PIDFile'}) {
+ $mainpid = get_pid($data->{'Service.PIDFile'});
+ } else {
+ $mainpid = get_pid("$FULL_SERVICE.pid");
+ }
+ if (defined $data->{'Service.ExecStop'}) {
+ for my $x (@{ $data->{'Service.ExecStop'} }) {
+ my $runit = 1;
+ if (defined $mainpid) {
+ $x =~ s!\$MAINPID\b|\$\{MAINPID\}!$mainpid!g;
+ } elsif ($x =~ /\$MAINPID\b|\$\{MAINPID\}/) {
+ $runit = 0;
+ log_command("Service [$FULL_SERVICE] would like to stop via ExecStop [$x] but we have no pid file, skipping.\n");
+ }
+ if ($runit) {
+ log_command("Running stop [$x]\n");
+ system $x;
+ sleep 1;
+ }
+ }
+ }
+ my $ret = undef;
+ if ($TYPE eq 'target') {
+ # noop
+ } elsif (defined $data->{'Service.Type'} and $data->{'Service.Type'} eq 'oneshot') {
+ # noop
+ } elsif ($TYPE eq 'socket') {
+ my $pids = `/usr/sbin/fuser $data->{'Socket.ListenStream'} 2> /dev/null`;
+ if (defined $pids) {
+ chomp $pids;
+ $pids =~ s/^\s+//;
+ my @pids = split /\s+/, $pids;
+ if (@pids) {
+ exec_stop_pre($data);
+ log_command("Will kill [@pids] as fuser [$data->{'Socket.ListenStream'}] of [$FULL_SERVICE]\n");
+ $ret = stop_pids(@pids);
+ }
+ }
+ } elsif (defined $data->{'Service.PIDFile'}) {
+ my $pid = get_pid($data->{'Service.PIDFile'});
+ if (defined $pid) {
+ log_command("Will kill [$pid] found in Service.PIDFile of [$FULL_SERVICE]\n");
+ $ret = stop_pids($pid);
+ }
+ } else {
+ my $path = get_pid("$FULL_SERVICE.name");
+ if (defined $path) {
+ if (my @pids = pidof($path)) {
+ log_command("Will kill [@pids] as pidof [$path] found in [$FULL_SERVICE.name]\n");
+ $ret = stop_pids(@pids);
+ } else {
+ warn "No pidof for [$path] found in [$FULL_SERVICE.name].\n";
+ }
+ } else {
+ my $pid = get_pid("$FULL_SERVICE.pid");
+ if (defined $pid) {
+ log_command("Will kill [$pid] found in [$FULL_SERVICE.pid]\n");
+ $ret = stop_pids($pid);
+ } else {
+ warn "No pid and no name for [$FULL_SERVICE].\n";
+ }
+ }
+ }
+ exec_stop_post($data);
+ unlink "$RUNNING_DIR/$FULL_SERVICE.pid", "$RUNNING_DIR/$FULL_SERVICE.name", "$RUNNING_DIR/$FULL_SERVICE.oneshot";
+ if (defined $data->{'Unit.Wants'}) {
+ for my $x (@{ $data->{'Unit.Wants'} }) {
+ system $0, 'stop', $x;
+ }
+ }
+ if (defined $data->{'Unit.Requires'}) {
+ for my $x (@{ $data->{'Unit.Requires'} }) {
+ system $0, 'stop', $x;
+ }
+ }
+ exit ( defined $ret ? $ret : 0 );
+}
+
+sub add_runuser {
+ my ($data, $cmd) = @_;
+ if (defined $data->{'Service.User'}) {
+ unshift @$cmd, '-u', $data->{'Service.User'}, '--';
+ if (defined $data->{'Service.Group'}) {
+ unshift @$cmd, '-g', $data->{'Service.Group'};
+ }
+ unshift @$cmd, '/usr/sbin/runuser';
+ }
+}
+
+if ($COMMAND eq 'start') {
+ my (@starting_stack, %starting_stack);
+ if (defined $ENV{_SYSTEMCTL_LITE_STARTING}) {
+ @starting_stack = split /:/, $ENV{_SYSTEMCTL_LITE_STARTING};
+ @starting_stack{@starting_stack} = ();
+ $ENV{_SYSTEMCTL_LITE_STARTING} .= ":$FULL_SERVICE";
+ } else {
+ $ENV{_SYSTEMCTL_LITE_STARTING} = $FULL_SERVICE;
+ }
+
+ if ($TYPE eq 'service' and is_running($data)) {
+ log_command("Service [$FULL_SERVICE] already found running, not starting again.\n");
+ exit;
+ }
+ if (defined $data->{'Service.PIDFile'}) {
+ log_command("Service [$FULL_SERVICE] defines PIDFile [$data->{'Service.PIDFile'}], unlinking it before start\n");
+ unlink $data->{'Service.PIDFile'};
+ }
+ if (defined $data->{'Unit.Wants'}) {
+ for my $x (@{ $data->{'Unit.Wants'} }) {
+ if (exists $starting_stack{$x}) {
+ log_command("Skipping start of [$x], we are already in the process of starting it.\n");
+ next;
+ }
+ my @cmd = ($0, 'start', $x);
+ log_command("Running [@cmd] for Unit.Wants of [$FULL_SERVICE]\n");
+ system @cmd;
+ }
+ }
+ if (defined $data->{'Unit.Requires'}) {
+ for my $x (@{ $data->{'Unit.Requires'} }) {
+ if (exists $starting_stack{$x}) {
+ log_command("Skipping start of [$x], we are already in the process of starting it.\n");
+ next;
+ }
+ my @cmd = ($0, 'start', $x);
+ log_command("Running [@cmd] for Unit.Requires of [$FULL_SERVICE]\n");
+ if (system @cmd) {
+ log_command("Failed to start [$x], aborting start\n");
+ exit 1;
+ }
+ }
+ }
+ if (defined $data->{'Service.PIDFile'} and is_running($data)) {
+ log_command("Service [$FULL_SERVICE] defines PIDFile [$data->{'Service.PIDFile'}] and it seems to have already started, not starting again.\n");
+ exit;
+ }
+
+ if ($TYPE eq 'target') {
+ exit;
+ }
+ if ($TYPE eq 'socket' and -S $data->{'Socket.ListenStream'}) {
+ my $out = `/usr/sbin/fuser $data->{'Socket.ListenStream'} 2> /dev/null`;
+ if (defined $out and $out ne '') {
+ log_command("Service [$FULL_SERVICE] already found active on socket [$data->{'Socket.ListenStream'}], not starting again.\n");
+ exit;
+ }
+ }
+ if (defined $data->{'Service.Type'} and $data->{'Service.Type'} eq 'dbus') {
+ my @cmd = ($0, 'start', 'dbus.socket');
+ log_command("Running [@cmd] for Service.Type dbus\n");
+ system @cmd;
+ }
+ if (defined $data->{'Service.ExecStartPre'}) {
+ for my $x (@{ $data->{'Service.ExecStartPre'} }) {
+ my $can_fail = 0;
+ if ($x =~ s/^-//) {
+ $can_fail = 1;
+ }
+ my @cmd = split /\s+/, $x;
+ if (not $data->{'Service.PermissionsStartOnly'} or $data->{'Service.PermissionsStartOnly'} =~ /^(false|0)$/i) {
+ add_runuser($data, \@cmd);
+ }
+ no warnings 'uninitialized';
+ log_command("Running start pre [@cmd]\n");
+ if (system @cmd and not $can_fail) {
+ exit 1;
+ }
+ }
+ }
+ my @paths;
+ if ($TYPE eq 'socket') {
+ my $service = $SERVICE;
+ if (defined $data->{'Socket.Accept'} and $data->{'Socket.Accept'} eq 'true') {
+ $service =~ s/\.socket$/\@.service/;
+ @paths = ( '/bin/systemctl-socket-daemon', $data->{'Socket.ListenStream'}, $data->{'Socket.SocketMode'} // '0666', $service );
+ } else {
+ $service =~ s/\.socket$/\.service/;
+ my $ret = system "$0 is-active $service > /dev/null";
+ if (($ret >> 8) == 0) {
+ log_command("Service [$service] is already running for [$SERVICE]\n");
+ exit;
+ }
+ @paths = ( $0, 'start', $service );
+ }
+ } else {
+ @paths = get_exec_start($data);
+ }
+ my $first_path = $paths[0];
+
+ my $ENV = '';
+ if (exists $data->{'Service.EnvironmentFile'}) {
+ for my $e (@{ $data->{'Service.EnvironmentFile'} }) {
+ my $error_fail = 1;
+ if ($e =~ s/^-//) {
+ $error_fail = 0;
+ }
+ my $fh = new IO::File($e);
+ if (not defined $fh) {
+ if ($error_fail) {
+ warn "Error reading EnvironmentFile [$e]: $!\n";
+ exit 5;
+ }
+ } else {
+ while (my $line = <$fh>) {
+ chomp $line;
+ next if $line =~ /^\s*(#|$)/;
+ $ENV .= "export $line; ";
+ }
+ $fh->close();
+ }
+ }
+ }
+ if (defined $data->{'Service.Environment'}) {
+ my $x = $data->{'Service.Environment'};
+ $x =~ s/^"(.*)"$/$1/;
+ $ENV .= "export $x; ";
+ }
+ add_runuser($data, \@paths);
+ log_command("Running [$ENV@paths]\n");
+ if (defined $data->{'Service.Type'} and $data->{'Service.Type'} eq 'oneshot') {
+ system "$ENV@paths";
+ if (defined $data->{'Service.RemainAfterExit'} and $data->{'Service.RemainAfterExit'} eq 'yes') {
+ local * PIDFILE;
+ open PIDFILE, '>', "$RUNNING_DIR/$FULL_SERVICE.oneshot";
+ close PIDFILE;
+ }
+ exit;
+ }
+ my $pid = fork();
+ die "Failed to fork for [@_]\n" if not defined $pid;
+ if ($pid == 0) {
+ open(STDOUT, '>>', '/var/log/systemctl.log');
+ open(STDERR, '>>', '/var/log/systemctl.log');
+ open(STDIN, '<', '/dev/null');
+ POSIX::setsid();
+ exec "$ENV@paths";
+ }
+ if (defined $data->{'Service.PIDFile'}) {
+ log_command("Service [$FULL_SERVICE] defines PIDFile [$data->{'Service.PIDFile'}], not marking pid\n");
+ unlink "$RUNNING_DIR/$FULL_SERVICE.pid";
+ my $i = 0;
+ while (not -f $data->{'Service.PIDFile'}) {
+ sleep 0.2;
+ $i++;
+ if ($i > 250) {
+ log_command("Starting [$FULL_SERVICE] did not create PIDFile [$data->{'Service.PIDFile'}]\n");
+ exit 10;
+ }
+ }
+ my $pid = get_pid($data->{'Service.PIDFile'});
+ if (not defined $pid or not kill 0, $pid) {
+ log_command("Starting [$FULL_SERVICE] created PIDFile [$data->{'Service.PIDFile'}] but the process is not running\n");
+ exit 11;
+ }
+ } else {
+ local * PIDFILE;
+ open PIDFILE, '>', "$RUNNING_DIR/$FULL_SERVICE.pid";
+ print PIDFILE "$pid\n";
+ close PIDFILE;
+ log_command("Marked pid [$pid] for [$FULL_SERVICE]\n");
+ sleep 1;
+ if (defined $data->{'Service.Type'} and $data->{'Service.Type'} ne 'simple' and $data->{'Service.Type'} ne 'notify' and pidof($first_path)) {
+ local * PIDFILE;
+ open PIDFILE, '>', "$RUNNING_DIR/$FULL_SERVICE.name";
+ print PIDFILE "$first_path\n";
+ close PIDFILE;
+ log_command("Marked process name [$first_path] for [$FULL_SERVICE]\n");
+ }
+ }
+ if (defined $data->{'Service.Type'}
+ and $data->{'Service.Type'} eq 'dbus'
+ and defined $data->{'Service.BusName'}) {
+ my $busname = $data->{'Service.BusName'};
+ my $objectpath = $busname;
+ $objectpath =~ s!^|\.!/!g;
+ for (0 .. 10) {
+ system "/usr/bin/dbus-send --system --type=method_call --print-reply --dest=$busname $objectpath org.freedesktop.DBus.Introspectable.Introspect > /dev/null";
+ exit if ($? >> 8) == 0;
+ sleep 1;
+ }
+ exit 9;
+ }
+ exit;
+}
+
+if ($COMMAND eq 'is-enabled') {
+ if (-e "$ENABLED_DIR/$FULL_SERVICE") {
+ print "enabled\n";
+ exit 0;
+ }
+ print "disabled\n";
+ exit 1;
+}
+
+if ($COMMAND eq 'enable') {
+ if (not -d $ENABLED_DIR) {
+ mkdir $ENABLED_DIR;
+ }
+ local * FILE;
+ open FILE, '>', "$ENABLED_DIR/$FULL_SERVICE";
+ exit;
+}
+
+if ($COMMAND eq 'disable') {
+ unlink "$ENABLED_DIR/$FULL_SERVICE";
+ exit;
+}
+
+die "Unknown command [$COMMAND].\n";
+
+1;
+
diff --git a/99-ci-twentythree/systemctl-socket-daemon b/99-ci-twentythree/systemctl-socket-daemon
new file mode 100644
index 0000000..5250cad
--- /dev/null
+++ b/99-ci-twentythree/systemctl-socket-daemon
@@ -0,0 +1,67 @@
+#!/usr/bin/perl
+
+# Copyright 2014 Jan Pazdziora
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+use strict;
+use warnings FATAL => 'all';
+
+use IO::Socket::UNIX ();
+use Socket ();
+use POSIX ();
+
+sub daemonize {
+ open(STDERR, '>>', '/var/log/systemctl-socket-daemon.log') || die "can't write log: $!";
+ open(STDOUT, '>&STDERR') || die "can't write stdout to log: $!";
+ chdir("/") || die "can't chdir to /: $!";
+ open(STDIN, '<', '/dev/null') || die "can't read /dev/null: $!";
+ defined(my $pid = fork()) || die "can't fork: $!";
+ exit if $pid; # non-zero now means I am the parent
+ (POSIX::setsid() != -1) || die "Can't start a new session: $!";
+}
+
+my ($socket_path, $socket_mode, $service) = @ARGV;
+if (not defined $socket_path or not defined $service) {
+ die "Usage: $0 /path/to/unix/socket service-to-run\n";
+}
+if (-e $socket_path) {
+ warn "Path [$socket_path] already exists, removing\n";
+ unlink $socket_path;
+}
+
+my $service_data = `/bin/systemctl show $service 2>&1`;
+if ($?) {
+ die "Failed to find service [$service]:\n$service_data";
+}
+
+my $socket = new IO::Socket::UNIX(
+ Type => Socket::SOCK_STREAM,
+ Local => $socket_path,
+ Listen => Socket::SOMAXCONN
+) or die "socket: $!\n";
+chmod oct($socket_mode), $socket_path;
+
+daemonize();
+
+while (1) {
+ next unless my $connection = $socket->accept;
+ my $pid = fork();
+ if ($pid == 0) {
+ *STDIN = $connection;
+ *STDOUT = $connection;
+ exec '/bin/systemctl', 'start', $service;
+ die "exec should have never reached here\n";
+ }
+}
+
diff --git a/99-ci-twentythree/vimrc b/99-ci-twentythree/vimrc
new file mode 100644
index 0000000..30fa2ed
--- /dev/null
+++ b/99-ci-twentythree/vimrc
@@ -0,0 +1,9 @@
+set shiftwidth=4
+set tabstop=4
+set expandtab
+set enc=utf-8
+
+autocmd BufNewFile,BufRead /srv/cyrus-imapd.git/*/*.{c,h} set tabstop=8 softtabstop=4 shiftwidth=4 list listchars=tab:>. noexpandtab
+autocmd BufNewFile,BufRead /srv/cyrus-imapd.git/cunit/cunit.pl set tabstop=8 softtabstop=4 shiftwidth=4 list listchars=tab:>. noexpandtab
+autocmd BufNewFile,BufRead /srv/cyrus-imapd.git/configure.ac set tabstop=8 shiftwidth=8 noexpandtab
+
diff --git a/99-ci-twentytwo/Dockerfile b/99-ci-twentytwo/Dockerfile
new file mode 100644
index 0000000..b24d793
--- /dev/null
+++ b/99-ci-twentytwo/Dockerfile
@@ -0,0 +1,98 @@
+FROM fedora:22
+MAINTAINER Kolab Systems <vanmeeuwen@kolabsys.com>
+
+ADD http://obs.kolabsys.com/repositories/Kolab:/Development/Fedora_22/Kolab:Development.repo \
+ /etc/yum.repos.d/Kolab:Development.repo
+
+RUN echo "priority=60" >> /etc/yum.repos.d/Kolab:Development.repo
+
+RUN rpm --import https://ssl.kolabsys.com/community.asc
+
+ADD http://download.opensuse.org/repositories/openSUSE:Tools/Fedora_22/openSUSE:Tools.repo \
+ /etc/yum.repos.d/openSUSE:Tools.repo
+
+RUN rpm --import http://download.opensuse.org/repositories/openSUSE:/Tools/Fedora_22/repodata/repomd.xml.key
+
+RUN sed -i \
+ -e '/tsflags=nodocs/d' \
+ -e '/override_install_langs/d' \
+ /etc/dnf/dnf.conf
+
+#RUN dnf -y reinstall \* && \
+# dnf clean all
+
+ENV IMAGE twentytwo
+
+ADD /dbus.service /etc/systemd/system/dbus.service
+RUN ln -sf dbus.service /etc/systemd/system/messagebus.service
+
+ADD /httpd.service /etc/systemd/system/httpd.service
+
+ADD /systemctl /usr/bin/systemctl
+ADD /systemctl-socket-daemon /usr/bin/systemctl-socket-daemon
+
+RUN chmod -v a+rx \
+ /usr/bin/systemctl \
+ /usr/bin/systemctl-socket-daemon
+
+ADD /vimrc /root/.vimrc
+
+RUN dnf clean all && \
+ dnf -y install \
+ ant \
+ bind-utils \
+ build \
+ git \
+ lsof \
+ net-tools \
+ nmap-ncat \
+ openldap-clients \
+ osc \
+ perl-Data-Dumper \
+ perl-Digest-MD5 \
+ perl-TimeDate \
+ php-phpunit-PHPUnit-Selenium \
+ psmisc \
+ rpmdevtools \
+ screen \
+ strace \
+ sudo \
+ telnet \
+ traceroute \
+ vim-enhanced \
+ wget \
+ yum-utils && \
+ dnf clean all
+
+RUN sed -i -e '/requiretty/d' /etc/sudoers
+
+WORKDIR /srv
+RUN git clone https://github.com/google/closure-compiler.git closure-compiler.git
+WORKDIR /srv/closure-compiler.git
+RUN ant jar
+
+ADD http://mirror.kolabsys.com/pub/releases/selenium-server-standalone.jar /usr/local/lib/selenium-server-standalone.jar
+
+#WORKDIR /srv
+#RUN git clone https://github.com/SeleniumHQ/selenium.git selenium.git
+#WORKDIR /srv/selenium.git
+#RUN ./go --trace --verbose build
+#RUN ./go selenium-server-standalone
+
+WORKDIR /srv
+RUN wget http://mirror.kolabsys.com/pub/releases/phantomjs-1.9.7-linux-x86_64.tar.bz2 && \
+ tar jxvf phantomjs-1.9.7-linux-x86_64.tar.bz2 && \
+ cp phantomjs-1.9.7-linux-x86_64/bin/phantomjs /usr/local/bin/ && \
+ rm -rf phantomjs-1.9.7-linux-x86_64*
+
+#WORKDIR /srv/
+#RUN git clone https://github.com/ariya/phantomjs.git phantomjs.git
+#WORKDIR /srv/phantomjs.git
+#RUN ./build.sh --confirm
+
+ADD /functions.sh /
+ADD entrypoint.sh /
+
+RUN chmod 755 /entrypoint.sh
+
+ENTRYPOINT [ "/entrypoint.sh" ]
diff --git a/99-ci-twentytwo/dbus.service b/99-ci-twentytwo/dbus.service
new file mode 100644
index 0000000..0be95c4
--- /dev/null
+++ b/99-ci-twentytwo/dbus.service
@@ -0,0 +1,16 @@
+[Unit]
+Description=D-Bus System Message Bus
+Requires=dbus.socket
+After=syslog.target
+
+[Service]
+PIDFile=/var/run/messagebus.pid
+ExecStartPre=/bin/mkdir -p /var/run/dbus
+ExecStartPre=/bin/chmod g+w /var/run/ /var/run/dbus/
+ExecStart=/bin/dbus-daemon --system --fork
+ExecReload=/bin/dbus-send --print-reply --system --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig
+ExecStopPost=/bin/rm -f /var/run/messagebus.pid
+OOMScoreAdjust=-900
+User=dbus
+Group=root
+PermissionsStartOnly=true
diff --git a/99-ci-twentytwo/entrypoint.sh b/99-ci-twentytwo/entrypoint.sh
new file mode 100755
index 0000000..a099eca
--- /dev/null
+++ b/99-ci-twentytwo/entrypoint.sh
@@ -0,0 +1,148 @@
+#!/bin/bash
+
+if [ ! -d "/srv/stick.git" ]; then
+ git clone https://git.kolab.org/diffusion/QA/stick.git /srv/stick.git
+elif [ -z "${PS1}" ]; then
+ pushd /srv/stick.git
+ git remote set-url origin https://git.kolab.org/diffusion/QA/stick.git
+ git fetch origin
+ git reset --hard origin/master
+ git clean -d -f -x
+ popd
+fi
+
+source /functions.sh
+
+export TEST_BUILD=${TEST_BUILD:-0}
+export TEST_FUNCTIONAL=${TEST_FUNCTIONAL:-0}
+export TEST_INTEGRATION=${TEST_INTEGRATION:-0}
+export TEST_PERFORMANCE=${TEST_PERFORMANCE:-0}
+export TEST_UNIT=${TEST_UNIT:-0}
+export TEST_OBS=${TEST_OBS:-0}
+
+# If PS1 is set, we're interactive
+if [ ! -z "${PS1}" ]; then
+ # Set a sensible prompt
+ PS1='[\u@${IMAGE} \W]\$ '
+
+ export GIT_PS1_SHOWDIRTYSTATE=1
+ export GIT_PS1_SHOWUNTRACKEDFILES=1
+ export GIT_PS1_SHOWUPSTREAM="auto verbose"
+
+ if [ ! -f "/etc/bash_completion" ]; then
+ if [ -f "/etc/bash_completion.d/git" ]; then
+ . /etc/bash_completion.d/git
+ PS1='[\u@${IMAGE} \W$(__git_ps1 " (%s)")]\$ '
+ fi
+ else
+ PS1='[\u@${IMAGE} \W$(__git_ps1 " (%s)")]\$ '
+ fi
+
+ export PS1
+
+ PROMPT_COMMAND="echo -ne '\033]0;${IMAGE} (in ${HOSTNAME})\007'"
+
+ if [ -f "/usr/share/git-core/contrib/completion/git-prompt.sh" ]; then
+ source /usr/share/git-core/contrib/completion/git-prompt.sh
+ fi
+fi
+
+if [ ! -d "/srv/${PACKAGE}.git" ]; then
+ git clone ${RO_URI} /srv/${PACKAGE}.git
+
+ pushd /srv/${PACKAGE}.git
+
+ for branch in $(git branch -la | sed -e 's/^* //g' -e 's/ //g' -e '/remotes\/origin\/HEAD/d' -e 's|remotes/origin/||g' | sort -u); do
+ git checkout $branch
+ done
+
+ popd
+else
+ pushd /srv/${PACKAGE}.git
+
+ git remote set-url origin ${RO_URI}
+ git fetch origin
+ git reset --hard origin/master
+ git clean -d -f -x
+
+ for branch in $(git branch -la | sed -e 's/^* //g' -e '/\(detached from/d' -e 's/ //g' -e '/remotes\/origin\/HEAD/d' -e 's|remotes/origin/||g' | sort -u); do
+ git checkout $branch
+ done
+
+ popd
+fi
+
+retval=0
+
+if [ -x "$(which yum 2>/dev/null)" ]; then
+ yum clean metadata; retval=$(( ${retval} + $? ))
+ yum -y update; retval=$(( ${retval} + $? ))
+ rpmdev-setuptree; retval=$(( ${retval} + $? ))
+elif [ -x "$(which apt-get 2>/dev/null)" ]; then
+ apt-get update; retval=$(( ${retval} + $? ))
+fi
+
+pushd /srv/${PACKAGE}.git
+
+if [ ! -z "${COMMIT}" ]; then
+ git checkout ${COMMIT}; retval=$(( ${retval} + $? ))
+fi
+
+# TODO: A differential has a base commit.
+
+if [ ${retval} -ne 0 ]; then
+ _report
+ exit 1
+fi
+
+if [ -x "../stick.git/drydocker/${PACKAGE}/test_build.sh" -a ${TEST_BUILD} -eq 1 ]; then
+ retval=$(_shell ../stick.git/drydocker/${PACKAGE}/test_build.sh)
+ if [ ${retval} -ne 0 ]; then
+ _report
+ exit 1
+ fi
+fi
+
+if [ -x "../stick.git/drydocker/${PACKAGE}/test_unit.sh" -a ${TEST_UNIT} -eq 1 ]; then
+ retval=$(_shell ../stick.git/drydocker/${PACKAGE}/test_unit.sh)
+ if [ ${retval} -ne 0 ]; then
+ _report
+ exit 1
+ fi
+fi
+
+if [ -x "../stick.git/drydocker/${PACKAGE}/test_functional.sh" -a ${TEST_FUNCTIONAL} -eq 1 ]; then
+ retval=$(_shell ../stick.git/drydocker/${PACKAGE}/test_functional.sh)
+ if [ ${retval} -ne 0 ]; then
+ _report
+ exit 1
+ fi
+fi
+
+if [ -x "../stick.git/drydocker/${PACKAGE}/test_obs.sh" ]; then
+ retval=$(_shell ../stick.git/drydocker/${PACKAGE}/test_obs.sh)
+ if [ ${retval} -ne 0 ]; then
+ _report
+ exit 1
+ fi
+fi
+
+if [ -x "../stick.git/drydocker/${PACKAGE}/test_integration.sh" -a ${TEST_INTEGRATION} -eq 1 ]; then
+ retval=$(_shell ../stick.git/drydocker/${PACKAGE}/test_integration.sh)
+ if [ ${retval} -ne 0 ]; then
+ _report
+ exit 1
+ fi
+fi
+
+if [ -x "../stick.git/drydocker/${PACKAGE}/test_obs_checkin.sh" ]; then
+ retval=$(_shell ../stick.git/drydocker/${PACKAGE}/test_obs_checkin.sh)
+ if [ ${retval} -ne 0 ]; then
+ _report
+ exit 1
+ fi
+fi
+
+popd
+
+_report
diff --git a/99-ci-twentytwo/functions.sh b/99-ci-twentytwo/functions.sh
new file mode 100644
index 0000000..27a9d32
--- /dev/null
+++ b/99-ci-twentytwo/functions.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+
+# Create 3 as an alias for 1, so the _shell function
+# can output data without the caller getting the input.
+exec 3>&1
+
+function _report {
+ echo $(printf '%0.1s' "="{1..72})
+ cat ${TMPDIR:-/tmp}/report.log
+ rm -rf ${TMPDIR:-/tmp}/report.log
+ echo $(printf '%0.1s' "="{1..72})
+}
+
+export -f _report
+
+function _report_msg {
+ printf "%*s" $(( ( ${BASH_SUBSHELL} - 1 ) * 4 )) " " >> ${TMPDIR:-/tmp}/report.log
+ echo "$@" >> ${TMPDIR:-/tmp}/report.log
+}
+
+export -f _report_msg
+
+function _shell {
+ revision=$(git rev-parse HEAD 2>/dev/null)
+ if [ -z "${revision}" ]; then
+ pushd /srv/${PACKAGE}.git >/dev/null 2>&1 3>&1
+ revision=$(git rev-parse HEAD 2>/dev/null)
+ popd >/dev/null 2>&1 3>&1
+ fi
+
+ if [ -z "${revision}" ]; then
+ revision=unknown
+ fi
+
+ echo "Running $@ ..." >&3
+ $@ >&3 2>&3 ; retval=$?
+
+ if [ ${retval} -eq 0 ]; then
+ _report_msg "Running '$@' OK (at ${revision})"
+ echo "Running $@ OK (at ${revision})" >&3
+ else
+ _report_msg "Running '$@' FAILED (at ${revision})"
+ echo "Running $@ FAILED (at ${revision})" >&3
+ fi
+
+ echo ${retval}
+}
+
+export -f _shell
+
+function _install_package {
+ if [ -x "$(which yum 2>/dev/null)" ]; then
+ yum -y install $@
+ elif [ -x "$(which apt-get 2>/dev/null)" ]; then
+ apt-get -y install $@
+ fi
+}
+
+function _install_package_builddep {
+ if [ -x "$(which yum 2>/dev/null)" ]; then
+ yum-builddep -y --disablerepo=openSUSE_Tools $@
+ elif [ -x "$(which apt-get 2>/dev/null)" ]; then
+ apt-get -y build-dep $@
+ fi
+}
diff --git a/99-ci-twentytwo/httpd.service b/99-ci-twentytwo/httpd.service
new file mode 100644
index 0000000..ba7ec71
--- /dev/null
+++ b/99-ci-twentytwo/httpd.service
@@ -0,0 +1,4 @@
+.include /lib/systemd/system/httpd.service
+[Service]
+PIDFile=/var/run/httpd/httpd.pid
+
diff --git a/99-ci-twentytwo/sudoers.drydock-worker b/99-ci-twentytwo/sudoers.drydock-worker
new file mode 100644
index 0000000..489b82b
--- /dev/null
+++ b/99-ci-twentytwo/sudoers.drydock-worker
@@ -0,0 +1 @@
+drydock-worker ALL=(ALL) NOPASSWD: ALL
diff --git a/99-ci-twentytwo/systemctl b/99-ci-twentytwo/systemctl
new file mode 100644
index 0000000..6a15c0b
--- /dev/null
+++ b/99-ci-twentytwo/systemctl
@@ -0,0 +1,680 @@
+#!/usr/bin/perl
+
+# Copyright 2014 Jan Pazdziora
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+use strict;
+use warnings FATAL => 'all';
+
+use IO::File ();
+use IO::Dir ();
+use IO::Socket::UNIX ();
+use Socket ();
+use Data::Dumper ();
+use POSIX ();
+use Time::HiRes qw(sleep time);
+
+sub log_command {
+ local * LOG;
+ open(LOG, '>>', '/var/log/systemctl.log');
+ print LOG @_;
+ close LOG;
+}
+log_command("[@ARGV]\n");
+shift if @ARGV and $ARGV[0] eq '-q';
+
+for (my $i = 0; $i < @ARGV; $i++) {
+ if ($ARGV[$i] eq '--ignore-dependencies') {
+ splice @ARGV, $i, 1;
+ last;
+ }
+}
+if (@ARGV == 1 and $ARGV[0] eq 'daemon-reload') {
+ exit 0;
+}
+if (@ARGV == 2 and $ARGV[0] eq '--system' and $ARGV[1] eq 'daemon-reload') {
+ exit 0;
+}
+
+for (keys %ENV) {
+ delete $ENV{$_} unless $_ eq '_SYSTEMCTL_LITE_STARTING';
+}
+
+my $RUNNING_DIR = '/run/systemctl-lite-running';
+if (not -d $RUNNING_DIR) {
+ mkdir $RUNNING_DIR;
+}
+my $ENABLED_DIR = '/etc/systemctl-lite-enabled';
+if (@ARGV == 1) {
+ if ($ARGV[0] eq 'start-enabled' and -d $ENABLED_DIR) {
+ local * ENABLED;
+ opendir ENABLED, $ENABLED_DIR;
+ my %services;
+ while (defined(my $f = readdir ENABLED)) {
+ next if $f eq '.' or $f eq '..';
+ my $modified = (stat "$ENABLED_DIR/$f")[9];
+ if (defined $modified) {
+ $services{$f} = $modified;
+ }
+ }
+ close ENABLED;
+ for my $s (sort { $services{$a} <=> $services{$b} or $a cmp $b } keys %services) {
+ print "Starting [$s]\n";
+ system $0, 'start', $s;
+ exit ($? >> 8) if ($? >> 8);
+ }
+ }
+ if ($ARGV[0] eq 'stop-running' and -d $RUNNING_DIR) {
+ local * RUNNING;
+ opendir RUNNING, $RUNNING_DIR;
+ my %services;
+ while (defined(my $f = readdir RUNNING)) {
+ next if $f eq '.' or $f eq '..';
+ my $modified = (stat "$RUNNING_DIR/$f")[9];
+ if (defined $modified) {
+ my $trimmed = $f;
+ $trimmed =~ s/\..+$//;
+ $services{$trimmed} = $modified;
+ }
+ }
+ close RUNNING;
+ for my $s (sort { $services{$b} <=> $services{$a} or $a cmp $b } keys %services) {
+ system $0, 'stop', $s;
+ }
+ }
+ exit;
+}
+
+if (@ARGV != 2) {
+ die "Usage: $0 (start|stop|status|...) (service|target|socket thing)\n";
+}
+
+my ($COMMAND, $SERVICE) = @ARGV;
+my $TYPE = 'service';
+if ($SERVICE =~ /\.(target|socket)$/) {
+ $TYPE = $1;
+} elsif (not $SERVICE =~ /\.service$/) {
+ $SERVICE .= '.service';
+}
+
+my @PATHS = (
+ '/etc/systemd/system',
+ '/run/systemd/system',
+ '/usr/lib/systemd/system',
+);
+
+my $FULL_SERVICE = $SERVICE;
+my $INSTANCE = undef;
+
+my $file = undef;
+if ($SERVICE =~ s/\@(.+)\.service$/\@.service/) {
+ $INSTANCE = $1;
+}
+for my $p (@PATHS) {
+ if (-e "$p/$SERVICE") {
+ if (-l "$p/$SERVICE") {
+ my $new_service = readlink("$p/$SERVICE");
+ log_command("Service [$p/$SERVICE] is a symlink to [$new_service]\n");
+ $new_service =~ s!^.*/!!;
+ $SERVICE = $new_service;
+ }
+ $file = "$p/$SERVICE";
+ last;
+ }
+}
+
+if ($SERVICE =~ s/\@(.+)\.service$/\@.service/) {
+ $INSTANCE = $1;
+ for my $p (@PATHS) {
+ if (-f "$p/$SERVICE") {
+ $file = "$p/$SERVICE";
+ last;
+ }
+ }
+}
+
+if (not defined $file) {
+ if ($COMMAND eq 'is-enabled') {
+ exit 1;
+ }
+ if ($COMMAND eq 'is-active') {
+ exit 3;
+ }
+ warn "No service definition found for [$FULL_SERVICE].\n";
+ exit 2;
+}
+
+sub parse_file {
+ my ($file, $data) = @_;
+ if (-d $file) {
+ my $op;
+ if ($file =~ /\.requires$/) {
+ $op = 'Unit.Requires';
+ } elsif ($file =~ /\.wants$/) {
+ $op = 'Unit.Wants';
+ } else {
+ die "Unknown directory [$file].\n";
+ }
+ my $dh = new IO::Dir($file);
+ while (defined(my $de = $dh->read)) {
+ next if $de eq '.' or $de eq '..';
+ push @{$data->{$op}}, $de unless $de =~ /\.target$/;
+ }
+ $dh->close;
+ return;
+ }
+ my $fh = new IO::File($file);
+ my $section = 'undefined';
+ while (my $line = <$fh>) {
+ chomp $line;
+ if ($line =~ /^\[(.+)\]\s*$/) {
+ $section = $1;
+ next;
+ }
+ next if $line =~ /^\s*(#|$)/;
+ if ($line =~ /^\.include\s(.+)/) {
+ parse_file($1, $data);
+ next;
+ }
+ my ($key, $value) = split /=/, $line, 2;
+ if (defined $INSTANCE) {
+ $value =~ s/\%i/$INSTANCE/g;
+ }
+ if ($key eq 'EnvironmentFile') {
+ if ($value eq '') {
+ delete $data->{"$section.$key"};
+ } else {
+ push @{ $data->{"$section.$key"} }, $value;
+ }
+ } elsif ($key =~ /^(Wants|Requires)$/) {
+ push @{ $data->{"$section.$key"} }, $value unless $value =~ /\.target$/;
+ } elsif ($key =~ /^(ExecStart(Pre|Post)|ExecReload|ExecStop(Pre|Post)?)$/) {
+ push @{ $data->{"$section.$key"} }, $value;
+ } else {
+ $data->{"$section.$key"} = $value;
+ }
+ }
+ $fh->close;
+ if (defined $data->{'Service.ExecStart'} and not defined $data->{'Service.PIDFile'}) {
+ my ($pidfile) = grep /^\/.+\.pid$/, split /\s+/, $data->{'Service.ExecStart'};
+ if (defined $pidfile) {
+ $data->{'Service.PIDFile'} = $pidfile;
+ log_command("Guessing pid file [$data->{'Service.PIDFile'}] from ExecStart [$data->{'Service.ExecStart'}]\n");
+ }
+ }
+}
+
+my $data = {};
+parse_file($file, $data);
+for my $p (@PATHS) {
+ if (-d "$p/$SERVICE.wants") {
+ $file = "$p/$SERVICE.wants";
+ parse_file("$p/$SERVICE.wants", $data);
+ last;
+ }
+}
+
+if ($COMMAND eq 'show') {
+ print Data::Dumper::Dumper $data;
+ exit;
+}
+
+sub pidof {
+ my $command = shift;
+ my $pids = `/usr/sbin/pidof $command`;
+ chomp $pids;
+ if ($pids ne '') {
+ return split /\s+/, $pids;
+ }
+ return;
+}
+
+sub get_exec_start {
+ my $data = shift;
+ my $d = $data->{'Service.ExecStart'};
+ if (not defined $d) {
+ warn "No ExecStart value found for [$SERVICE].\n";
+ exit 3;
+ }
+ return split /\s+/, $d;
+}
+
+sub get_pid {
+ my $file = shift;
+ if (not $file =~ m!^/!) {
+ $file = "$RUNNING_DIR/$file";
+ }
+ if (-f $file) {
+ local * PIDFILE;
+ open PIDFILE, '<', $file;
+ my $pid = <PIDFILE>;
+ close PIDFILE;
+ if (defined $pid) {
+ chomp $pid;
+ return $pid;
+ }
+ }
+}
+
+sub is_running {
+ my $data = shift;
+ my $ret;
+ if (-f "$RUNNING_DIR/$FULL_SERVICE.oneshot") {
+ return 1;
+ } elsif (defined $data->{'Service.PIDFile'}) {
+ my $pid = get_pid($data->{'Service.PIDFile'});
+ if (defined $pid) {
+ $ret = kill 0, $pid;
+ }
+ } else {
+ my $path = get_pid("$FULL_SERVICE.name");
+ if (defined $path) {
+ if (pidof($path)) {
+ $ret = 1;
+ }
+ } else {
+ my $pid = get_pid("$FULL_SERVICE.pid");
+ if (defined $pid) {
+ $ret = kill 0, $pid;
+ }
+ }
+ }
+ return $ret;
+}
+if ($COMMAND eq 'is-active' or $COMMAND eq 'status') {
+ if (is_running($data)) {
+ print "active\n";
+ exit;
+ }
+ print "inactive\n";
+ exit 3;
+}
+
+sub exec_stop_pre {
+ my ($data) = @_;
+ if (defined $data->{'Socket.ExecStopPre'}) {
+ for my $x (@{ $data->{'Socket.ExecStopPre'} }) {
+ log_command("Running stop pre [$x]\n");
+ system $x;
+ }
+ }
+}
+sub exec_stop_post {
+ my ($data) = @_;
+ if (defined $data->{'Service.ExecStopPost'}) {
+ for my $x (@{ $data->{'Service.ExecStopPost'} }) {
+ log_command("Running stop post [$x]\n");
+ system $x;
+ }
+ }
+}
+
+if ($TYPE eq 'target' and not defined $data->{'Unit.Wants'} and not defined $data->{'Unit.Requires'}) {
+ warn "No Unit.Wants/.wants/Unit.Requires/.requires list for target [$SERVICE]\n";
+ exit 8;
+}
+
+if ($COMMAND eq 'restart') {
+ if ($TYPE ne 'service' or is_running($data)) {
+ system $0, 'stop', $FULL_SERVICE;
+ }
+ system $0, 'start', $FULL_SERVICE;
+ exit;
+}
+
+sub pids_went_away_timeout {
+ my $timeout = shift;
+ my $start = time;
+ while (kill 0, @_) {
+ if (time - $start > $timeout) {
+ log_command(sprintf(" ** pid(s) [%s] not killed within %d s\n", join(', ', @_), $timeout));
+ return 0;
+ }
+ sleep 0.1;
+ }
+ log_command(sprintf(" ** pid(s) [%s] got killed after %.2f s\n", join(', ', @_), time - $start));
+ return 1;
+}
+
+sub stop_pids {
+ my @pids = @_;
+ kill 15, @pids;
+ if (not pids_went_away_timeout(5, @pids)) {
+ kill 9, @pids;
+ if (not pids_went_away_timeout(5, @pids)) {
+ log_command("Failed to kill [@pids] even with 9\n");
+ warn "Failed to kill [@pids].\n";
+ return 1;
+ }
+ log_command("Killed [@pids] with 9\n");
+ } else {
+ log_command("Killed [@pids] with 15\n");
+ }
+ return 0;
+}
+
+if ($COMMAND eq 'stop') {
+ my $mainpid;
+ if (defined $data->{'Service.PIDFile'}) {
+ $mainpid = get_pid($data->{'Service.PIDFile'});
+ } else {
+ $mainpid = get_pid("$FULL_SERVICE.pid");
+ }
+ if (defined $data->{'Service.ExecStop'}) {
+ for my $x (@{ $data->{'Service.ExecStop'} }) {
+ my $runit = 1;
+ if (defined $mainpid) {
+ $x =~ s!\$MAINPID\b|\$\{MAINPID\}!$mainpid!g;
+ } elsif ($x =~ /\$MAINPID\b|\$\{MAINPID\}/) {
+ $runit = 0;
+ log_command("Service [$FULL_SERVICE] would like to stop via ExecStop [$x] but we have no pid file, skipping.\n");
+ }
+ if ($runit) {
+ log_command("Running stop [$x]\n");
+ system $x;
+ sleep 1;
+ }
+ }
+ }
+ my $ret = undef;
+ if ($TYPE eq 'target') {
+ # noop
+ } elsif (defined $data->{'Service.Type'} and $data->{'Service.Type'} eq 'oneshot') {
+ # noop
+ } elsif ($TYPE eq 'socket') {
+ my $pids = `/usr/sbin/fuser $data->{'Socket.ListenStream'} 2> /dev/null`;
+ if (defined $pids) {
+ chomp $pids;
+ $pids =~ s/^\s+//;
+ my @pids = split /\s+/, $pids;
+ if (@pids) {
+ exec_stop_pre($data);
+ log_command("Will kill [@pids] as fuser [$data->{'Socket.ListenStream'}] of [$FULL_SERVICE]\n");
+ $ret = stop_pids(@pids);
+ }
+ }
+ } elsif (defined $data->{'Service.PIDFile'}) {
+ my $pid = get_pid($data->{'Service.PIDFile'});
+ if (defined $pid) {
+ log_command("Will kill [$pid] found in Service.PIDFile of [$FULL_SERVICE]\n");
+ $ret = stop_pids($pid);
+ }
+ } else {
+ my $path = get_pid("$FULL_SERVICE.name");
+ if (defined $path) {
+ if (my @pids = pidof($path)) {
+ log_command("Will kill [@pids] as pidof [$path] found in [$FULL_SERVICE.name]\n");
+ $ret = stop_pids(@pids);
+ } else {
+ warn "No pidof for [$path] found in [$FULL_SERVICE.name].\n";
+ }
+ } else {
+ my $pid = get_pid("$FULL_SERVICE.pid");
+ if (defined $pid) {
+ log_command("Will kill [$pid] found in [$FULL_SERVICE.pid]\n");
+ $ret = stop_pids($pid);
+ } else {
+ warn "No pid and no name for [$FULL_SERVICE].\n";
+ }
+ }
+ }
+ exec_stop_post($data);
+ unlink "$RUNNING_DIR/$FULL_SERVICE.pid", "$RUNNING_DIR/$FULL_SERVICE.name", "$RUNNING_DIR/$FULL_SERVICE.oneshot";
+ if (defined $data->{'Unit.Wants'}) {
+ for my $x (@{ $data->{'Unit.Wants'} }) {
+ system $0, 'stop', $x;
+ }
+ }
+ if (defined $data->{'Unit.Requires'}) {
+ for my $x (@{ $data->{'Unit.Requires'} }) {
+ system $0, 'stop', $x;
+ }
+ }
+ exit ( defined $ret ? $ret : 0 );
+}
+
+sub add_runuser {
+ my ($data, $cmd) = @_;
+ if (defined $data->{'Service.User'}) {
+ unshift @$cmd, '-u', $data->{'Service.User'}, '--';
+ if (defined $data->{'Service.Group'}) {
+ unshift @$cmd, '-g', $data->{'Service.Group'};
+ }
+ unshift @$cmd, '/usr/sbin/runuser';
+ }
+}
+
+if ($COMMAND eq 'start') {
+ my (@starting_stack, %starting_stack);
+ if (defined $ENV{_SYSTEMCTL_LITE_STARTING}) {
+ @starting_stack = split /:/, $ENV{_SYSTEMCTL_LITE_STARTING};
+ @starting_stack{@starting_stack} = ();
+ $ENV{_SYSTEMCTL_LITE_STARTING} .= ":$FULL_SERVICE";
+ } else {
+ $ENV{_SYSTEMCTL_LITE_STARTING} = $FULL_SERVICE;
+ }
+
+ if ($TYPE eq 'service' and is_running($data)) {
+ log_command("Service [$FULL_SERVICE] already found running, not starting again.\n");
+ exit;
+ }
+ if (defined $data->{'Service.PIDFile'}) {
+ log_command("Service [$FULL_SERVICE] defines PIDFile [$data->{'Service.PIDFile'}], unlinking it before start\n");
+ unlink $data->{'Service.PIDFile'};
+ }
+ if (defined $data->{'Unit.Wants'}) {
+ for my $x (@{ $data->{'Unit.Wants'} }) {
+ if (exists $starting_stack{$x}) {
+ log_command("Skipping start of [$x], we are already in the process of starting it.\n");
+ next;
+ }
+ my @cmd = ($0, 'start', $x);
+ log_command("Running [@cmd] for Unit.Wants of [$FULL_SERVICE]\n");
+ system @cmd;
+ }
+ }
+ if (defined $data->{'Unit.Requires'}) {
+ for my $x (@{ $data->{'Unit.Requires'} }) {
+ if (exists $starting_stack{$x}) {
+ log_command("Skipping start of [$x], we are already in the process of starting it.\n");
+ next;
+ }
+ my @cmd = ($0, 'start', $x);
+ log_command("Running [@cmd] for Unit.Requires of [$FULL_SERVICE]\n");
+ if (system @cmd) {
+ log_command("Failed to start [$x], aborting start\n");
+ exit 1;
+ }
+ }
+ }
+ if (defined $data->{'Service.PIDFile'} and is_running($data)) {
+ log_command("Service [$FULL_SERVICE] defines PIDFile [$data->{'Service.PIDFile'}] and it seems to have already started, not starting again.\n");
+ exit;
+ }
+
+ if ($TYPE eq 'target') {
+ exit;
+ }
+ if ($TYPE eq 'socket' and -S $data->{'Socket.ListenStream'}) {
+ my $out = `/usr/sbin/fuser $data->{'Socket.ListenStream'} 2> /dev/null`;
+ if (defined $out and $out ne '') {
+ log_command("Service [$FULL_SERVICE] already found active on socket [$data->{'Socket.ListenStream'}], not starting again.\n");
+ exit;
+ }
+ }
+ if (defined $data->{'Service.Type'} and $data->{'Service.Type'} eq 'dbus') {
+ my @cmd = ($0, 'start', 'dbus.socket');
+ log_command("Running [@cmd] for Service.Type dbus\n");
+ system @cmd;
+ }
+ if (defined $data->{'Service.ExecStartPre'}) {
+ for my $x (@{ $data->{'Service.ExecStartPre'} }) {
+ my $can_fail = 0;
+ if ($x =~ s/^-//) {
+ $can_fail = 1;
+ }
+ my @cmd = split /\s+/, $x;
+ if (not $data->{'Service.PermissionsStartOnly'} or $data->{'Service.PermissionsStartOnly'} =~ /^(false|0)$/i) {
+ add_runuser($data, \@cmd);
+ }
+ no warnings 'uninitialized';
+ log_command("Running start pre [@cmd]\n");
+ if (system @cmd and not $can_fail) {
+ exit 1;
+ }
+ }
+ }
+ my @paths;
+ if ($TYPE eq 'socket') {
+ my $service = $SERVICE;
+ if (defined $data->{'Socket.Accept'} and $data->{'Socket.Accept'} eq 'true') {
+ $service =~ s/\.socket$/\@.service/;
+ @paths = ( '/bin/systemctl-socket-daemon', $data->{'Socket.ListenStream'}, $data->{'Socket.SocketMode'} // '0666', $service );
+ } else {
+ $service =~ s/\.socket$/\.service/;
+ my $ret = system "$0 is-active $service > /dev/null";
+ if (($ret >> 8) == 0) {
+ log_command("Service [$service] is already running for [$SERVICE]\n");
+ exit;
+ }
+ @paths = ( $0, 'start', $service );
+ }
+ } else {
+ @paths = get_exec_start($data);
+ }
+ my $first_path = $paths[0];
+
+ my $ENV = '';
+ if (exists $data->{'Service.EnvironmentFile'}) {
+ for my $e (@{ $data->{'Service.EnvironmentFile'} }) {
+ my $error_fail = 1;
+ if ($e =~ s/^-//) {
+ $error_fail = 0;
+ }
+ my $fh = new IO::File($e);
+ if (not defined $fh) {
+ if ($error_fail) {
+ warn "Error reading EnvironmentFile [$e]: $!\n";
+ exit 5;
+ }
+ } else {
+ while (my $line = <$fh>) {
+ chomp $line;
+ next if $line =~ /^\s*(#|$)/;
+ $ENV .= "export $line; ";
+ }
+ $fh->close();
+ }
+ }
+ }
+ if (defined $data->{'Service.Environment'}) {
+ my $x = $data->{'Service.Environment'};
+ $x =~ s/^"(.*)"$/$1/;
+ $ENV .= "export $x; ";
+ }
+ add_runuser($data, \@paths);
+ log_command("Running [$ENV@paths]\n");
+ if (defined $data->{'Service.Type'} and $data->{'Service.Type'} eq 'oneshot') {
+ system "$ENV@paths";
+ if (defined $data->{'Service.RemainAfterExit'} and $data->{'Service.RemainAfterExit'} eq 'yes') {
+ local * PIDFILE;
+ open PIDFILE, '>', "$RUNNING_DIR/$FULL_SERVICE.oneshot";
+ close PIDFILE;
+ }
+ exit;
+ }
+ my $pid = fork();
+ die "Failed to fork for [@_]\n" if not defined $pid;
+ if ($pid == 0) {
+ open(STDOUT, '>>', '/var/log/systemctl.log');
+ open(STDERR, '>>', '/var/log/systemctl.log');
+ open(STDIN, '<', '/dev/null');
+ POSIX::setsid();
+ exec "$ENV@paths";
+ }
+ if (defined $data->{'Service.PIDFile'}) {
+ log_command("Service [$FULL_SERVICE] defines PIDFile [$data->{'Service.PIDFile'}], not marking pid\n");
+ unlink "$RUNNING_DIR/$FULL_SERVICE.pid";
+ my $i = 0;
+ while (not -f $data->{'Service.PIDFile'}) {
+ sleep 0.2;
+ $i++;
+ if ($i > 250) {
+ log_command("Starting [$FULL_SERVICE] did not create PIDFile [$data->{'Service.PIDFile'}]\n");
+ exit 10;
+ }
+ }
+ my $pid = get_pid($data->{'Service.PIDFile'});
+ if (not defined $pid or not kill 0, $pid) {
+ log_command("Starting [$FULL_SERVICE] created PIDFile [$data->{'Service.PIDFile'}] but the process is not running\n");
+ exit 11;
+ }
+ } else {
+ local * PIDFILE;
+ open PIDFILE, '>', "$RUNNING_DIR/$FULL_SERVICE.pid";
+ print PIDFILE "$pid\n";
+ close PIDFILE;
+ log_command("Marked pid [$pid] for [$FULL_SERVICE]\n");
+ sleep 1;
+ if (defined $data->{'Service.Type'} and $data->{'Service.Type'} ne 'simple' and $data->{'Service.Type'} ne 'notify' and pidof($first_path)) {
+ local * PIDFILE;
+ open PIDFILE, '>', "$RUNNING_DIR/$FULL_SERVICE.name";
+ print PIDFILE "$first_path\n";
+ close PIDFILE;
+ log_command("Marked process name [$first_path] for [$FULL_SERVICE]\n");
+ }
+ }
+ if (defined $data->{'Service.Type'}
+ and $data->{'Service.Type'} eq 'dbus'
+ and defined $data->{'Service.BusName'}) {
+ my $busname = $data->{'Service.BusName'};
+ my $objectpath = $busname;
+ $objectpath =~ s!^|\.!/!g;
+ for (0 .. 10) {
+ system "/usr/bin/dbus-send --system --type=method_call --print-reply --dest=$busname $objectpath org.freedesktop.DBus.Introspectable.Introspect > /dev/null";
+ exit if ($? >> 8) == 0;
+ sleep 1;
+ }
+ exit 9;
+ }
+ exit;
+}
+
+if ($COMMAND eq 'is-enabled') {
+ if (-e "$ENABLED_DIR/$FULL_SERVICE") {
+ print "enabled\n";
+ exit 0;
+ }
+ print "disabled\n";
+ exit 1;
+}
+
+if ($COMMAND eq 'enable') {
+ if (not -d $ENABLED_DIR) {
+ mkdir $ENABLED_DIR;
+ }
+ local * FILE;
+ open FILE, '>', "$ENABLED_DIR/$FULL_SERVICE";
+ exit;
+}
+
+if ($COMMAND eq 'disable') {
+ unlink "$ENABLED_DIR/$FULL_SERVICE";
+ exit;
+}
+
+die "Unknown command [$COMMAND].\n";
+
+1;
+
diff --git a/99-ci-twentytwo/systemctl-socket-daemon b/99-ci-twentytwo/systemctl-socket-daemon
new file mode 100644
index 0000000..5250cad
--- /dev/null
+++ b/99-ci-twentytwo/systemctl-socket-daemon
@@ -0,0 +1,67 @@
+#!/usr/bin/perl
+
+# Copyright 2014 Jan Pazdziora
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+use strict;
+use warnings FATAL => 'all';
+
+use IO::Socket::UNIX ();
+use Socket ();
+use POSIX ();
+
+sub daemonize {
+ open(STDERR, '>>', '/var/log/systemctl-socket-daemon.log') || die "can't write log: $!";
+ open(STDOUT, '>&STDERR') || die "can't write stdout to log: $!";
+ chdir("/") || die "can't chdir to /: $!";
+ open(STDIN, '<', '/dev/null') || die "can't read /dev/null: $!";
+ defined(my $pid = fork()) || die "can't fork: $!";
+ exit if $pid; # non-zero now means I am the parent
+ (POSIX::setsid() != -1) || die "Can't start a new session: $!";
+}
+
+my ($socket_path, $socket_mode, $service) = @ARGV;
+if (not defined $socket_path or not defined $service) {
+ die "Usage: $0 /path/to/unix/socket service-to-run\n";
+}
+if (-e $socket_path) {
+ warn "Path [$socket_path] already exists, removing\n";
+ unlink $socket_path;
+}
+
+my $service_data = `/bin/systemctl show $service 2>&1`;
+if ($?) {
+ die "Failed to find service [$service]:\n$service_data";
+}
+
+my $socket = new IO::Socket::UNIX(
+ Type => Socket::SOCK_STREAM,
+ Local => $socket_path,
+ Listen => Socket::SOMAXCONN
+) or die "socket: $!\n";
+chmod oct($socket_mode), $socket_path;
+
+daemonize();
+
+while (1) {
+ next unless my $connection = $socket->accept;
+ my $pid = fork();
+ if ($pid == 0) {
+ *STDIN = $connection;
+ *STDOUT = $connection;
+ exec '/bin/systemctl', 'start', $service;
+ die "exec should have never reached here\n";
+ }
+}
+
diff --git a/99-ci-twentytwo/vimrc b/99-ci-twentytwo/vimrc
new file mode 100644
index 0000000..30fa2ed
--- /dev/null
+++ b/99-ci-twentytwo/vimrc
@@ -0,0 +1,9 @@
+set shiftwidth=4
+set tabstop=4
+set expandtab
+set enc=utf-8
+
+autocmd BufNewFile,BufRead /srv/cyrus-imapd.git/*/*.{c,h} set tabstop=8 softtabstop=4 shiftwidth=4 list listchars=tab:>. noexpandtab
+autocmd BufNewFile,BufRead /srv/cyrus-imapd.git/cunit/cunit.pl set tabstop=8 softtabstop=4 shiftwidth=4 list listchars=tab:>. noexpandtab
+autocmd BufNewFile,BufRead /srv/cyrus-imapd.git/configure.ac set tabstop=8 shiftwidth=8 noexpandtab
+