|
@@ -0,0 +1,116 @@
|
|
|
+#! /usr/bin/env python3
|
|
|
+"""
|
|
|
+This script checks for available updates on Void Linux using xbps and notifies
|
|
|
+the configured administrator account about them. It currently requires
|
|
|
+python 3.x and no additional packages and is supposed to be run with cron or
|
|
|
+another scheduled execution mechanism.
|
|
|
+"""
|
|
|
+
|
|
|
+import subprocess
|
|
|
+import smtplib
|
|
|
+import socket
|
|
|
+import re
|
|
|
+
|
|
|
+from email.mime.multipart import MIMEMultipart
|
|
|
+from email.mime.text import MIMEText
|
|
|
+
|
|
|
+
|
|
|
+# Email server to be used to send the notification
|
|
|
+ADMIN_EMAIL = "root"
|
|
|
+# Mail server to be used to send the notification
|
|
|
+MAIL_SERVER = "localhost"
|
|
|
+# Port to use on the mail server
|
|
|
+MAIL_SERVER_PORT = 25
|
|
|
+# User name to log in to the mail server
|
|
|
+MAIL_SERVER_USER = ""
|
|
|
+# Password to log in to the mail server
|
|
|
+MAIL_SERVER_PASSWORD = ""
|
|
|
+
|
|
|
+AVAILABLE_UPDATES = []
|
|
|
+
|
|
|
+DEVNULL = open("/dev/null", "w")
|
|
|
+
|
|
|
+try:
|
|
|
+ XBPS_INSTALL_RESULT = subprocess.check_output(["xbps-install", "-Sun"],
|
|
|
+ stderr=DEVNULL)
|
|
|
+except subprocess.CalledProcessError:
|
|
|
+ pass
|
|
|
+else:
|
|
|
+ XBPS_INSTALL_RESULT = XBPS_INSTALL_RESULT.decode("utf-8").split("\n")
|
|
|
+ for line in XBPS_INSTALL_RESULT:
|
|
|
+ if "update" in line:
|
|
|
+ try:
|
|
|
+ package = line.split(" ")[0]
|
|
|
+ package_regex = "^([A-Za-z0-9-]*)-([0-9].*_[0-9])$"
|
|
|
+ match_object = re.match(package_regex, package)
|
|
|
+ package_name = match_object.groups()[0]
|
|
|
+ new_package_version = match_object.groups()[1]
|
|
|
+ except IndexError:
|
|
|
+ continue
|
|
|
+ else:
|
|
|
+ try:
|
|
|
+ xbps_query_result = subprocess.check_output(
|
|
|
+ ["xbps-query", "--show", package_name], stderr=DEVNULL)
|
|
|
+ except subprocess.CalledProcessError:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ xbps_query_result = xbps_query_result.decode(
|
|
|
+ "utf-8").split("\n")
|
|
|
+ for line in xbps_query_result:
|
|
|
+ if "pkgver" in line:
|
|
|
+ installed_package = line.split(
|
|
|
+ ":")[1].strip()
|
|
|
+ match = re.match(package_regex,
|
|
|
+ installed_package)
|
|
|
+ installed_package_version = match.groups()[1]
|
|
|
+ package_update = {
|
|
|
+ "name": package_name,
|
|
|
+ "new_version": new_package_version,
|
|
|
+ "old_version": installed_package_version,
|
|
|
+ }
|
|
|
+ AVAILABLE_UPDATES.append(package_update)
|
|
|
+ break
|
|
|
+if AVAILABLE_UPDATES:
|
|
|
+ HOSTNAME = socket.getfqdn()
|
|
|
+ MSG = MIMEMultipart()
|
|
|
+ MAIL_TEXT = "The following package updates are available on host %s:\n\n"\
|
|
|
+ % HOSTNAME
|
|
|
+ MSG["Subject"] = "%s updates available on host %s"\
|
|
|
+ % (len(AVAILABLE_UPDATES), HOSTNAME)
|
|
|
+ MSG["From"] = "voixicron@%s" % HOSTNAME
|
|
|
+ MSG["To"] = ADMIN_EMAIL
|
|
|
+ for update in AVAILABLE_UPDATES:
|
|
|
+ MAIL_TEXT += "%s (%s -> %s)\n"\
|
|
|
+ % (update["name"],
|
|
|
+ update["old_version"],
|
|
|
+ update["new_version"])
|
|
|
+ MSG_TEXT = MIMEText(MAIL_TEXT.encode("utf-8"), _charset="utf-8")
|
|
|
+ MSG.attach(MSG_TEXT)
|
|
|
+ SERVER_CONNECTION = smtplib.SMTP(MAIL_SERVER, MAIL_SERVER_PORT)
|
|
|
+ try:
|
|
|
+ SERVER_CONNECTION.connect()
|
|
|
+ except (smtplib.SMTPConnectError, smtplib.SMTPServerDisconnected,
|
|
|
+ socket.error):
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ try:
|
|
|
+ SERVER_CONNECTION.starttls()
|
|
|
+ except smtplib.SMTPException:
|
|
|
+ pass
|
|
|
+ if MAIL_SERVER_USER:
|
|
|
+ try:
|
|
|
+ SERVER_CONNECTION.login(MAIL_SERVER_USER, MAIL_SERVER_PASSWORD)
|
|
|
+ except smtplib.SMTPAuthenticationError:
|
|
|
+ pass
|
|
|
+ except smtplib.SMTPException:
|
|
|
+ pass
|
|
|
+ try:
|
|
|
+ SERVER_CONNECTION.sendmail("voixicron@%s" % HOSTNAME, ADMIN_EMAIL,
|
|
|
+ MSG.as_string())
|
|
|
+ except smtplib.SMTPRecipientsRefused:
|
|
|
+ pass
|
|
|
+ except smtplib.SMTPSenderRefused:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ SERVER_CONNECTION.quit()
|
|
|
+DEVNULL.close()
|