This closes another unfixed detail
of issue #657 "divide abrtd into two parts to get rid of inotify"
Signed-off-by: Denys Vlasenko <dvlasenk(a)redhat.com>
---
src/daemon/abrt-handle-upload.in | 267 ++++++++++++++++++++++++++-------------
1 file changed, 180 insertions(+), 87 deletions(-)
diff --git a/src/daemon/abrt-handle-upload.in b/src/daemon/abrt-handle-upload.in
index e727db6..e258c3b 100755
--- a/src/daemon/abrt-handle-upload.in
+++ b/src/daemon/abrt-handle-upload.in
@@ -1,90 +1,183 @@
-#!/bin/sh
+#!/usr/bin/python -u
# Called by abrtd when a new file is noticed in upload directory.
# The task of this script is to unpack the file and move
# problem data found in it to abrtd spool directory.
-#
-# Usage: abrt-handle-upload [-d] ABRT_SPOOL_DIR UPLOAD_DIR FILENAME
-#
-# -d - deletes an uploaded archive
-# ABRT_SPOOL_DIR - a directory where valid uploaded archives are unpacked to
-# UPLOAD_DIR - a directory where uploaded archives are stored in
-# FILENAME - an uploaded archive file name
-
-#echo "Started: $0 $*"
-
-print_clean_and_die()
-{
- printf "%s\n" "$*"
- #echo delete_on_exit="$delete_on_exit"
- test "$delete_on_exit" && rm -rf -- $delete_on_exit
- exit $die_exitcode
-}
-
-die_exitcode=1
-delete_on_exit=""
-
-delete_archive=false
-if test x"$1" == x"-d"; then delete_archive=true; shift; fi
-
-abrt_dir="$1"
-upload_dir="$2"
-archive="$3"
-
-test -d "$abrt_dir" || print_clean_and_die "Not a directory:
'$abrt_dir'"
-test -d "$upload_dir" || print_clean_and_die "Not a directory:
'$upload_dir'"
-test x"${archive#/}" != x"$archive" && print_clean_and_die
"Skipping: '$archive' (starts with slash)"
-test x"${archive#.}" != x"$archive" && print_clean_and_die
"Skipping: '$archive' (starts with dot)"
-test x"${archive#*..}" != x"$archive" && print_clean_and_die
"Skipping: '$archive' (contains ..)"
-test x"${archive#* }" != x"$archive" && print_clean_and_die
"Skipping: '$archive' (contains space)"
-# Note: next line has a tab!
-test x"${archive#* }" != x"$archive" && print_clean_and_die
"Skipping: '$archive' (contains tab)"
-
-cd -- "$upload_dir" || print_clean_and_die "Can't chdir to
'$upload_dir'"
-
-unpacker=""
-test x"${archive%.tar.gz}" != x"$archive" &&
unpacker="gunzip"
-test x"${archive%.tar.bz2}" != x"$archive" &&
unpacker="bunzip2"
-test x"${archive%.tar.xz}" != x"$archive" &&
unpacker="unxz"
-
-test "$unpacker" || print_clean_and_die "Unknown file type:
'$archive'"
-
-workingdir=`mktemp -d "abrt_handle_upload.XXXXXXXXXX"
--tmpdir=@LARGE_DATA_TMP_DIR@` || print_clean_and_die "Can't create working
directory"
-delete_on_exit="$workingdir"
-
-tempdir="$workingdir/remote.`date +%Y-%m-%d-%H:%M:%S.%N`.$$"
-working_archive="$workingdir/$archive"
-
-if $delete_archive; then
- mv -- "$archive" "$working_archive" || print_clean_and_die
"Can't move '$archive' to '$working_archive'"
-else
- cp -- "$archive" "$working_archive" || print_clean_and_die
"Can't copy '$archive' to '$working_archive'"
-fi
-
-$unpacker -t -- "$working_archive" || print_clean_and_die "Verification
error on '$archive'"
-
-echo "Unpacking '$archive'"
-mkdir "$tempdir" || print_clean_and_die "Can't create
'$tempdir' directory"
-$unpacker <"$working_archive" | tar xf - -C "$tempdir" ||
print_clean_and_die "Can't unpack '$archive'"
-
-# The archive can contain either plain dump files
-# or one or more complete problem data directories.
-# Checking second possibility first.
-if test -f "$tempdir/analyzer" && test -f "$tempdir/time"
&& test -f "$tempdir/uid"; then
- printf "1" >"$tempdir/remote"
- mv -- "$tempdir" "$abrt_dir"
-else
- (
- cd -- "$tempdir" || exit
- for d in *; do
- test -d "$d" || continue
- printf "1" >"$d/remote"
- dst="$abrt_dir/$d"
- test -e "$dst" && dst="$abrt_dir/$d.$$"
- test -e "$dst" && continue
- mv -- "$d" "$dst"
- done
- )
-fi
-
-die_exitcode=0
-print_clean_and_die "'$archive' processed successfully"
+
+import sys
+import os
+import getopt
+import tempfile
+import shutil
+import datetime
+
+from reportclient import _, set_verbosity, error_msg_and_die, error_msg, log1, log
+import problem
+
+def spawn_and_wait(prog):
+ return os.spawnlp(os.P_WAIT, prog, prog)
+
+def write_str_to(filename, s):
+ fd = os.open(filename, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0666)
+ if fd >= 0:
+ os.write(fd, s)
+ os.close(fd)
+
+if __name__ == "__main__":
+
+ # Helper: exit with cleanup
+ die_exitcode = 1
+ delete_on_exit = None
+ def print_clean_and_die(fmt, *args):
+ sys.stderr.write("%s\n" % (fmt % args))
+ if delete_on_exit:
+ shutil.rmtree(delete_on_exit, True) # True: ignore_errors
+ sys.exit(die_exitcode)
+
+ # localization
+ #init_gettext() - done by reportclient module init
+
+ verbose = 0
+ ABRT_VERBOSE = os.getenv("ABRT_VERBOSE")
+ if ABRT_VERBOSE:
+ try:
+ verbose = int(ABRT_VERBOSE)
+ except:
+ pass
+
+ progname = os.path.basename(sys.argv[0])
+ help_text = _(
+ "Usage: %s [-vd] ABRT_SPOOL_DIR UPLOAD_DIR FILENAME"
+ "\n"
+ "\n -v - Verbose"
+ "\n -d - Delete uploaded archive"
+ "\n ABRT_SPOOL_DIR - Directory where valid uploaded archives are unpacked
to"
+ "\n UPLOAD_DIR - Directory where uploaded archives are stored"
+ "\n FILENAME - Uploaded archive file name"
+ "\n"
+ ) % progname
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "vdh", ["help"])
+ except getopt.GetoptError as err:
+ error_msg(err) # prints something like "option -a not recognized"
+ error_msg_and_die(help_text)
+
+ delete_archive = False
+ for opt, arg in opts:
+ if opt in ("-h", "--help"):
+ print help_text
+ sys.exit(0)
+ if opt == "-v":
+ verbose += 1
+ if opt == "-d":
+ delete_archive = True
+
+ set_verbosity(verbose)
+
+ if len(args) < 3:
+ error_msg_and_die(help_text)
+
+ abrt_dir = args[0]
+ upload_dir = args[1]
+ archive = args[2]
+
+ if not os.path.isdir(abrt_dir):
+ error_msg_and_die("Not a directory: '%s'", abrt_dir)
+
+ if not os.path.isdir(upload_dir):
+ error_msg_and_die("Not a directory: '%s'", upload_dir)
+
+ if archive[0] == "/":
+ error_msg_and_die("Skipping: '%s' (starts with slash)",
archive)
+
+ if archive[0] == ".":
+ error_msg_and_die("Skipping: '%s' (starts with dot)", archive)
+
+ if ".." in archive:
+ error_msg_and_die("Skipping: '%s' (contains ..)", archive)
+
+ if " " in archive:
+ error_msg_and_die("Skipping: '%s' (contains space)", archive)
+
+ if "\t" in archive:
+ error_msg_and_die("Skipping: '%s' (contains tab)", archive)
+
+ try:
+ os.chdir(upload_dir)
+ except OSError:
+ error_msg_and_die("Can't change directory to '%s'",
upload_dir)
+
+ if archive.endswith(".tar.gz"):
+ unpacker = "gunzip"
+ elif archive.endswith(".tgz"):
+ unpacker = "gunzip"
+ elif archive.endswith(".tar.bz2"):
+ unpacker = "bunzip2"
+ elif archive.endswith(".tar.xz"):
+ unpacker = "unxz"
+ else:
+ error_msg_and_die("Unknown file type: '%s'", archive)
+
+ try:
+ working_dir = tempfile.mkdtemp(prefix="abrt_handle_upload.",
dir="@LARGE_DATA_TMP_DIR@")
+ except OSError:
+ error_msg_and_die("Can't create working directory in '%s'",
"@LARGE_DATA_TMP_DIR@")
+ delete_on_exit = working_dir
+
+ try:
+ tempdir = working_dir + "/remote." +
datetime.datetime.now().strftime("%Y-%m-%d-%H:%M:%S.%f.") + str(os.getpid())
+ working_archive = working_dir + "/" + archive
+
+ if delete_archive:
+ try:
+ shutil.move(archive, working_archive)
+ except IOError:
+ print_clean_and_die("Can't move '%s' to
'%s'", archive, working_archive)
+ else:
+ try:
+ shutil.copy(archive, working_archive)
+ except IOError:
+ print_clean_and_die("Can't copy '%s' to
'%s'", archive, working_archive)
+
+ ex = os.spawnlp(os.P_WAIT, unpacker, unpacker, "-t", "--",
working_archive)
+ if ex != 0:
+ print_clean_and_die("Verification error on '%s'", archive)
+
+ log("Unpacking '%s'", archive)
+ try:
+ os.mkdir(tempdir)
+ except OSError:
+ print_clean_and_die("Can't create '%s' directory",
tempdir)
+
+ ex = os.system(unpacker+" <"+working_archive+" | tar xf - -C
"+tempdir)
+ if ex != 0:
+ print_clean_and_die("Can't unpack '%s'", archive)
+
+ # The archive can contain either plain dump files
+ # or one or more complete problem data directories.
+ # Checking second possibility first.
+ if os.path.exists(tempdir+"/analyzer") and
os.path.exists(tempdir+"/time"):
+ write_str_to(tempdir+"/remote", "1")
+ shutil.move(tempdir, abrt_dir)
+ problem.notify_new_path(abrt_dir+"/"+os.path.basename(tempdir))
+ else:
+ for d in os.listdir(tempdir):
+ if not os.path.isdir(tempdir+"/"+d):
+ continue
+ write_str_to(tempdir+"/"+d+"/remote", "1")
+ dst = abrt_dir+"/"+d
+ if os.path.exists(dst):
+ dst += "."+str(os.getpid())
+ if os.path.exists(dst):
+ continue
+ shutil.move(tempdir+"/"+d, dst)
+ problem.notify_new_path(dst)
+
+ die_exitcode = 0
+ # This deletes working_dir (== delete_on_exit)
+ print_clean_and_die("'%s' processed successfully", archive)
+
+ except:
+ if delete_on_exit:
+ shutil.rmtree(delete_on_exit, True) # True: ignore_errors
+ raise
--
1.8.1.4