summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTing-Wei Lan <lantw44@gmail.com>2015-01-29 21:19:32 +0800
committerTing-Wei Lan <lantw44@gmail.com>2015-01-29 21:19:32 +0800
commitae8bb35d10c22e3c62b963b5b7f70b4475fd9b6f (patch)
tree70d5ec6f878dc63856a26e9788828409d283e320
downloadmisc-tools-ae8bb35d10c22e3c62b963b5b7f70b4475fd9b6f.tar.gz
misc-tools-ae8bb35d10c22e3c62b963b5b7f70b4475fd9b6f.tar.zst
misc-tools-ae8bb35d10c22e3c62b963b5b7f70b4475fd9b6f.zip
Initial commit - import things written for various hosts
-rwxr-xr-xadmin/rpmdu.sh50
-rwxr-xr-xadmin/rpmsize.sh43
-rwxr-xr-xadmin/search-login.py65
-rwxr-xr-xadmin/ssh-bad-login.sh39
-rwxr-xr-xadmin/yumdb-reason-editor.py198
-rw-r--r--char/test-wchar.c31
-rwxr-xr-xdesktop/empathy-xml2txt.py20
-rwxr-xr-xdesktop/gen-ms-inet-shortcut.sh11
-rwxr-xr-xdesktop/webkit1-gtk-user-agent.py11
-rwxr-xr-xdesktop/webkit2-gtk-user-agent.py11
-rwxr-xr-xdownload/flickr-download-public.py51
-rwxr-xr-ximage/set-time-from-exif-info.sh17
-rw-r--r--network/in_addr-show.c23
-rwxr-xr-xnetwork/unescape.js18
-rwxr-xr-xpackage/check-update-chromium.py36
-rw-r--r--system/get-login.c7
-rw-r--r--system/set-login.c15
-rw-r--r--system/test-libacl.c469
-rw-r--r--system/test-libcap.c206
19 files changed, 1321 insertions, 0 deletions
diff --git a/admin/rpmdu.sh b/admin/rpmdu.sh
new file mode 100755
index 0000000..ef360b1
--- /dev/null
+++ b/admin/rpmdu.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+div_base=1024
+div_name="KB"
+if [ "`echo "$1" | cut -c 1`" = "-" ]
+then
+ optname=`echo "$1" | cut -c 2-`
+ case "$optname" in
+ "k")
+ ;;
+ "m")
+ div_base=1048576
+ div_name=MB
+ ;;
+ "g")
+ div_base=1073741824
+ div_name=GB
+ ;;
+ *)
+ echo "Usage: `basename "$0"` [OPTION] package_name..."
+ echo " -k KB"
+ echo " -m MB"
+ echo " -g GB"
+ exit 1
+ ;;
+ esac
+ shift
+fi
+
+while [ "$1" ]
+do
+ rpm -ql "$1" | {
+ while read oneline
+ do
+ if [ -f "$oneline" ]
+ then
+ du -k "$oneline"
+ fi
+ done
+ } | {
+ while read -d $'\t' filesize
+ do
+ total=$((${total}+${filesize}))
+ read
+ done
+ printf "%9d %s %s\n" "$(($total/$div_base))" "$div_name" "$1"
+ }
+
+ shift
+done
+
diff --git a/admin/rpmsize.sh b/admin/rpmsize.sh
new file mode 100755
index 0000000..d884810
--- /dev/null
+++ b/admin/rpmsize.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+div_base=1
+div_name="Bytes"
+if [ "`echo "$1" | cut -c 1`" = "-" ]
+then
+ optname=`echo "$1" | cut -c 2-`
+ case "$optname" in
+ "b")
+ ;;
+ "k")
+ div_base=1024
+ div_name=KB
+ ;;
+ "m")
+ div_base=1048576
+ div_name=MB
+ ;;
+ "g")
+ div_base=1073741824
+ div_name=GB
+ ;;
+ *)
+ echo "Usage: `basename "$0"` [OPTION] package_name..."
+ echo " -b Byte"
+ echo " -k KB"
+ echo " -m MB"
+ echo " -g GB"
+ exit 1
+ ;;
+ esac
+ shift
+fi
+while [ "$1" ]
+do
+ total=0
+ filesize=`rpm -q "$1" --queryformat "%{SIZE} "`
+ for i in $filesize
+ do
+ total=$((${total}+${i}))
+ done
+ printf "%12d %s %s\n" "$(($total/$div_base))" "$div_name" "$1"
+ shift
+done
diff --git a/admin/search-login.py b/admin/search-login.py
new file mode 100755
index 0000000..ba87958
--- /dev/null
+++ b/admin/search-login.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python3
+
+import sys
+import re
+from datetime import datetime
+
+if len(sys.argv) < 3:
+ sys.stderr.write(
+ 'Usage: {} output_of_last_FRw event_list\n'.format(sys.argv[0]))
+ quit(1)
+
+last_output = open(sys.argv[1], 'r')
+event_list = open(sys.argv[2], 'r')
+records = []
+
+while True:
+ last_line_raw = last_output.readline().strip()
+ if not last_line_raw:
+ break
+
+ last_line = last_line_raw
+ user_end_index = last_line.find(' ')
+ user = last_line[0:user_end_index]
+ if user == 'reboot':
+ continue
+
+ last_line = last_line[user_end_index:len(last_line)].strip()
+ terminal_end_index = last_line.find(' ')
+ terminal = last_line[0:terminal_end_index]
+
+ day_start_index = last_line.find(' ')
+ last_line = last_line[day_start_index:len(last_line)].strip()
+ date_start_index = last_line.find(' ')
+ last_line = last_line[date_start_index:len(last_line)].strip()
+
+ login_time = last_line[0:20]
+ separator = last_line[20:23]
+ logout_time = last_line[27:47]
+
+ login = datetime.strptime(login_time, '%b %d %H:%M:%S %Y')
+ if separator == ' - ' and not logout_time.startswith(' '):
+ logout = datetime.strptime(logout_time, '%b %d %H:%M:%S %Y')
+ else:
+ logout = datetime.max
+
+ records.append({
+ 'user': user,
+ 'tty': terminal,
+ 'login': login,
+ 'logout': logout,
+ 'raw': last_line_raw
+ })
+
+
+while True:
+ event_raw = event_list.readline().strip()
+ if not event_raw:
+ break
+
+ event = event_raw
+ event_time = datetime.strptime(event, '%Y-%m-%d %H:%M:%S')
+
+ for record in records:
+ if event_time >= record['login'] and event_time <= record['logout']:
+ print(event_time, '{0:16} => {1}'.format(record['user'], record['raw']))
diff --git a/admin/ssh-bad-login.sh b/admin/ssh-bad-login.sh
new file mode 100755
index 0000000..69519d6
--- /dev/null
+++ b/admin/ssh-bad-login.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+if [ "$1" ]; then
+ since="$1"
+else
+ since="`date "+%Y-%m-%d"`"
+fi
+
+if [ "$2" ]; then
+ until="$2"
+else
+ until="now"
+fi
+
+journalctl _SYSTEMD_UNIT=sshd.service \
+ --since="$since" --until="$until" | \
+ grep 'Failed password for' | \
+ sed -e 's/.*from\ //g' -e 's/\ port.*//g' | sort -n | {
+ count=0;
+ firstrun=0;
+ printed=0;
+ while read oneline;
+ do
+ printed=0;
+ if [ "$prevline" != "$oneline" ] && [ "$firstrun" = "1" ];
+ then
+ echo "$count $prevline";
+ count=0;
+ printed=1;
+ fi
+ count=$(($count+1));
+ prevline="$oneline";
+ firstrun=1;
+ done
+ if [ "$printed" = "0" ];
+ then
+ echo "$count $prevline";
+ fi } | \
+ sort -nr
diff --git a/admin/yumdb-reason-editor.py b/admin/yumdb-reason-editor.py
new file mode 100755
index 0000000..9a47691
--- /dev/null
+++ b/admin/yumdb-reason-editor.py
@@ -0,0 +1,198 @@
+#!/usr/bin/env python2
+
+import yum
+from gi.repository import Gtk
+
+
+class YumDB:
+ def __init__(self):
+ self.yb = yum.YumBase()
+ self.yb.conf
+
+ def get_reasons(self, patterns=None):
+ reasons = []
+ for pkg in sorted(self.yb.rpmdb.returnPackages(patterns=patterns)):
+ reasons.append({'nevra': pkg.nevra, \
+ 'group_member': pkg.yumdb_info.group_member \
+ if hasattr(pkg.yumdb_info, 'group_member') else '', \
+ 'reason': pkg.yumdb_info.reason \
+ if hasattr(pkg.yumdb_info, 'reason') else '<unset>', \
+ 'reason_editor': pkg.yumdb_info.reason_editor \
+ if hasattr(pkg.yumdb_info, 'reason_editor') else ''})
+ return reasons
+
+ def get_summary(self, nevra):
+ return self.yb.rpmdb.returnPackages(patterns=[ nevra ])[0].summary
+
+ def get_description(self, nevra):
+ return self.yb.rpmdb.returnPackages(patterns=[ nevra ])[0].description
+
+ def set_reason(self, nevra, value):
+ try:
+ pkg = self.yb.rpmdb.returnPackages(patterns=[ nevra ])[0]
+ except IndexError as e:
+ return '{} does not exists!'.format(nevra)
+
+ try:
+ pkg.yumdb_info.reason = value
+ pkg.yumdb_info.reason_editor = 'modified'
+ except Exception as e:
+ return '{} fails: {}'.format(nevra, e[1])
+
+ return True
+
+
+class PkgList(Gtk.TreeView):
+ def add_column(self, name, index):
+ renderer = Gtk.CellRendererText()
+ column = Gtk.TreeViewColumn(name)
+ column.pack_start(renderer, True)
+ column.add_attribute(renderer, 'text', index)
+ column.set_resizable(True)
+ column.set_sort_column_id(index)
+ column.set_sort_indicator(index)
+ self.append_column(column)
+
+class ReasonEditor(Gtk.Window):
+ COLUMN_NUMBER = 0
+ COLUMN_NEVRA = 1
+ COLUMN_GROUP = 2
+ COLUMN_REASON = 3
+ COLUMN_STATUS = 4
+
+ def __init__(self):
+ Gtk.Window.__init__(self, title='YumDB Reason Editor')
+ self.set_default_size(800, 600)
+
+ self.vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
+
+ self.pkg_store = Gtk.ListStore(int, str, str, str, str)
+ self.pkg_list = PkgList(self.pkg_store)
+ self.pkg_list.add_column('#', 0)
+ self.pkg_list.add_column('Name-Version-Arch', 1)
+ self.pkg_list.add_column('Group', 2)
+ self.pkg_list.add_column('Reason', 3)
+ self.pkg_list.add_column('Status', 4)
+ self.pkg_list.set_enable_search(False)
+ self.pkg_list.set_search_column(self.COLUMN_NEVRA)
+ self.pkg_list.connect('row-activated', self.toggle_reason)
+
+ self.pkg_scrollable = Gtk.ScrolledWindow()
+ self.pkg_scrollable.add(self.pkg_list)
+
+ self.count_label = Gtk.Label()
+
+ self.bottom_buttons = Gtk.Box()
+ self.reload_db = Gtk.Button.new_with_mnemonic(label='_Reload YumDB')
+ self.reload_db.connect('clicked', self.load_database)
+ self.show_info = Gtk.Button.new_with_mnemonic(label='_Info')
+ self.show_info.connect('clicked', self.show_summary_description)
+ self.enable_search = Gtk.ToggleButton('_Search Disabled')
+ self.enable_search.connect('toggled', self.toggle_search)
+ self.enable_search.set_use_underline(True)
+ self.bottom_buttons.pack_start(self.reload_db, True, True, 0)
+ self.bottom_buttons.pack_start(self.show_info, True, True, 0)
+ self.bottom_buttons.pack_start(self.enable_search, True, True, 0)
+
+ self.vbox.pack_start(self.pkg_scrollable, True, True, 0)
+ self.vbox.pack_start(self.count_label, False, False, 0)
+ self.vbox.pack_start(self.bottom_buttons, False, False, 0)
+ self.add(self.vbox)
+ self.show_all()
+
+ self.load_database()
+
+ def load_database(self, unused=None):
+ self.yumdb = YumDB()
+ self.pkg_store.clear()
+
+ print('Loading database ...')
+ data = self.yumdb.get_reasons()
+
+ print('Adding entries ...')
+ self.dep_count = 0
+ self.user_count = 0
+ for index, entry in enumerate(data):
+ self.pkg_store.append([ index + 1,
+ entry['nevra'], entry['group_member'],
+ entry['reason'], entry['reason_editor'] ])
+ if entry['reason'] == 'dep':
+ self.dep_count += 1
+ else:
+ self.user_count += 1
+
+ self.pkg_count = index + 1
+ self.update_count()
+ self.show_all()
+
+ def update_count(self):
+ self.count_label.set_label('{} dep, {} user, {} pkgs'.format(
+ self.dep_count, self.user_count, self.pkg_count))
+
+ def toggle_search(self, unused=None):
+ if self.enable_search.get_active():
+ self.enable_search.set_label('_Search Enabled')
+ self.pkg_list.set_enable_search(True)
+ else:
+ self.enable_search.set_label('_Search Disabled')
+ self.pkg_list.set_enable_search(False)
+
+ def toggle_reason(self, path, column, unused=None):
+ model = self.pkg_list.get_model()
+ tree_path = self.pkg_list.get_cursor()[0]
+ if tree_path == None:
+ return
+
+ tree_iter = model.get_iter(tree_path)
+ if tree_iter == None:
+ return
+
+ nevra = model[tree_iter][self.COLUMN_NEVRA]
+ is_dep = model[tree_iter][self.COLUMN_REASON] == 'dep'
+
+ result = self.yumdb.set_reason(nevra, 'user' if is_dep else 'dep')
+ if result != True:
+ error_dialog = Gtk.MessageDialog(
+ title='YumDB Error',
+ buttons=Gtk.ButtonsType.CLOSE,
+ message_type=Gtk.MessageType.ERROR,
+ message_format=result)
+ error_dialog.run()
+ error_dialog.destroy()
+ return
+
+ new_entry = self.yumdb.get_reasons([ nevra ])[0]
+ model[tree_iter][self.COLUMN_REASON] = new_entry['reason']
+ model[tree_iter][self.COLUMN_STATUS] = new_entry['reason_editor']
+ tree_path.next()
+ self.pkg_list.set_cursor(tree_path)
+ if is_dep:
+ self.dep_count -= 1
+ self.user_count += 1
+ else:
+ self.dep_count += 1
+ self.user_count -= 1
+ self.update_count()
+
+ def show_summary_description(self, unused=None):
+ model, tree_iter = self.pkg_list.get_selection().get_selected()
+ if tree_iter == None:
+ return
+ nevra = model[tree_iter][1]
+
+ dialog = Gtk.MessageDialog(
+ title=nevra,
+ buttons=Gtk.ButtonsType.CLOSE,
+ message_type=Gtk.MessageType.INFO,
+ message_format=None)
+ dialog.set_markup('<big><b>{}</b></big>\n\n{}'.format(
+ self.yumdb.get_summary(nevra),
+ self.yumdb.get_description(nevra)))
+ dialog.run()
+ dialog.destroy()
+
+
+if __name__ == '__main__':
+ editor = ReasonEditor()
+ editor.connect('delete-event', Gtk.main_quit)
+ Gtk.main()
diff --git a/char/test-wchar.c b/char/test-wchar.c
new file mode 100644
index 0000000..ab37604
--- /dev/null
+++ b/char/test-wchar.c
@@ -0,0 +1,31 @@
+#define _POSIX_C_SOURCE 200809L
+#define _XOPEN_SOURCE 700
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <wchar.h>
+
+int main () {
+ setlocale (LC_ALL, "");
+
+ char *line = NULL;
+ ssize_t str_len = getline (&line, &(size_t){ 0 }, stdin);
+
+ mbstate_t mbs;
+ wchar_t wc;
+ size_t mbrlen_result;
+ int wcwidth_result;
+
+ memset (&mbs, 0, sizeof (mbs));
+ mbrlen_result = mbrlen (line, str_len, &mbs);
+
+ memset (&mbs, 0, sizeof (mbs));
+ mbrtowc (&wc, line, str_len, &mbs);
+ wcwidth_result = wcwidth (wc);
+
+ printf ("mbrlen = %zu, wcwidth = %d\n", mbrlen_result, wcwidth_result);
+ free (line);
+ return 0;
+}
diff --git a/desktop/empathy-xml2txt.py b/desktop/empathy-xml2txt.py
new file mode 100755
index 0000000..9c6a7a0
--- /dev/null
+++ b/desktop/empathy-xml2txt.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python2
+# -*- coding: utf-8 -*-
+
+import sys
+from lxml import etree
+
+def empathy_xml2txt(infile, outfile):
+ xmlparser = etree.XMLParser(encoding = 'UTF-8')
+ xmltree = etree.parse(infile, xmlparser)
+ xmlroot = xmltree.getroot()
+ for msg in xmlroot.iter():
+ if msg.tag == "message":
+ outfile.write("{} <{:^12}> {}\n".format(
+ msg.get('time').replace('T', ' '),
+ msg.get('id'),
+ msg.text.encode('UTF-8')))
+
+if __name__ == "__main__":
+ for i in sys.argv[1:]:
+ empathy_xml2txt(i, sys.stdout)
diff --git a/desktop/gen-ms-inet-shortcut.sh b/desktop/gen-ms-inet-shortcut.sh
new file mode 100755
index 0000000..0e6aeea
--- /dev/null
+++ b/desktop/gen-ms-inet-shortcut.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+[ "$#" != "2" ] && {
+ echo "$0: Need 2 arguments"
+ echo "Usage: $0 filename url"
+} && exit 1
+
+{
+ echo "[InternetShortcut]"
+ echo "URL=$2"
+} > "$1"
diff --git a/desktop/webkit1-gtk-user-agent.py b/desktop/webkit1-gtk-user-agent.py
new file mode 100755
index 0000000..9ea72ba
--- /dev/null
+++ b/desktop/webkit1-gtk-user-agent.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+from gi.repository import WebKit
+
+version = '{}.{}.{}'.format(
+ WebKit.major_version(),
+ WebKit.minor_version(),
+ WebKit.micro_version())
+user_agent = WebKit.WebView().get_settings().get_user_agent()
+
+print('version = {}, user-agent = {}'.format(version, user_agent))
diff --git a/desktop/webkit2-gtk-user-agent.py b/desktop/webkit2-gtk-user-agent.py
new file mode 100755
index 0000000..1af74e4
--- /dev/null
+++ b/desktop/webkit2-gtk-user-agent.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+from gi.repository import WebKit2
+
+version = '{}.{}.{}'.format(
+ WebKit2.get_major_version(),
+ WebKit2.get_minor_version(),
+ WebKit2.get_micro_version())
+user_agent = WebKit2.WebView().get_settings().get_user_agent()
+
+print('version = {}, user-agent = {}'.format(version, user_agent))
diff --git a/download/flickr-download-public.py b/download/flickr-download-public.py
new file mode 100755
index 0000000..91fbeef
--- /dev/null
+++ b/download/flickr-download-public.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+
+flickr_api_key = 'e65a9f9957d8f6ae7490072452c0a345'
+flickr_group_id = '<Insert your flickr group ID here>'
+
+def flickr_url(page):
+ return '{}?api_key={}&method={}&group_id={}&extras={}&page={}&per_page={}'.format(
+ 'https://api.flickr.com/services/rest/',
+ flickr_api_key, 'flickr.photos.search',
+ flickr_group_id, 'url_o', page, 500)
+
+
+import os
+import urllib.request
+from xml.etree import ElementTree
+
+def flickr_request(page):
+ url = flickr_url(page)
+ print('Retrieving information from page {} ...'.format(page), end='', flush=True)
+ info = urllib.request.urlopen(url)
+ print(' done')
+ return info.readall()
+
+def flickr_download(url):
+ fname = os.path.basename(urllib.parse.urlsplit(url).path)
+ try:
+ f = open(fname, 'xb')
+ except FileExistsError:
+ print('Skipping {}'.format(url))
+ return
+
+ print('Downloading {} ...'.format(url), end='', flush=True)
+ data = urllib.request.urlopen(url).readall()
+ print(' done')
+ f.write(data)
+ f.close()
+
+info = ElementTree.fromstring(flickr_request(1))
+pages = int(info.find('photos').get('pages'))
+photos = int(info.find('photos').get('total'))
+print('There are {} photos ({} pages)'.format(photos, pages))
+
+count = 0
+for page in range(1, pages + 1):
+ info = ElementTree.fromstring(flickr_request(page))
+ for node in info.iter():
+ if node.tag == 'photo':
+ count = count + 1
+ print('[{}/{}] '.format(count, photos), end='', flush=True)
+ url = node.get('url_o')
+ flickr_download(url)
diff --git a/image/set-time-from-exif-info.sh b/image/set-time-from-exif-info.sh
new file mode 100755
index 0000000..bd50997
--- /dev/null
+++ b/image/set-time-from-exif-info.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+filter_exiftool_output () {
+ exiftool -d '%Y%m%d%H%M.%S' "$1" | grep "$2" | tail -n 1 | awk '{print $4}'
+}
+
+count=0
+for i in *; do
+ count=$(( $count + 1 ))
+ printf "%4d: Touching %s ..." "$count" "$i"
+ datetime="`filter_exiftool_output "$i" '^Date/Time'`"
+ : ${datetime:="`filter_exiftool_output "$i" '^Create Date'`"}
+ : ${datetime:="`filter_exiftool_output "$i" '^Create'`"}
+ : ${datetime:="`filter_exiftool_output "$i" '^Modify'`"}
+ printf " %s\n" "$datetime"
+ touch -t "$datetime" "$i"
+done
diff --git a/network/in_addr-show.c b/network/in_addr-show.c
new file mode 100644
index 0000000..e8dd01b
--- /dev/null
+++ b/network/in_addr-show.c
@@ -0,0 +1,23 @@
+#include <arpa/inet.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+int main (int argc, char *argv[]) {
+ char ipstr[INET_ADDRSTRLEN];
+ unsigned long ipbin;
+
+ for (int i = 1; i < argc; i++) {
+ if (sscanf (argv[i], "%lx", &ipbin) <= 0) {
+ return 1;
+ }
+ struct in_addr ipaddr = { .s_addr = ipbin };
+ if (inet_ntop (AF_INET, &ipaddr, ipstr, INET_ADDRSTRLEN) == NULL) {
+ return 2;
+ }
+ puts (ipstr);
+ }
+
+ return 0;
+}
diff --git a/network/unescape.js b/network/unescape.js
new file mode 100755
index 0000000..fadca7b
--- /dev/null
+++ b/network/unescape.js
@@ -0,0 +1,18 @@
+#!/usr/bin/env seed
+
+const Gio = imports.gi.Gio;
+
+var path = '/dev/stdin';
+if (Seed.argv.length >= 3) {
+ path = Seed.argv[2];
+}
+
+var file = Gio.file_new_for_path(path);
+var istream = new Gio.DataInputStream.c_new(file.read());
+
+var line;
+while ((line = istream.read_line_utf8()) != undefined) {
+ print(unescape(line.replace(/\+/g, ' ')));
+}
+
+istream.close();
diff --git a/package/check-update-chromium.py b/package/check-update-chromium.py
new file mode 100755
index 0000000..74942c5
--- /dev/null
+++ b/package/check-update-chromium.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+
+from pkg_resources import parse_version
+import json
+import urllib.request
+
+
+def get_upstream_version():
+ url = 'http://omahaproxy.appspot.com/all?os=linux&channel=stable'
+ data = urllib.request.urlopen(url).readall()
+ return data.split(b'\n')[1].split(b',')[2].decode()
+
+def get_package_version_cgit():
+ cgit_plain_url = 'http://phantom.tfcis.org/~lantw44/cgit/copr-rpm-spec/plain/chromium/chromium/chromium.spec'
+ spec = urllib.request.urlopen(cgit_plain_url).readall().decode()
+ return spec.split('\nVersion:')[1].split()[0]
+
+def get_package_version_copr():
+ copr_api_url = 'https://copr.fedoraproject.org/api'
+ url = copr_api_url + '/coprs/lantw44/chromium/monitor/'
+ data = json.loads(urllib.request.urlopen(url).readall().decode())
+ for pkg in data['packages']:
+ if pkg['pkg_name'] == 'chromium':
+ return pkg['pkg_version']
+
+get_package_version = get_package_version_copr
+latest = get_upstream_version()
+current = get_package_version()
+
+import sys
+if len(sys.argv) >= 2:
+ print('>>> latest = {}, packaged = {}'.format(latest, current))
+
+if parse_version(current) < parse_version(latest):
+ print('Please update the chromium package!')
+ print('>>> latest = {}, packaged = {}'.format(latest, current))
diff --git a/system/get-login.c b/system/get-login.c
new file mode 100644
index 0000000..a73514a
--- /dev/null
+++ b/system/get-login.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <unistd.h>
+
+int main () {
+ printf ("getlogin() = %s\n", getlogin());
+ return 0;
+}
diff --git a/system/set-login.c b/system/set-login.c
new file mode 100644
index 0000000..d00ad51
--- /dev/null
+++ b/system/set-login.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+#include <unistd.h>
+
+int main (int argc, char* argv[]) {
+ if (argc < 2){
+ fprintf (stderr, "One Argument required.\n");
+ return 1;
+ }
+ printf ("setlogin(%s)\n", argv[1]);
+ if (setlogin (argv[1]) < 0){
+ perror("setlogin");
+ return 2;
+ }
+ return 0;
+}
diff --git a/system/test-libacl.c b/system/test-libacl.c
new file mode 100644
index 0000000..27ccc5a
--- /dev/null
+++ b/system/test-libacl.c
@@ -0,0 +1,469 @@
+#ifdef __FreeBSD__
+# define _WITH_GETLINE
+#else
+# define _POSIX_C_SOURCE 200809L
+# define _XOPEN_SOURCE 700
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <grp.h>
+#include <locale.h>
+#include <pwd.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <unistd.h>
+
+// Needed to access non-portable functions on Linux
+#ifdef __SYS_ACL_H
+# include <acl/libacl.h>
+#endif
+
+typedef enum {
+ CMD_MODIFY_ACTION_EDIT,
+ CMD_MODIFY_ACTION_DELETE,
+ CMD_MODIFY_ACTION_LAST,
+} CmdModifyAction;
+
+
+static void print_function_result (bool success, const char* function){
+ if (success) {
+ printf ("\033[1;32m%s\033[0m: OK\n", function);
+ } else {
+ printf ("\033[1;31m%s\033[0m: %s\n", function, strerror (errno));
+ }
+}
+
+static bool check_error_int (int rval, const char* function) {
+ if (rval < 0){
+ print_function_result (false, function);
+ return true;
+ } else {
+ print_function_result (true, function);
+ return false;
+ }
+}
+
+static bool check_error_ptr (void* rval, const char* function) {
+ if (rval == NULL) {
+ print_function_result (false, function);
+ return true;
+ } else {
+ print_function_result (true, function);
+ return false;
+ }
+}
+
+static const char* read_input (const char* prompt) {
+ static char* buffer_ptr = NULL;
+ static size_t buffer_len = 0;
+
+ clearerr (stdin);
+ fputs (prompt, stdout);
+ fflush (stdout);
+
+ ssize_t str_len = getline (&buffer_ptr, &buffer_len, stdin);
+ if (str_len < 0) {
+ free (buffer_ptr);
+ buffer_ptr = NULL;
+ buffer_len = 0;
+ return "";
+ }
+
+ buffer_ptr[str_len - 1] = '\0';
+ return buffer_ptr;
+}
+
+static acl_type_t read_acl_type (void) {
+#define READ_ACL_TYPE_INVALID (-1)
+ static_assert (ACL_TYPE_ACCESS != READ_ACL_TYPE_INVALID, "ACL_TYPE_ACCESS == READ_ACL_TYPE_INVALID");
+ static_assert (ACL_TYPE_DEFAULT != READ_ACL_TYPE_INVALID, "ACL_TYPE_DEFAULT == READ_ACL_TYPE_INVALID");
+#ifdef ACL_TYPE_NFS4
+ static_assert (ACL_TYPE_NFS4 != READ_ACL_TYPE_INVALID, "ACL_TYPE_NFS4 == READ_ACL_TYPE_INVALID");
+ const char* input = read_input ("Mode [1=access 2=default 3=nfsv4]: ");
+#else
+ const char* input = read_input ("Mode [1=access 2=default]: ");
+#endif
+
+ switch (input[0]) {
+ case '1':
+ return ACL_TYPE_ACCESS;
+ case '2':
+ return ACL_TYPE_DEFAULT;
+#ifdef ACL_TYPE_NFS4
+ case '3':
+ return ACL_TYPE_NFS4;
+#endif
+ default:
+ return READ_ACL_TYPE_INVALID;
+ }
+
+ return READ_ACL_TYPE_INVALID;
+}
+
+static void entry_display (acl_entry_t entry, unsigned int count) {
+ acl_tag_t tag;
+ acl_permset_t permset;
+
+ void* qualifier_ptr;
+ uid_t* uid_ptr;
+ gid_t* gid_ptr;
+
+ if (check_error_int (acl_get_tag_type (entry, &tag), "acl_get_tag_type")) {
+ return;
+ }
+ if (tag == ACL_USER || tag == ACL_GROUP) {
+ if (check_error_ptr (qualifier_ptr = acl_get_qualifier (entry), "acl_get_qualifier")) {
+ return;
+ }
+ }
+ if (check_error_int (acl_get_permset (entry, &permset), "acl_get_permset")) {
+ return;
+ }
+
+ printf ("%u: ", count);
+ switch (tag) {
+ case ACL_USER:
+ case ACL_USER_OBJ:
+ putchar ('u');
+ break;
+ case ACL_GROUP:
+ case ACL_GROUP_OBJ:
+ putchar ('g');
+ break;
+ case ACL_OTHER:
+ putchar ('o');
+ break;
+ case ACL_MASK:
+ putchar ('m');
+ }
+ putchar (':');
+
+ if (tag == ACL_USER) {
+ struct passwd* pwd;
+ uid_ptr = qualifier_ptr;
+ errno = 0;
+ if ((pwd = getpwuid (*uid_ptr)) == NULL) {
+ printf ("\033[1;31m%lu\033[0m", (unsigned long)*uid_ptr);
+ } else {
+ printf ("%s(%lu)", pwd->pw_name, (unsigned long)*uid_ptr);
+ }
+ } else if (tag == ACL_GROUP) {
+ struct group* grp;
+ gid_ptr = qualifier_ptr;
+ errno = 0;
+ if ((grp = getgrgid (*gid_ptr)) == NULL) {
+ printf ("\033[1;31m%lu\033[0m", (unsigned long)*gid_ptr);
+ } else {
+ printf ("%s(%lu)", grp->gr_name, (unsigned long)*gid_ptr);
+ }
+ }
+ putchar (':');
+
+#ifdef _SYS_ACL_H_ // TrustedBSD and FreeBSD
+ putchar (acl_get_perm_np (permset, ACL_READ) ? 'r' : '-');
+ putchar (acl_get_perm_np (permset, ACL_WRITE) ? 'w' : '-');
+ putchar (acl_get_perm_np (permset, ACL_EXECUTE) ? 'x' : '-');
+#elif defined(__SYS_ACL_H) // Linux and possibly Hurd or other GNU systems
+ putchar (acl_get_perm (permset, ACL_READ) ? 'r' : '-');
+ putchar (acl_get_perm (permset, ACL_WRITE) ? 'w' : '-');
+ putchar (acl_get_perm (permset, ACL_EXECUTE) ? 'x' : '-');
+#else
+# error "Sorry, your operating system is not supported."
+#endif
+}
+
+static void entry_edit(acl_entry_t* entry){
+ acl_tag_t tag;
+ const char* input;
+
+ input = read_input ("Tag [u g uo go o m]: ");
+ switch (input[0]) {
+ case 'u':
+ switch (input[1]) {
+ case '\0':
+ tag = ACL_USER;
+ break;
+ case 'o':
+ tag = ACL_USER_OBJ;
+ break;
+ default:
+ return;
+ }
+ break;
+ case 'g':
+ switch (input[1]){
+ case '\0':
+ tag = ACL_GROUP;
+ break;
+ case 'o':
+ tag = ACL_GROUP_OBJ;
+ break;
+ default:
+ return;
+ }
+ break;
+ case 'o':
+ tag = ACL_OTHER;
+ break;
+ case 'm':
+ tag = ACL_MASK;
+ break;
+ default:
+ return;
+ }
+
+ if (check_error_int (acl_set_tag_type (*entry, tag), "acl_set_tag_type")) {
+ return;
+ }
+
+ if (tag == ACL_USER) {
+ input = read_input ("User [user name or #uid]: ");
+ uid_t uid;
+ if (input[0] == '#') {
+ uid = (uid_t)atol (&input[1]);
+ } else {
+ struct passwd* pwd;
+ errno = 0;
+ if (check_error_ptr (pwd = getpwnam (input), "getpwnam")) {
+ return;
+ }
+ uid = pwd->pw_uid;
+ }
+ if (check_error_int (acl_set_qualifier (*entry, &uid), "acl_set_qualifier")) {
+ return;
+ }
+ } else if (tag == ACL_GROUP) {
+ input = read_input ("Group [group name or #gid]: ");
+ gid_t gid;
+ if (input[0] == '#') {
+ gid = (gid_t)atol (&input[1]);
+ } else {
+ struct group* grp;
+ errno = 0;
+ if (check_error_ptr (grp = getgrnam (input), "getgrnam")) {
+ return;
+ }
+ gid = grp->gr_gid;
+ }
+ if (check_error_int (acl_set_qualifier (*entry, &gid), "acl_set_qualifier")) {
+ return;
+ }
+ }
+
+ input = read_input ("Permission: ");
+ size_t len = strlen (input);
+
+ acl_permset_t permset;
+ if (check_error_int (acl_get_permset (*entry, &permset), "acl_get_permset")) {
+ return;
+ }
+ if (check_error_int (acl_clear_perms (permset), "acl_clear_perms")) {
+ return;
+ }
+ for (size_t i = 0; i < len; i++) {
+ switch (input[i]) {
+ case 'r':
+ if (check_error_int (acl_add_perm (permset, ACL_READ), "acl_add_perm")) {
+ return;
+ }
+ break;
+ case 'w':
+ if (check_error_int (acl_add_perm (permset, ACL_WRITE), "acl_add_perm")) {
+ return;
+ }
+ break;
+ case 'x':
+ if (check_error_int (acl_add_perm (permset, ACL_EXECUTE), "acl_add_perm")) {
+ return;
+ }
+ }
+ }
+}
+
+static void cmd_add (acl_t* alist) {
+ acl_entry_t entry;
+
+ if (check_error_int (acl_create_entry (alist, &entry), "acl_create_entry")) {
+ return;
+ }
+ entry_edit (&entry);
+}
+
+static void cmd_modify (const acl_t* alist, CmdModifyAction action) {
+ acl_entry_t entry;
+ int rval = acl_get_entry (*alist, ACL_FIRST_ENTRY, &entry);
+ unsigned int count = 0;
+
+ do {
+ count++;
+ switch (rval) {
+ case 1:
+ check_error_int (rval, "acl_get_entry");
+ break;
+ case 0:
+ return;
+ case -1:
+ check_error_int (rval, "acl_get_entry");
+ return;
+ }
+
+ entry_display (entry, count);
+ putchar(' ');
+
+ switch (action) {
+ case CMD_MODIFY_ACTION_DELETE: {
+ const char* input = read_input ("Delete [y/n/q]? ");
+ switch (input[0]) {
+ case 'q':
+ return;
+ case 'y':
+ check_error_int (acl_delete_entry (*alist, entry), "acl_delete_entry");
+ }
+ } break;
+
+ case CMD_MODIFY_ACTION_EDIT: {
+ const char* input = read_input ("Edit [y/n/q]? ");
+ switch (input[0]) {
+ case 'q':
+ return;
+ case 'y':
+ entry_edit (&entry);
+ }
+ } break;
+
+ default:
+ puts ("This should never happen");
+ return;
+ }
+ } while ((rval = acl_get_entry (*alist, ACL_NEXT_ENTRY, &entry)) == 1);
+}
+
+static void cmd_read (acl_t* alist){
+ acl_t alist_new;
+
+ char* name = strdup (read_input ("File name= "));
+ acl_type_t type = read_acl_type ();
+
+ if (type == READ_ACL_TYPE_INVALID) {
+ free (name);
+ return;
+ }
+
+ if (!check_error_ptr (alist_new = acl_get_file (name, type), "acl_get_file")) {
+ check_error_int (acl_free (*alist), "acl_free");
+ *alist = alist_new;
+ }
+ free (name);
+}
+
+static void cmd_write(const acl_t* alist){
+ char* name = strdup (read_input ("File name= "));
+ acl_type_t type = read_acl_type ();
+
+ if (type == READ_ACL_TYPE_INVALID) {
+ free (name);
+ return;
+ }
+
+ check_error_int (acl_set_file (name, type, *alist), "acl_set_file");
+ free (name);
+}
+
+static void cmd_zzz (void){
+ const char* name = read_input ("File name= ");
+ check_error_int (acl_delete_def_file (name), "acl_delete_def_file");
+}
+
+int main (int argc, char* argv[]) {
+ setlocale (LC_ALL, "");
+
+ acl_t alist;
+
+ if (check_error_ptr (alist = acl_init (4), "acl_init")) {
+ return 1;
+ }
+
+ while (true) {
+ const char* input = read_input ("\033[1;33macl>\033[0m ");
+
+ if (feof (stdin)) {
+ goto loop_end;
+ }
+
+ switch (input[0]) {
+ case 'a':
+ cmd_add (&alist);
+ break;
+ case 'c':
+ check_error_int (acl_calc_mask (&alist), "acl_calc_mask");
+ break;
+ case 'd':
+ cmd_modify (&alist, CMD_MODIFY_ACTION_DELETE);
+ break;
+ case 'e':
+ cmd_modify (&alist, CMD_MODIFY_ACTION_EDIT);
+ break;
+ case 'i': {
+ acl_t alist_new;
+ int count;
+ input = read_input ("Count= ");
+ count = atoi (input);
+ if (!check_error_ptr (alist_new = acl_init (count), "acl_init")) {
+ check_error_int (acl_free (alist), "acl_free");
+ alist = alist_new;
+ }
+ } break;
+ case 'p': {
+ char* atext;
+ if (!check_error_ptr (atext = acl_to_text (alist, NULL), "acl_to_text")) {
+ fputs (atext, stdout);
+ if (atext[strlen (atext) - 1] != '\n') {
+ putchar ('\n');
+ }
+ check_error_int (acl_free (atext), "acl_free");
+ }
+ } break;
+ case 'q':
+ goto loop_end;
+ case 'r':
+ cmd_read (&alist);
+ break;
+ case 'v':
+ if (acl_valid (alist) == 0) {
+ puts ("Current ACL structure is \033[1;32mvalid\033[0m.");
+ } else {
+ puts ("Current ACL structure is \033[1;31minvalid\033[0m.");
+ }
+ break;
+ case 'w':
+ cmd_write (&alist);
+ break;
+ case 'z':
+ cmd_zzz ();
+ break;
+ default:
+ fputs (
+ " a Add an ACL entry\n"
+ " c Automatically generate the mask value\n"
+ " d Delete ACL entries\n"
+ " e Edit ACL entries\n"
+ " i Clear and initialize an empty ACL structure\n"
+ " p Print current ACL structure\n"
+ " q Quit this program\n"
+ " r Read ACL structure from file\n"
+ " v Verify current ACL\n"
+ " w Write ACL structure to file\n"
+ " z Delete default ACL entries from file\n"
+ , stdout);
+ }
+ }
+
+loop_end:
+ check_error_int (acl_free (alist), "acl_free");
+ return 0;
+}
diff --git a/system/test-libcap.c b/system/test-libcap.c
new file mode 100644
index 0000000..806795e
--- /dev/null
+++ b/system/test-libcap.c
@@ -0,0 +1,206 @@
+#define _POSIX_C_SOURCE 200809L
+#define _XOPEN_SOURCE 700
+
+#include <ctype.h>
+#include <errno.h>
+#include <locale.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/capability.h>
+
+static void print_function_result (bool success, const char* function){
+ if (success) {
+ printf ("\033[1;32m%s\033[0m: OK\n", function);
+ } else {
+ printf ("\033[1;31m%s\033[0m: %s\n", function, strerror (errno));
+ }
+}
+
+static bool check_error_int (int rval, const char* function) {
+ if (rval < 0){
+ print_function_result (false, function);
+ return true;
+ } else {
+ print_function_result (true, function);
+ return false;
+ }
+}
+
+static bool check_error_ptr (void* rval, const char* function) {
+ if (rval == NULL) {
+ print_function_result (false, function);
+ return true;
+ } else {
+ print_function_result (true, function);
+ return false;
+ }
+}
+
+static const char* read_input (const char* prompt) {
+ static char* buffer_ptr = NULL;
+ static size_t buffer_len = 0;
+
+ clearerr (stdin);
+ fputs (prompt, stdout);
+ fflush (stdout);
+
+ ssize_t str_len = getline (&buffer_ptr, &buffer_len, stdin);
+ if (str_len < 0) {
+ free (buffer_ptr);
+ buffer_ptr = NULL;
+ buffer_len = 0;
+ return "";
+ }
+
+ buffer_ptr[str_len - 1] = '\0';
+ return buffer_ptr;
+}
+
+int main (int argc, char* argv[]) {
+ setlocale (LC_ALL, "");
+
+ cap_t store = NULL;
+
+ while (true) {
+ const char* input = read_input ("\033[1;33mcap>\033[m ");
+
+ if (feof (stdin)) {
+ goto loop_end;
+ }
+
+ switch (input[0]){
+ case 'c': {
+ cap_flag_t flag;
+ input = read_input ("[E]ffective [P]ermitted [I]nheritable ? ");
+ switch (toupper (input[0])) {
+ case 'E':
+ flag = CAP_EFFECTIVE;
+ break;
+ case 'P':
+ flag = CAP_PERMITTED;
+ break;
+ case 'I':
+ flag = CAP_INHERITABLE;
+ break;
+ default:
+ continue;
+ }
+ check_error_int (cap_clear_flag (store, flag), "cap_clear_flag");
+ } break;
+ case 'e': {
+ cap_flag_t flag;
+ input = read_input ("[E]ffective [P]ermitted [I]nheritable ? ");
+ switch (toupper (input[0])) {
+ case 'E':
+ flag = CAP_EFFECTIVE;
+ break;
+ case 'P':
+ flag = CAP_PERMITTED;
+ break;
+ case 'I':
+ flag = CAP_INHERITABLE;
+ break;
+ default:
+ continue;
+ }
+
+ cap_value_t value;
+ input = read_input ("Capability= ");
+ if (check_error_int (cap_from_name (input, &value), "cap_from_name")) {
+ break;
+ }
+
+ cap_flag_value_t flag_value;
+ input = read_input ("[C]lear [S]et ? ");
+ switch (toupper (input[0])) {
+ case 'C':
+ case 'R':
+ case '0':
+ flag_value = CAP_CLEAR;
+ break;
+ case 'S':
+ case '1':
+ flag_value = CAP_SET;
+ break;
+ }
+
+ check_error_int (
+ cap_set_flag (store, flag, 1, &value, flag_value),
+ "cap_set_flag");
+ } break;
+ case 'i':
+ if (store != NULL) {
+ check_error_int (cap_free (store), "cap_free");
+ store = NULL;
+ }
+ check_error_ptr (store = cap_init (), "cap_init");
+ break;
+ case 'f':
+ if (store == NULL) {
+ break;
+ }
+ check_error_int (cap_free (store), "cap_free");
+ store = NULL;
+ break;
+ case 'r':
+ if (store != NULL){
+ check_error_int (cap_free(store), "cap_free");
+ store = NULL;
+ }
+ input = read_input ("[P]rocess [F]ile ? ");
+ switch(toupper (input[0])){
+ case 'P':
+ case '1':
+ input = read_input ("PID= ");
+ check_error_ptr (
+ store = cap_get_pid ((pid_t)atol (input)),
+ "cap_get_pid");
+ break;
+ case 'F':
+ case '2':
+ input = read_input ("File= ");
+ check_error_ptr (
+ store = cap_get_file (input),
+ "cap_set_file");
+ break;
+ }
+ break;
+ case 'w':
+ if (store != NULL) {
+ input = read_input ("File= ");
+ check_error_int (cap_set_file (input, store), "cap_set_file");
+ }
+ break;
+ case 'p': {
+ char *ctext;
+ if (store == NULL) {
+ break;
+ }
+ check_error_ptr (ctext = cap_to_text (store, NULL), "cap_to_text");
+ if (ctext != NULL) {
+ puts (ctext);
+ check_error_int (cap_free (ctext), "cap_free");
+ }
+ } break;
+ default:
+ fputs (
+ " c\tClear a capability set\n"
+ " e\tEdit the capability data structure\n"
+ " f\tFree the capability data structure\n"
+ " i\tClear and Initialize a new capability\n"
+ " p\tPrint the current capability\n"
+ " r\tRead and Replace the capability\n"
+ " w\tSet the current capability to a process or a file\n",
+ stdout);
+ }
+ }
+
+loop_end:
+ if (store != NULL) {
+ check_error_int (cap_free (store), "cap_free");
+ store = NULL;
+ }
+ return 0;
+}