commit c534ea1c7906a3de3b9ab1aa18e30b9129494f82 Author: Michael Wesemann Date: Mon Aug 10 16:12:09 2026 +0200 initial commit [141.14.140.180,mike] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3a5465c --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +.DS_Store +.AppleDouble +.LSOverride +._* +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.mgshrc diff --git a/README b/README new file mode 100644 index 0000000..7e4853f --- /dev/null +++ b/README @@ -0,0 +1,46 @@ + +-------------------- Debian 10/11/12 -------------------- +# su - +# apt install git; git clone https://git.fhi.mpg.de/mike/linuxsetup +# cd ~/linuxsetup; ./setup.ssh +relogin as root +# cd ~/linuxsetup; ./setup.debian1x +# cd ~/linuxsetup; ./telemetry.setup + +-------------------- Raspberry Pi OS -------------------- +# sudo passwd root +# su - +# apt install git; git clone https://git.fhi.mpg.de/mike/linuxsetup +# cd ~/linuxsetup; ./setup.ssh +relogin as root +# cd ~/linuxsetup; ./setup.debian1x +# cd ~/linuxsetup; ./telemetry.setup + +-------------------- Ubuntu 18/20/22 -------------------- +# sudo passwd root +# su - +# git clone https://git.fhi.mpg.de/mike/linuxsetup +# cd ~/linuxsetup; ./setup.ssh +relogin as root +# cd ~/linuxsetup; ./setup.ubuntu2x +# cd ~/linuxsetup; ./telemetry.setup + +-------------------- restic backup -------------------- +decrypt restic conf (password: quo...): +# openssl enc -a -d -aes-256-cbc -salt -pbkdf2 -iter 1000000 -in restic.config.enc +# ./restic.setup +# rt backup +check crontab + +-------------------- mariadb -------------------- +# apt install mariadb-server +MariaDB> ALTER USER root@localhost IDENTIFIED VIA mysql_native_password USING PASSWORD("eizohphu"); +# mybackup -a +# myuser + +-------------------- go -------------------- +# wget https://go.dev/dl/go1.25.4.linux-arm64.tar.gz +# rm -rf /db/go && tar -C /db -xzf go1.25.4.linux-arm64.tar.gz +export PATH=/db/go/bin:$PATH +export CGO_ENABLED=0 + diff --git a/extra.setup b/extra.setup new file mode 100755 index 0000000..8bb6265 --- /dev/null +++ b/extra.setup @@ -0,0 +1,39 @@ +#!/usr/bin/perl +######################################################################################## extra setup (mwx'2025) +use Config; + +$HOME=$ENV{"HOME"}; + + + +if ($Config{archname}=~/^darwin/) { + if ($Config{myuname}=~/arm64/) { + system("brew install eza"); + } +} else { + system("./upd https://github.com/eza-community/eza -i /db/bin") + +} + +system("mkdir -p $HOME/.config"); +system("cp -r extra/config/eza $HOME/.config"); + +system("./upd https://github.com/sxyazi/yazi -i /db/bin") + + +system("mkdir -p $HOME/.config"); +system("cp -r extra/config/yazi $HOME/.config"); + + +system("curl -s https://ohmyposh.dev/install.sh | bash -s -- -d /db/bin"); +system("mkdir -p /db/etc"); +system("cp extra/omp.json /db/etc/"); + + +system("git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf"); +system("~/.fzf/install"); + +system("cp -r extra/zshrc $HOME/.zshrc"); + + +########################################################################################################### END diff --git a/extra/config/btop/btop.conf b/extra/config/btop/btop.conf new file mode 100644 index 0000000..0c431b9 --- /dev/null +++ b/extra/config/btop/btop.conf @@ -0,0 +1,218 @@ +#? Config file for btop v. 1.4.0 + +#* Name of a btop++/bpytop/bashtop formatted ".theme" file, "Default" and "TTY" for builtin themes. +#* Themes should be placed in "../share/btop/themes" relative to binary or "$HOME/.config/btop/themes" +color_theme = "Default" + +#* If the theme set background should be shown, set to False if you want terminal background transparency. +theme_background = False + +#* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false. +truecolor = True + +#* Set to true to force tty mode regardless if a real tty has been detected or not. +#* Will force 16-color mode and TTY theme, set all graph symbols to "tty" and swap out other non tty friendly symbols. +force_tty = False + +#* Define presets for the layout of the boxes. Preset 0 is always all boxes shown with default settings. Max 9 presets. +#* Format: "box_name:P:G,box_name:P:G" P=(0 or 1) for alternate positions, G=graph symbol to use for box. +#* Use whitespace " " as separator between different presets. +#* Example: "cpu:0:default,mem:0:tty,proc:1:default cpu:0:braille,proc:0:tty" +presets = "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:default cpu:0:block,net:0:tty" + +#* Set to True to enable "h,j,k,l,g,G" keys for directional control in lists. +#* Conflicting keys for h:"help" and k:"kill" is accessible while holding shift. +vim_keys = False + +#* Rounded corners on boxes, is ignored if TTY mode is ON. +rounded_corners = True + +#* Default symbols to use for graph creation, "braille", "block" or "tty". +#* "braille" offers the highest resolution but might not be included in all fonts. +#* "block" has half the resolution of braille but uses more common characters. +#* "tty" uses only 3 different symbols but will work with most fonts and should work in a real TTY. +#* Note that "tty" only has half the horizontal resolution of the other two, so will show a shorter historical view. +graph_symbol = "braille" + +# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". +graph_symbol_cpu = "default" + +# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". +graph_symbol_mem = "default" + +# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". +graph_symbol_net = "default" + +# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". +graph_symbol_proc = "default" + +#* Manually set which boxes to show. Available values are "cpu mem net proc" and "gpu0" through "gpu5", separate values with whitespace. +shown_boxes = "cpu mem net proc" + +#* Update time in milliseconds, recommended 2000 ms or above for better sample times for graphs. +update_ms = 500 + +#* Processes sorting, "pid" "program" "arguments" "threads" "user" "memory" "cpu lazy" "cpu direct", +#* "cpu lazy" sorts top process over time (easier to follow), "cpu direct" updates top process directly. +proc_sorting = "cpu lazy" + +#* Reverse sorting order, True or False. +proc_reversed = False + +#* Show processes as a tree. +proc_tree = False + +#* Use the cpu graph colors in the process list. +proc_colors = True + +#* Use a darkening gradient in the process list. +proc_gradient = True + +#* If process cpu usage should be of the core it's running on or usage of the total available cpu power. +proc_per_core = True + +#* Show process memory as bytes instead of percent. +proc_mem_bytes = True + +#* Show cpu graph for each process. +proc_cpu_graphs = True + +#* Use /proc/[pid]/smaps for memory information in the process info box (very slow but more accurate) +proc_info_smaps = False + +#* Show proc box on left side of screen instead of right. +proc_left = False + +#* (Linux) Filter processes tied to the Linux kernel(similar behavior to htop). +proc_filter_kernel = False + +#* In tree-view, always accumulate child process resources in the parent process. +proc_aggregate = False + +#* Sets the CPU stat shown in upper half of the CPU graph, "total" is always available. +#* Select from a list of detected attributes from the options menu. +cpu_graph_upper = "Auto" + +#* Sets the CPU stat shown in lower half of the CPU graph, "total" is always available. +#* Select from a list of detected attributes from the options menu. +cpu_graph_lower = "Auto" + +#* Toggles if the lower CPU graph should be inverted. +cpu_invert_lower = True + +#* Set to True to completely disable the lower CPU graph. +cpu_single_graph = False + +#* Show cpu box at bottom of screen instead of top. +cpu_bottom = False + +#* Shows the system uptime in the CPU box. +show_uptime = True + +#* Show cpu temperature. +check_temp = True + +#* Which sensor to use for cpu temperature, use options menu to select from list of available sensors. +cpu_sensor = "Auto" + +#* Show temperatures for cpu cores also if check_temp is True and sensors has been found. +show_coretemp = True + +#* Set a custom mapping between core and coretemp, can be needed on certain cpus to get correct temperature for correct core. +#* Use lm-sensors or similar to see which cores are reporting temperatures on your machine. +#* Format "x:y" x=core with wrong temp, y=core with correct temp, use space as separator between multiple entries. +#* Example: "4:0 5:1 6:3" +cpu_core_map = "" + +#* Which temperature scale to use, available values: "celsius", "fahrenheit", "kelvin" and "rankine". +temp_scale = "celsius" + +#* Use base 10 for bits/bytes sizes, KB = 1000 instead of KiB = 1024. +base_10_sizes = False + +#* Show CPU frequency. +show_cpu_freq = True + +#* Draw a clock at top of screen, formatting according to strftime, empty string to disable. +#* Special formatting: /host = hostname | /user = username | /uptime = system uptime +clock_format = "%X" + +#* Update main ui in background when menus are showing, set this to false if the menus is flickering too much for comfort. +background_update = True + +#* Custom cpu model name, empty string to disable. +custom_cpu_name = "" + +#* Optional filter for shown disks, should be full path of a mountpoint, separate multiple values with whitespace " ". +#* Begin line with "exclude=" to change to exclude filter, otherwise defaults to "most include" filter. Example: disks_filter="exclude=/boot /home/user". +disks_filter = "" + +#* Show graphs instead of meters for memory values. +mem_graphs = True + +#* Show mem box below net box instead of above. +mem_below_net = False + +#* Count ZFS ARC in cached and available memory. +zfs_arc_cached = True + +#* If swap memory should be shown in memory box. +show_swap = True + +#* Show swap as a disk, ignores show_swap value above, inserts itself after first disk. +swap_disk = True + +#* If mem box should be split to also show disks info. +show_disks = True + +#* Filter out non physical disks. Set this to False to include network disks, RAM disks and similar. +only_physical = True + +#* Read disks list from /etc/fstab. This also disables only_physical. +use_fstab = True + +#* Setting this to True will hide all datasets, and only show ZFS pools. (IO stats will be calculated per-pool) +zfs_hide_datasets = False + +#* Set to true to show available disk space for privileged users. +disk_free_priv = False + +#* Toggles if io activity % (disk busy time) should be shown in regular disk usage view. +show_io_stat = True + +#* Toggles io mode for disks, showing big graphs for disk read/write speeds. +io_mode = False + +#* Set to True to show combined read/write io graphs in io mode. +io_graph_combined = False + +#* Set the top speed for the io graphs in MiB/s (100 by default), use format "mountpoint:speed" separate disks with whitespace " ". +#* Example: "/mnt/media:100 /:20 /boot:1". +io_graph_speeds = "" + +#* Set fixed values for network graphs in Mebibits. Is only used if net_auto is also set to False. +net_download = 100 + +net_upload = 100 + +#* Use network graphs auto rescaling mode, ignores any values set above and rescales down to 10 Kibibytes at the lowest. +net_auto = False + +#* Sync the auto scaling for download and upload to whichever currently has the highest scale. +net_sync = False + +#* Starts with the Network Interface specified here. +net_iface = "" + +#* Show battery stats in top right if battery is present. +show_battery = True + +#* Which battery to use if multiple are present. "Auto" for auto detection. +selected_battery = "Auto" + +#* Show power stats of battery next to charge indicator. +show_battery_watts = True + +#* Set loglevel for "~/.config/btop/btop.log" levels are: "ERROR" "WARNING" "INFO" "DEBUG". +#* The level set includes all lower levels, i.e. "DEBUG" will show all logging info. +log_level = "WARNING" diff --git a/extra/config/eza/theme.yml b/extra/config/eza/theme.yml new file mode 100644 index 0000000..5787a96 --- /dev/null +++ b/extra/config/eza/theme.yml @@ -0,0 +1,123 @@ +# eza theme — Palette aus coltest.go +# +# white #F0F0EA pink #F5B2F7 +# yellow #F9E2AF violet #CBA6F7 +# orange #FAB387 grey #AAAABB +# red #F38BA8 dark #777788 +# green #94E2D5 darker #444455 +# blue #B4BEFE +# +# Ort: ~/.config/eza/theme.yml (oder $EZA_CONFIG_DIR/theme.yml) +# Getestet mit eza 0.23.5. + +colourful: true + +filekinds: + normal: {foreground: "#F0F0EA"} # white + directory: {foreground: "#B4BEFE", is_bold: true} # blue + symlink: {foreground: "#F5B2F7", is_underline: false} # pink + pipe: {foreground: "#CBA6F7"} # violet + block_device: {foreground: "#FAB387"} # orange + char_device: {foreground: "#F9E2AF"} # yellow + socket: {foreground: "#F5B2F7", is_bold: true} # pink + special: {foreground: "#CBA6F7"} # violet + executable: {foreground: "#94E2D5", is_bold: true} # green + mount_point: {foreground: "#B4BEFE", is_underline: false} + +perms: + user_read: {foreground: "#94E2D5"} # green + user_write: {foreground: "#F9E2AF"} # yellow + user_execute_file: {foreground: "#F38BA8", is_underline: false} # red + user_execute_other: {foreground: "#F38BA8", is_underline: false} # red + group_read: {foreground: "#94E2D5"} + group_write: {foreground: "#F9E2AF"} + group_execute: {foreground: "#F38BA8", is_underline: false} + other_read: {foreground: "#94E2D5"} + other_write: {foreground: "#F9E2AF"} + other_execute: {foreground: "#F38BA8", is_underline: false} + special_user_file: {foreground: "#F5B2F7", is_underline: false} # pink — setuid + special_other: {foreground: "#F5B2F7", is_underline: false} # pink + attribute: {foreground: "#777788"} # dark — @ / xattr + +size: + number_byte: {foreground: "#94E2D5"} # green + number_kilo: {foreground: "#94E2D5"} + number_mega: {foreground: "#F9E2AF"} # yellow + number_giga: {foreground: "#FAB387"} # orange + number_huge: {foreground: "#F38BA8"} # red + unit_byte: {foreground: "#94E2D5"} + unit_kilo: {foreground: "#94E2D5"} + unit_mega: {foreground: "#F9E2AF"} + unit_giga: {foreground: "#FAB387"} + unit_huge: {foreground: "#F38BA8"} + major: {foreground: "#CBA6F7"} # violet — Device-Nummern + minor: {foreground: "#F5B2F7"} # pink + +users: + user_you: {foreground: "#F0F0EA"} # white + user_root: {foreground: "#F38BA8"} # red + user_other: {foreground: "#AAAABB"} # grey + group_yours: {foreground: "#AAAABB"} # grey + group_other: {foreground: "#777788"} # dark + group_root: {foreground: "#F38BA8"} # red + +links: + normal: {foreground: "#F5B2F7"} # pink + multi_link_file: {foreground: "#CBA6F7"} # violet + +git: + new: {foreground: "#94E2D5"} # green + modified: {foreground: "#F9E2AF"} # yellow + deleted: {foreground: "#F38BA8"} # red + renamed: {foreground: "#CBA6F7"} # violet + typechange: {foreground: "#FAB387"} # orange + ignored: {foreground: "#444455"} # darker + conflicted: {foreground: "#F5B2F7"} # pink + +git_repo: + branch_main: {foreground: "#94E2D5"} # green + branch_other: {foreground: "#CBA6F7"} # violet + git_clean: {foreground: "#94E2D5"} # green + git_dirty: {foreground: "#F9E2AF"} # yellow + +security_context: + none: {foreground: "#777788"} # dark + selinux: + colon: {foreground: "#444455"} + user: {foreground: "#B4BEFE"} + role: {foreground: "#CBA6F7"} + typ: {foreground: "#F5B2F7"} + range: {foreground: "#F9E2AF"} + +file_type: + image: {foreground: "#CBA6F7"} # violet + video: {foreground: "#F5B2F7"} # pink + music: {foreground: "#94E2D5"} # green + lossless: {foreground: "#94E2D5"} # green + crypto: {foreground: "#F38BA8"} # red + document: {foreground: "#F0F0EA"} # white + compressed: {foreground: "#FAB387"} # orange + temp: {foreground: "#444455"} # darker + compiled: {foreground: "#AAAABB"} # grey + build: {foreground: "#F9E2AF", is_underline: false} # yellow — README, Makefile, … + source: {foreground: "#B4BEFE"} # blue + +punctuation: {foreground: "#444455"} # darker — die - in rwx +date: {foreground: "#B4BEFE"} # blue +inode: {foreground: "#F5B2F7"} # pink +blocks: {foreground: "#777788"} # dark +header: {foreground: "#AAAABB", is_underline: false} # grey +octal: {foreground: "#777788"} # dark +flags: {foreground: "#FAB387"} # orange +symlink_path: {foreground: "#CBA6F7", is_underline: false} # violet +control_char: {foreground: "#F38BA8"} # red +broken_symlink: {foreground: "#F38BA8", is_underline: false} # red +broken_path_overlay: {foreground: "#F38BA8", is_underline: false} + +# Eigene Regeln pro Dateiname / Endung — das, was lsd nicht kann: +# +# filenames: +# Makefile: {filename: {foreground: "#F38BA8", is_bold: true}} +# extensions: +# go: {filename: {foreground: "#94E2D5"}} +# md: {filename: {foreground: "#B4BEFE"}} diff --git a/extra/config/lsd/colors.yaml b/extra/config/lsd/colors.yaml new file mode 100644 index 0000000..d8a8251 --- /dev/null +++ b/extra/config/lsd/colors.yaml @@ -0,0 +1,39 @@ +user: 230 +group: 187 +permission: + read: green + write: yellow + exec: red + exec-sticky: 5 + no-access: 245 + octal: 6 + acl: dark_cyan + context: cyan +date: + hour-old: 159 + day-old: 158 + older: 157 +size: + none: 245 + small: 229 + medium: 216 + large: 172 +inode: + valid: 219 + invalid: 245 +links: + valid: 13 + invalid: 245 +tree-edge: 245 +git-status: + default: 245 + unmodified: 245 + ignored: 245 + new-in-index: green + new-in-workdir: green + typechange: yellow + deleted: red + renamed: green + modified: yellow + conflicted: red + \ No newline at end of file diff --git a/extra/config/lsd/config.yaml b/extra/config/lsd/config.yaml new file mode 100644 index 0000000..1727180 --- /dev/null +++ b/extra/config/lsd/config.yaml @@ -0,0 +1,150 @@ +# == Classic == +# This is a shorthand to override some of the options to be backwards compatible +# with `ls`. It affects the "color"->"when", "sorting"->"dir-grouping", "date" +# and "icons"->"when" options. +# Possible values: false, true +classic: false + +# == Blocks == +# This specifies the columns and their order when using the long and the tree +# layout. +# Possible values: permission, user, group, context, size, date, name, inode, links, git +blocks: + - permission + - user + - date + - size + - git + - name + + +# == Color == +# This has various color options. (Will be expanded in the future.) +color: + # When to colorize the output. + # When "classic" is set, this is set to "never". + # Possible values: never, auto, always + when: auto + # How to colorize the output. + # When "classic" is set, this is set to "no-color". + # Possible values: default, custom + # When "custom" is set, lsd will look in the config directory for `colors.yaml`. + theme: custom + +# == Date == +# This specifies the date format for the date column. The freeform format +# accepts a strftime like string. +# When "classic" is set, this is set to "date". +# Possible values: date, locale, relative, '+' +# `date_format` will be a `strftime` formatted value. e.g. `date: '+%d %b %y %X'` will give you a date like this: 17 Jun 21 20:14:55 +date: date + +# == Dereference == +# Whether to dereference symbolic links. +# Possible values: false, true +dereference: false + +# == Display == +# What items to display. Do not specify this for the default behavior. +# Possible values: all, almost-all, directory-only +# display: all + +# == Icons == +icons: + # When to use icons. + # When "classic" is set, this is set to "never". + # Possible values: always, auto, never + when: auto + # Which icon theme to use. + # Possible values: fancy, unicode + theme: fancy + # Separator between icon and the name + # Default to 1 space + separator: " " + +# == Ignore Globs == +# A list of globs to ignore when listing. +# ignore-globs: +# - .git + +# == Indicators == +# Whether to add indicator characters to certain listed files. +# Possible values: false, true +indicators: false + +# == Layout == +# Which layout to use. "oneline" might be a bit confusing here and should be +# called "one-per-line". It might be changed in the future. +# Possible values: grid, tree, oneline +layout: grid + +# == Recursion == +recursion: + # Whether to enable recursion. + # Possible values: false, true + enabled: false + # How deep the recursion should go. This has to be a positive integer. Leave + # it unspecified for (virtually) infinite. + # depth: 3 + +# == Size == +# Specifies the format of the size column. +# Possible values: default, short, bytes +size: default + +# == Permission == +# Specify the format of the permission column +# Possible value: rwx, octal, attributes (windows only), disable +# permission: octal + +# == Sorting == +sorting: + # Specify what to sort by. + # Possible values: extension, name, time, size, version + column: name + # Whether to reverse the sorting. + # Possible values: false, true + reverse: false + # Whether to group directories together and where. + # When "classic" is set, this is set to "none". + # Possible values: first, last, none + dir-grouping: none + +# == No Symlink == +# Whether to omit showing symlink targets +# Possible values: false, true +no-symlink: false + +# == Total size == +# Whether to display the total size of directories. +# Possible values: false, true +total-size: false + +# == Hyperlink == +# Attach hyperlink to filenames +# Possible values: always, auto, never +hyperlink: never + +# == Symlink arrow == +# Specifies how the symlink arrow display, chars in both ascii and utf8 +symlink-arrow: ⇒ + +# == Header == +# Whether to display block headers. +# Possible values: false, true +header: false + +# == Literal == +# Whether to show quotes on filenames. +# Possible values: false, true +literal: false + +# == Truncate owner == +# How to truncate the username and group names for a file if they exceed a certain +# number of characters. +truncate-owner: + # Number of characters to keep. By default, no truncation is done (empty value). + after: + # String to be appended to a name if truncated. + marker: "" + \ No newline at end of file diff --git a/extra/config/yazi/flavors/mwx.yazi/flavor.toml b/extra/config/yazi/flavors/mwx.yazi/flavor.toml new file mode 100644 index 0000000..d0da728 --- /dev/null +++ b/extra/config/yazi/flavors/mwx.yazi/flavor.toml @@ -0,0 +1,185 @@ +# yazi flavor "mwx" — Palette aus coltest.go +# +# white #F0F0EA pink #F5B2F7 +# yellow #F9E2AF violet #CBA6F7 +# orange #FAB387 grey #AAAABB +# red #F38BA8 dark #777788 +# green #94E2D5 darker #444455 +# blue #B4BEFE +# +# Schema: yazi 26.2.2 — [mgr] (früher [manager]), [tabs] (früher tab_* in +# [manager]), [cmp] (früher [completion]), [indicator] (früher hovered/ +# preview_hovered). Alte Sektionsnamen werden von yazi still ignoriert. + +[mgr] +cwd = { fg = "#94E2D5" } + +# Find +find_keyword = { fg = "#F9E2AF", bold = true, italic = true } +find_position = { fg = "#F5B2F7", bg = "reset", bold = true, italic = true } + +# Symlink-Ziel +symlink_target = { fg = "#777788" } + +# Marker +marker_copied = { fg = "#94E2D5", bg = "#94E2D5" } +marker_cut = { fg = "#F38BA8", bg = "#F38BA8" } +marker_marked = { fg = "#CBA6F7", bg = "#CBA6F7" } +marker_selected = { fg = "#FAB387", bg = "#FAB387" } + +# Count +count_copied = { fg = "#444455", bg = "#94E2D5" } +count_cut = { fg = "#444455", bg = "#F38BA8" } +count_selected = { fg = "#444455", bg = "#FAB387" } + +# Border +border_symbol = "│" +border_style = { fg = "#B4BEFE" } + + +[indicator] +# current = die ganze Cursor-Zeile (ersetzt das alte "hovered") +parent = { fg = "#F0F0EA", bg = "#444455" } +current = { fg = "#444455", bg = "#B4BEFE", bold = true } +preview = { fg = "#AAAABB", bg = "#444455" } + + +[tabs] +active = { fg = "#444455", bg = "#B4BEFE", bold = true } +inactive = { fg = "#B4BEFE", bg = "#444455" } + + +[mode] +normal_main = { fg = "#444455", bg = "#B4BEFE", bold = true } +normal_alt = { fg = "#B4BEFE", bg = "#444455" } + +# Select mode +select_main = { fg = "#444455", bg = "#94E2D5", bold = true } +select_alt = { fg = "#94E2D5", bg = "#444455" } + +# Unset mode +unset_main = { fg = "#444455", bg = "#AAAABB", bold = true } +unset_alt = { fg = "#AAAABB", bg = "#444455" } + + +[status] +# Permissions — wie in lsd/eza: read grün, write gelb, exec rot +perm_sep = { fg = "#777788" } +perm_type = { fg = "#B4BEFE" } +perm_read = { fg = "#94E2D5" } +perm_write = { fg = "#F9E2AF" } +perm_exec = { fg = "#F38BA8" } + +# Progress +progress_label = { fg = "#F0F0EA", bold = true } +progress_normal = { fg = "#B4BEFE", bg = "#444455" } +progress_error = { fg = "#F38BA8", bg = "#444455" } + + +[pick] +border = { fg = "#B4BEFE" } +active = { fg = "#F5B2F7", bold = true } +inactive = {} + + +[input] +border = { fg = "#B4BEFE" } +title = {} +value = {} +selected = { reversed = true } + + +[cmp] +border = { fg = "#B4BEFE" } + + +[tasks] +border = { fg = "#B4BEFE" } +title = {} +hovered = { fg = "#F5B2F7", bold = true } + + +[which] +mask = { bg = "#444455" } +cand = { fg = "#94E2D5" } +rest = { fg = "#777788" } +desc = { fg = "#F5B2F7" } +separator = " " +separator_style = { fg = "#777788" } + + +[help] +on = { fg = "#94E2D5" } +run = { fg = "#F5B2F7" } +hovered = { reversed = true, bold = true } +footer = { fg = "#444455", bg = "#F0F0EA" } + + +[spot] +border = { fg = "#B4BEFE" } +title = { fg = "#B4BEFE" } +tbl_col = { fg = "#94E2D5" } +tbl_cell = { fg = "#F5B2F7", bg = "#444455" } + + +[notify] +title_info = { fg = "#94E2D5" } +title_warn = { fg = "#F9E2AF" } +title_error = { fg = "#F38BA8" } + + +[filetype] +rules = [ + # Bilder + { mime = "image/*", fg = "#FAB387" }, + + # Audio / Video + { mime = "{audio,video}/*", fg = "#FAB387" }, + + # Archive + { mime = "application/{zip,rar,7z*,tar,gzip}", fg = "#F9E2AF" }, + { mime = "application/{xz,zstd,bzip*,lzma,compress}", fg = "#F9E2AF" }, + { mime = "application/{archive,cpio,arj,xar,ms-cab*}", fg = "#F9E2AF" }, + + # Kaputte Links + { url = "*", is = "orphan", fg = "#777788", crossed = true }, + + # Symlinks + { url = "*", is = "link", fg = "#F5B2F7" }, + { url = "*/", is = "link", fg = "#CBA6F7" }, + + # Ausführbar + { url = "*", is = "exec", fg = "#F38BA8" }, + + # Sprachen + { url = "*.{c,c++,cake,cats,cc,cl,cp,cpp,cs}", fg = "#94E2D5" }, + { url = "*.{cshtml,css,csx,cxx,emacs,go}", fg = "#94E2D5" }, + { url = "*.{h,h++,hh,hpp,hs,hxx,idc,inl,ipp,ipynb}", fg = "#94E2D5" }, + { url = "*.{java,jl,js,json}", fg = "#94E2D5" }, + { url = "*.{ksh,l,lisp,lsp,lua,m}", fg = "#94E2D5" }, + { url = "*.{php,pl,ps1,py,ron}", fg = "#94E2D5" }, + { url = "*.{sass,sh,tcc,tpp}", fg = "#94E2D5" }, + { url = "*.{vbs,w,}", fg = "#94E2D5" }, + { url = "*.{sh,bash,zsh,fish}", fg = "#94E2D5" }, + { url = "*.{el,elc}", fg = "#94E2D5" }, + + # Config / Patches + { url = "*.{cfg,conf,yaml,yml,toml,inc}", fg = "#F9E2AF" }, + { url = "*.{diff,patch,matlab,ron}", fg = "#F9E2AF" }, + + # Markup + { url = "*.{jinja,markdown,md,mkd,mkdn,mkdown,tex}", fg = "#B4BEFE" }, + { url = "*.{htm,html,xhtml,xml}", fg = "#B4BEFE" }, + { url = "*.{org}", fg = "#CBA6F7" }, + + # Dokumente + { url = "*.{pdf,txt,rtf}", fg = "#AAAABB" }, + { url = "*.{doc,docx,xls,xlsx,ppt,pptx}", fg = "#AAAABB" }, + + # Virtuelles Dateisystem + { mime = "vfs/{absent,stale}", fg = "#777788" }, + + # Fallback + { url = "*", fg = "#F0F0EA" }, + { url = "*/", fg = "#B4BEFE" }, +] diff --git a/extra/config/yazi/flavors/mwx.yazi/flavor.toml.bak b/extra/config/yazi/flavors/mwx.yazi/flavor.toml.bak new file mode 100644 index 0000000..f0b7929 --- /dev/null +++ b/extra/config/yazi/flavors/mwx.yazi/flavor.toml.bak @@ -0,0 +1,159 @@ +[manager] +cwd = { fg = "#00d1e9" } + +# Hovered +hovered = { fg = "#ffffff", bg = "#66ccff" } +preview_hovered = { underline = true } + +# Find +find_keyword = { fg = "#ffde57", bold = true, italic = true, underline = true } +find_position = { fg = "#e45c9c", bg = "reset", bold = true, italic = true } + +# Marker +marker_copied = { fg = "#6ae073", bg = "#6ae073" } +marker_cut = { fg = "#ff6e64", bg = "#ff6e64" } +marker_marked = { fg = "#00d1e9", bg = "#00d1e9" } +marker_selected = { fg = "#ffde57", bg = "#ffde57" } + +# Tab +tab_active = { reversed = true } +tab_inactive = {} +tab_width = 1 + +# Count +count_copied = { fg = "#222327", bg = "#6ae073" } +count_cut = { fg = "#222327", bg = "#ff6e64" } +count_selected = { fg = "#222327", bg = "#ffde57" } + +# Border +border_symbol = "│" +border_style = { fg = "#66ccff" } + + +[mode] +normal_main = { fg = "#222327", bg = "#66ccff", bold = true } +normal_alt = { fg = "#66ccff", bg = "#393939" } + +# Select mode +select_main = { fg = "#222327", bg = "#6ae073", bold = true } +select_alt = { fg = "#6ae073", bg = "#393939" } + +# Unset mode +unset_main = { fg = "#222327", bg = "#f2cdcd", bold = true } +unset_alt = { fg = "#f2cdcd", bg = "#393939" } + + +[status] +separator_open = "" +separator_close = "" + +# Progress +progress_label = { fg = "#ffffff", bold = true } +progress_normal = { fg = "#66ccff", bg = "#45475a" } +progress_error = { fg = "#ff6e64", bg = "#45475a" } + +# Permissions +perm_sep = { fg = "#8c8c8c" } +perm_type = { fg = "#66ccff" } +perm_read = { fg = "#ffde57" } +perm_write = { fg = "#ff6e64" } +perm_exec = { fg = "#6ae073" } + + +[pick] +border = { fg = "#66ccff" } +active = { fg = "#e45c9c", bold = true } +inactive = {} + + +[input] +border = { fg = "#0000ff" } +title = {} +value = {} +selected = { reversed = true } + + +[completion] +border = { fg = "#66ccff" } + + +[tasks] +border = { fg = "#66ccff" } +title = {} +hovered = { fg = "#e45c9c", underline = true } + + +[which] +mask = { bg = "#393939" } +cand = { fg = "#00d1e9" } +rest = { fg = "#8c8c8c" } +desc = { fg = "#e45c9c" } +separator = "  " +separator_style = { fg = "#585b70" } + + +[help] +on = { fg = "#00d1e9" } +run = { fg = "#e45c9c" } +hovered = { reversed = true, bold = true } +footer = { fg = "#393939", bg = "#eaead7" } + + +[notify] +title_info = { fg = "#6ae073" } +title_warn = { fg = "#ffde57" } +title_error = { fg = "#ff6e64" } + + +[filetype] +rules = [ + # Images + { mime = "image/*", fg = "#ffb350" }, + + # Media + { mime = "{audio,video}/*", fg = "#ffb350" }, + + # Archives + { mime = "application/{zip,rar,7z*,tar,gzip}", fg = "#ffde57" }, + { mime = "application/{xz,zstd,bzip*,lzma,compress}", fg = "#ffde57" }, + { mime = "application/{archive,cpio,arj,xar,ms-cab*}", fg = "#ffde57" }, + + # Broken links + { name = "*", is = "orphan", fg = "#8c8c8c", crossed = true }, + + # Symlinks files + { name = "*", is = "link", fg = "#e45c9c" }, + { name = "*/", is = "link", fg = "#66ffcc" }, + + # Executables + { name = "*", is = "exec", fg = "#ff6e64" }, + + # Languages + { name = "*.{c,c++,cake,cats,cc,cl,cp,cpp,cs}", fg = "#6ae073" }, + { name = "*.{cshtml,css,csx,cxx,emacs,go}", fg = "#6ae073" }, + { name = "*.{h,h++,hh,hpp,hs,hxx,idc,inl,ipp,ipynb}", fg = "#6ae073" }, + { name = "*.{java,jl,js,json}", fg = "#6ae073" }, + { name = "*.{ksh,l,lisp,lsp,lua,m}", fg = "#6ae073" }, + { name = "*.{php,pl,ps1,py,ron}", fg = "#6ae073" }, + { name = "*.{sass,sh,tcc,tpp}", fg = "#6ae073" }, + { name = "*.{vbs,w,}", fg = "#6ae073" }, + { name = "*.{sh,bash,zsh,fish}", fg = "#6ae073" }, + + { name = "*.{cfg,conf,yaml,yml,toml,inc}", fg = "#ffde57" }, + { name = "*.{diff,patch,matlab,ron}", fg = "#ffde57" }, + + { name = "*.{jinja,markdown,md,mkd,mkdn,mkdown,tex}", fg = "#00d1e9" }, + { name = "*.{htm,html,xhtml,xml}", fg = "#00d1e9" }, + + # Emacs + { name = "*.{el,elc}", fg = "#6ae073" }, + { name = "*.{org}", fg = "#cd7bf6" }, + + # Documents + { name = "*.{pdf,txt,rtf}", fg = "#9999ff" }, + { name = "*.{pdf,doc,docx,xls,xlsx,ppt,pptx}", fg = "#9999ff" }, + + # Fallback + { name = "*", fg = "#eaead7" }, + { name = "*/", fg = "#66ccff" } +] diff --git a/extra/config/yazi/keymap.toml b/extra/config/yazi/keymap.toml new file mode 100644 index 0000000..f672852 --- /dev/null +++ b/extra/config/yazi/keymap.toml @@ -0,0 +1,4 @@ +[[manager.prepend_keymap]] +on = "t" +run = "plugin max-preview" +desc = "Maximize or restore preview" diff --git a/extra/config/yazi/package.toml b/extra/config/yazi/package.toml new file mode 100644 index 0000000..9091919 --- /dev/null +++ b/extra/config/yazi/package.toml @@ -0,0 +1,5 @@ +[plugin] +deps = [] + +[flavor] +deps = [] diff --git a/extra/config/yazi/theme.toml b/extra/config/yazi/theme.toml new file mode 100644 index 0000000..022029c --- /dev/null +++ b/extra/config/yazi/theme.toml @@ -0,0 +1,2 @@ +[flavor] +dark = "mwx" diff --git a/extra/config/yazi/yazi.toml b/extra/config/yazi/yazi.toml new file mode 100644 index 0000000..0f4ae9e --- /dev/null +++ b/extra/config/yazi/yazi.toml @@ -0,0 +1,3 @@ +[mgr] +# [parent, current, preview] — Default ist [1, 4, 3] +ratio = [1, 1, 3] diff --git a/extra/omp.json b/extra/omp.json new file mode 100644 index 0000000..a531603 --- /dev/null +++ b/extra/omp.json @@ -0,0 +1,133 @@ +{ + "palette": { + "white": "#F0F0EA", + "yellow": "#F9E2AF", + "orange": "#FAB387", + "red": "#F38BA8", + "green": "#94E2D5", + "blue": "#B4BEFE", + "pink": "#F5B2F7", + "violet": "#CBA6F7", + "grey": "#AAAABB", + "dark": "#777788", + "darker": "#444455" + }, + "var": { + "sep": "<#ffffff>・" + }, + "blocks": [ + { + "alignment": "left", + "newline": false, + "segments": [ + { + "foreground_templates": ["{{if .SSHSession }}p:violet{{else}}p:green{{ end }}"], + "style": "diamond", + "template": "{{.HostName}}{{.Var.sep}}{{.OS}}{{.Var.sep}}{{.Shell}}", + "type": "session" + },{ + "foreground": "p:orange", + "style": "diamond", + "template": "{{.Var.sep}}{{.SHLVL}}/{{.PromptCount}}", + "type": "session" + }, + { + "foreground_templates": ["{{if .Root }}p:red{{else}}p:green{{ end }}"], + "leading_diamond": "", + "style": "diamond", + "template": "{{.Var.sep}}{{.UserName}}", + "type": "session" + }, + + { + "foreground": "p:green", + "foreground_templates": ["{{ if gt .Code 0 }}p:red{{ end }}"], + "leading_diamond": "", + "style": "diamond", + "template": "{{.Var.sep}}{{.Code}}", + "type": "session" + }, + { + "foreground": "p:yellow", + "properties": { + "branch_icon": "", + "fetch_stash_count": true, + "fetch_status": true, + "fetch_upstream_icon": true, + "fetch_worktree_count": true + }, + "style": "diamond", + "template": "{{.Var.sep}}{{ .HEAD }} {{ .StashCount }}", + "trailing_diamond": "", + "type": "git" + }, + { + "type": "go", + "style": "plain", + "foreground": "p:blue", + "template": "{{.Var.sep}}GO {{ .Full }} " + } + ], + "type": "prompt" + }, + { + "alignment": "right", + "segments": [ + { + "foreground": "p:blue", + "properties": { + "time_format": "Mon, 15:04" + }, + "style": "diamond", + "template": "{{ .CurrentDate | date .Format }}{{.Var.sep}}", + "type": "time" + }, + { + "foreground": "#94ffa2", + "style": "diamond", + "template": "{{ round .PhysicalPercentUsed .Precision }}%{{.Var.sep}}{{ round .Load15 .Precision }}", + "properties": { + "precision": 1 + }, + "type": "sysinfo" + }, + { + "type": "battery", + "style": "plain", + "foreground": "#FFFFFF", + "background": "", + "foreground_templates": [ + "{{ if lt .Percentage 20 }}p:red{{ end }}", + "{{ if lt .Percentage 50 }}p:yellow{{ end }}", + "p:blue" + ], + "template": "{{if not .Error}}{{.Var.sep}}{{.Percentage}}%{{end}} " + } + + ], + "type": "prompt" + }, + { + "alignment": "left", + "newline": true, + "segments": [ + { + "properties": { + "always_enabled": true + }, + "style": "plain", + "template": "{{.PWD}} <#66ffcc>>{{if .Root }}>{{end}} ", + "type": "status" + } + ], + "type": "prompt" + } + ], + "console_title_template": "{{.UserName}}@{{.HostName}} {{.Shell}} in {{.PWD}}", + + "transient_prompt": { + "background": "transparent", + "template": "<#cc99ff>> " + }, + "version": 3 +} diff --git a/extra/zshrc b/extra/zshrc new file mode 100644 index 0000000..744e972 --- /dev/null +++ b/extra/zshrc @@ -0,0 +1,27 @@ +alias tsc='timeshift --yes --create --comments' +alias tsr='timeshift --yes --restore' +alias tsd='timeshift --yes --delete' +alias tsl='timeshift --list' + +eval "$(oh-my-posh init zsh --config /db/etc/omp.json )" + +[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh + +alias y yazi +alias f fzf + + +alias ll='eza --icons auto -la' +alias ls='eza --icons auto -a' +alias lt='eza --icons auto -la -s changed' +alias lx='eza --icons auto --tree -la' + +export FZF_DEFAULT_OPTS=$FZF_DEFAULT_OPTS' + --color=fg:#AAAABB,bg:#252528,hl:#F5B2F7 + --color=fg+:#F0F0EA,bg+:#444455,hl+:#F5B2F7 + --color=info:#94E2D5,prompt:#F38BA8,pointer:#CBA6F7 + --color=marker:#94E2D5,spinner:#CBA6F7,header:#AAAABB + --color=query:#F0F0EA,disabled:#777788,gutter:#252528 + --color=border:#444455,separator:#444455,scrollbar:#777788 + --color=label:#AAAABB,preview-fg:#F0F0EA,preview-bg:#252528' + \ No newline at end of file diff --git a/files/authorized_keys b/files/authorized_keys new file mode 100644 index 0000000..d4a4609 --- /dev/null +++ b/files/authorized_keys @@ -0,0 +1,3 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9kb7R4qAqRdPw90zxM9dg68bnskdgqAZLSaogAKSpcvsmVNDgz5XKAr22hg25VrhJdE4S8ptvAyDT3n18yYmqv0Bht7t/uHWUd+pzJHy5d763nII7ukQtKBZdLaLEqSGD1XkyOTj21MZiiCaNurU6pqbcx3mlfVGtH0SdBCs8Nz6tYVUC/jCn202LM5tmHakLgYBvU4QPb6nfNMGKvNVjxUCs1Vn+knPsUtiIi6ktkz8LHRSx8Qd9vlTLMccsnSm/FfaepVPLslQ2rA7fpixhWIH/sJizcTubB1ErA8BhDM7exD+UEfmN7CKvarFZxDf3WgckonIGuoS81wT+cZDT m +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCoqI8A+SES/kWp6ZqJ6agbk8lz7UhOIZZrSF1cnuv+9bCq2QtO5qkAalJSr5hNZXsEZl9OfQibcFk7GUWTaEHCg/vdTxfMUdWDQDkOyPNPQD2JRZ3NpcdtkteSEfYzPwyXFV3HSoQys6VQAib9SeMyDtTgFPN+xm2lQtVzGiFg73ny5Lq1PsaS40+6EwGZmMIfUQLVm5OjislDW1p+F1PyYUeM9wiK/KbJl99Pd5CECXN9uunAEOz/siDwpo1TXZ6od6ZKMCGDT3v742cc28HpHxK/GQ9ezXlaTZ4BldTtkoupK6KwxOZ8x/eyiGq00E/YdjtxhLi6ggmjlBk2Gk33 root@data + diff --git a/files/csh.cshrc b/files/csh.cshrc new file mode 100644 index 0000000..7a17366 --- /dev/null +++ b/files/csh.cshrc @@ -0,0 +1,49 @@ +unsetenv LANG +setenv HN `hostname` + +set prompt="%n@${HN}:%~ > " +if ( $USER == root ) then + set prompt="%n@${HN}:%~ >> " +endif + +set history=128 +set savehist=128 +set watch=( any any ) +set recexact +set autolist +set dunique +set matchbeep=nomatch +set pushdsilent +set fignore=( .o ) +set echo_style=both +unset ignoreeof +unset mail +set notify +set time=( 1 " %E [%P] used." ) + +alias a 'alias' +alias h 'history' +alias L 'last -16' +alias ls 'ls -F' +alias ll 'ls -lsah' +alias lt 'ls -ltrah' +alias cd 'cd \!*;echo $cwd' +alias pwd 'echo $cwd' +alias s 'ssh' +alias sr 'ssh -l root' +alias rs 'rsync -va --delete --stats' +alias p 'ps -ef | grep ${LOGNAME}' +alias P 'ps -ef' +alias af 'apt-cache search' +alias ai 'apt-get install' +alias sd 'lsblk -o NAME,FSTYPE,SIZE,MOUNTPOINT,LABEL' + +alias ga 'git add -v .' +alias gb 'git branch' +alias gs 'git status' +alias gl "git log -32 --reverse --date=local --format='%h %cd %s'" +alias gc 'git commit -m' +alias go 'git checkout' +alias gp 'git push' + +setenv PATH "$PATH":/db/bin diff --git a/files/default.jcf b/files/default.jcf new file mode 100644 index 0000000..d2780ed --- /dev/null +++ b/files/default.jcf @@ -0,0 +1,83 @@ +# joe theme — Palette aus mwxcol.go +# +# white #F0F0EA pink #F5B2F7 +# yellow #F9E2AF violet #CBA6F7 +# orange #FAB387 grey #AAAABB +# red #F38BA8 dark #777788 +# green #94E2D5 darker #444455 +# blue #B4BEFE +# +# Ort: ~/.joe/colors/default.jcf (verdeckt die System-Version) +# Getestet mit joe 4.6. + +.colors * + +.set white $F0F0EA +.set yellow $F9E2AF +.set orange $FAB387 +.set red $F38BA8 +.set green $94E2D5 +.set blue $B4BEFE +.set pink $F5B2F7 +.set violet $CBA6F7 +.set grey $AAAABB +.set dark $777788 +.set darker $444455 + +-text [white] + +# --- Syntax ----------------------------------------------------------- +=Bad [red] +=Preproc [orange] +=Define [orange] +=String [red] +=Comment [grey] +=IncLocal [green] +=IncSystem [green] bold +=Constant [red] +=Escape [green] bold +=Type [violet] +=Keyword [pink] +=Variable [green] +=Brace [white] bold +=Tag [blue] bold +=TagName +Tag +=Title bold +=TODO [yellow] +=BUG [yellow] + +# --- UI --------------------------------------------------------------- +-status [white]/[darker] +-selection /[darker] +-linum [dark] +-curlinum [yellow] bold +-menu [white]/[darker] +-menusel [darker]/[blue] + +# --- diff ------------------------------------------------------------- +=diff.AddLine [green] +=diff.DelLine [red] +=diff.ChgLine [yellow] +=diff.Garbage [darker] +=diff.FileOld [red] bold +=diff.FileNew [green] bold +=diff.Hunk [violet] bold + +# Identitäts-Mapping wie bisher: numerische Farben aus alten Syntax-Files +# greifen auf die 16 Farben des Terminals durch. +-term 0 0 +-term 1 1 +-term 2 2 +-term 3 3 +-term 4 4 +-term 5 5 +-term 6 6 +-term 7 7 +-term 8 8 +-term 9 9 +-term 10 10 +-term 11 11 +-term 12 12 +-term 13 13 +-term 14 14 +-term 15 15 diff --git a/files/dx b/files/dx new file mode 100755 index 0000000..a4312ed --- /dev/null +++ b/files/dx @@ -0,0 +1,95 @@ +#!/usr/bin/perl +######################################################################## count files and directories (mwx'2016) +use Getopt::Std;getopts('dnh'); + +$version='1.0.2'; + +if ($opt_h) {;&help;exit;} + +if (-d $ARGV[0]) { + &dx($ARGV[0]); +} else { + &dx("."); +} + +sub dx() { + my($dir)=@_; + $ml=length($dir); + + opendir(DIR,$dir); + while($f=readdir(DIR)) { + if ($f ne '.' && $f ne '..') { + + if (-d "$dir/$f") { + $n=0;$s=0; + open(IN,"find '$dir/$f' -type f |"); + while() { + chomp(); + $s+=(stat($_))[7]; + $ts+=(stat($_))[7]; + $n++; + $tn++; + } + close(IN); + $N{"$f/"}=$n; + $S{"$f/"}=$s; + $ml=length($f) if (length($f)>$ml); + } + + if (-f "$dir/$f" && !$opt_d) { + $S{$f}+=(stat("$dir/$f"))[7]; + $ts+=(stat("$dir/$f"))[7]; + $N{$f}++; + $tn++; + $ml=length($f) if (length($f)>$ml); + } + + } + } + closedir(DIR); + + $frm=sprintf "%%-%ds",$ml+1; + $out=sprintf "$frm %8d %8s\n",$dir,$tn,&formsize($ts); + + if ($opt_n) { + for $f (sort { $N{$a} <=> $N{$b} } (keys(%N))) { + $out.=sprintf " $frm %8d %8s\n",$f,$N{$f},&formsize($S{$f}); + } + } else { + for $f (sort { $S{$a} <=> $S{$b} } (keys(%S))) { + $out.=sprintf " $frm %8d %8s\n",$f,$N{$f},&formsize($S{$f}); + } + } + print $out; +} + +####################################################################################################### SUPPORT + +sub formsize() { + my($b)=@_; + if ($b>1024*1024*1024*1024) { + $s=sprintf("%.0fT",$b/1024/1024/1024/1024) + } elsif ($b>1024*1024*1024) { + $s=sprintf("%.0fG",$b/1024/1024/1024) + } elsif ($b>1024*1024) { + $s=sprintf("%.0fM",$b/1024/1024) + } elsif ($b>1024) { + $s=sprintf("%.0fK",$b/1024) + } else { + $s=sprintf("%.0f",$b) + } + return $s; +} + +sub help() { +print <<"ENDOFHELP"; +dx ${version}, count files and directories, mwx'2016 +usage: dx [-n] [-d] [path] + -n sort by number of files (default by size) + -d count only directories + -h this help +ENDOFHELP +} + +########################################################################################################### END + diff --git a/files/gx b/files/gx new file mode 100755 index 0000000..ebabaab --- /dev/null +++ b/files/gx @@ -0,0 +1,20 @@ +#!/usr/bin/perl +use Getopt::Std;getopts('x'); + +use Sys::Hostname qw(hostname);use Socket; +my($ip) = inet_ntoa( (gethostbyname(hostname()))[4] ); +my($user)=getpwuid( $< ); + +if ($opt_x) { + $comment="[$ip,$user] " . join(' ',@ARGV); +} else { + $comment=join(' ',@ARGV); +} + +$comment='-' if ($comment=~/^\s*$/); +$comment=~s/\s*$//; + +system("git add -v ."); +system("git commit -m '$comment'"); +system("git push"); + diff --git a/files/gy b/files/gy new file mode 100755 index 0000000..84b6e25 --- /dev/null +++ b/files/gy @@ -0,0 +1,51 @@ +#!/usr/bin/perl + +$repo=$ARGV[0]; +$repo=~s/\/\s*$//; + +die if ($repo=~/^\s*$/); + +$cgit='git://git.micw.org'; +$pgit='ssh://git@git.micw.org:2234/home/git'; + +if (-d $repo) { + if (yesno('overwrite existing directory?',0)) { + &cmd("rm -rf $repo") + } else { + exit; + } +} + +&cmd("git clone $cgit/$repo.git"); +&cmd("cd $repo;git remote set-url origin $pgit/$repo.git"); + +sub cmd() { + my($cmd,$quiet)=@_; + print "$cmd\n" if (!$quiet); + system($cmd); +} + +sub yesno { + my($prom,$def)=@_; + my($ans); + if ($def) {;$ans=&getkey("$prom Y/n ? ");} + else {;$ans=&getkey("$prom y/N ? ");} + if ($ans=~/^\s*$/) { + if ($def) {;return(1);} + else {;return(0);} + } + if ($ans=~/^\s*y\s*$/i || $ans=~/^\s*yes\s*$/i) { + return 1; + } + return 0; +} + +sub getkey { + $|=1; + print "$_[0]"; + system "stty", '-icanon', '-echo', 'eol', "\001"; + $key = getc(STDIN);$key=~s/[\r\n\t]//g; + system "stty", 'icanon', 'echo', 'eol', "^@"; + print "$key\n"; + return $key; +} diff --git a/files/joerc b/files/joerc new file mode 100755 index 0000000..5e4c9b1 --- /dev/null +++ b/files/joerc @@ -0,0 +1,99 @@ + +-lmsg \i%k%T%W%I%X %n %m%y%R %x +-rmsg %S Row %r Col %c %p%% %u ^H help ^T menu + +-nonotice +-noxon +-beep +-tab 2 +-indentc 9 +-nobackups +-pg 0 +--autoindent + +{Basic +^Y Save & Quit ^F Search/Replace ^A Begining of Line ^B Block Start +^S Save ^G Search Next ^E End of Line ^W Block Cut +^C Abort ^N Next Page ^U Begininig of File ^V Block Paste +^T Menu ^P Previous Page ^Q End of File ^H Help +^Q Undo ^K Delete Line ^L Goto Line +^R Redo ^D Delete Character mwx'2013 joerc v2.02 +} + +:main +type ^@ TO ÿ + +rtn ^M +backs ^? +abort ^C + +exsave ^Y +save ^S +undo ^Z +redo ^R + +delch ^D +dellin ^K + +help ^H + +rtarw ^[ [ C +ltarw ^[ [ D +uparw ^[ [ A +dnarw ^[ [ B +pgdn ^N +pgup ^P +line ^L + +ffirst ^F +fnext ^G + +markb,msg,"Mark set",rtn ^B +markk,copy,blkdel,msg,"Block copy",rtn ^W +yank ^V + +bol ^A +eol ^E +bof ^U +eof ^Q + +menu,"root",rtn ^T + +:prompt +:inherit main + +:query +:inherit main + +:querya +type ^@ TO ÿ + +:querysr +:inherit main + +:menu +:inherit main + +abort ^Y +backsmenu ^? +bolmenu ^A +eolmenu ^E +rtarwmenu ^[ [ C +ltarwmenu ^[ [ D +uparwmenu ^[ [ A +dnarwmenu ^[ [ B +rtn ^M + +:defmenu root +mode,"autoindent",rtn I Autoindent %Zautoindent% +mode,"overwrite",rtn T Overtype %Zoverwrite% +mode,"wordwrap",rtn W Word wrap %Zwordwrap% +mode,"hex",rtn % % Hex edit mode +mode,"tab",rtn D Tab width %Ztab% +mode,"crlf",rtn Z CR-LF (MS-DOS) %Zcrlf% +mode,"linums",rtn N Line numbers %Zlinums% +mode,"beep",rtn B Beep %Zbeep% +mode,"rdonly",rtn % % Read only %Zrdonly% +mode,"icase",rtn % % Search case %Zicase% +execmd C command +mode O option diff --git a/files/joerc4 b/files/joerc4 new file mode 100755 index 0000000..95b5580 --- /dev/null +++ b/files/joerc4 @@ -0,0 +1,104 @@ +-notite +-assume_color +-guess_non_utf8 +-guess_utf16 +-guess_crlf +-guess_indent +-menu_above +-transpose +-pastehack +-restore +-search_prompting +-nobackups +-nodeadjoe +-undo_keep 0 +-noxon + +-lmsg \i%k%T%W%I%X %n %m%y%R %x +-rmsg %S Row %r Col %c %p%% %u ^H help +-smsg ** Line %r Col %c Offset %o(0x%O) %e %a(0x%A) Width %w ** +-zmsg ** Line %r Col %c Offset %o(0x%O) ** + +-highlight +-istep 2 +-tab 2 + +:include ftyperc + +{Basic +^Y Save & Quit ^F Search/Replace ^A Begining of Line ^B Block Start ^T^H Toggle Hex +^S Save ^G Search Next ^E End of Line ^W Block Cut ^T^O Overwrite Mode +^C Abort ^N Next Page ^U Begininig of File ^V Block Paste ^T^I Toggle Autoindent +^Z Undo ^P Previous Page ^Q End of File ^H Help ^T^T Set Tab Width +^R Redo ^K Delete Line ^L Goto Line ^T^C Execute Command + ^D Delete Character mwx'2017 joerc v4.x.x +} + +:windows Bindings common to all windows +type U+0 TO U+10FFFF +rtn ^M +backs ^? +abort ^C + +exsave ^Y +save ^S +undo ^Z +redo ^R + +delch ^D +dellin ^K + +help ^H + +rtarw ^[ [ C +ltarw ^[ [ D +uparw ^[ [ A +dnarw ^[ [ B +pgdn ^N +pgup ^P +line ^L + +ffirst ^F +fnext ^G + +markb,msg,"Mark set",rtn ^B +markk,copy,blkdel,msg,"Block copy",rtn ^W +yank ^V + +bol ^A +eol ^E +bof ^U +eof ^Q + +mode,"hex",rtn ^T ^H +mode,"overwrite",rtn ^T ^O +mode,"tab",rtn ^T ^T +mode,"autoindent",rtn ^T ^I +execmd ^T ^C + +:main Text editing window +:inherit windows + +:prompt +:inherit main + +:menu +:inherit windows + +:query +:inherit windows + +:querya +type U+0 TO U+10FFFF + +:querysr +type U+0 TO U+10FFFF + +:shell Input to shell windows +:inherit main + +:vtshell Input to ANSI shell windows +:inherit main + + + diff --git a/files/locale b/files/locale new file mode 100644 index 0000000..31062ff --- /dev/null +++ b/files/locale @@ -0,0 +1 @@ +LANG="C.UTF-8" diff --git a/files/mbackup b/files/mbackup new file mode 100755 index 0000000..2586663 --- /dev/null +++ b/files/mbackup @@ -0,0 +1,573 @@ +#!/usr/bin/perl +############################################################################################# mbackup (mwx'2023) +$VERSION='3.2.0'; +use Getopt::Std;getopts('vVDWMYhsfc:');$opt_v=1 if ($opt_V); +use Net::Ping; +use Fcntl ':flock'; +chomp($HOST=`hostname`); + +&help if($opt_h); + +$NOW=time(); +my(@z)=localtime($NOW);$z[4]+=1;$z[5]-=100;$z[6]+=1; +$z=sprintf("%02d.%02d-%02d:%02d",$z[3],$z[4],$z[5],$z[2],$z[1]); + + +$MAX{'daily'}=7; # default values +$MAX{'weekly'}=4; +$MAX{'monthly'}=12; +$MAX{'yearly'}=3; + +$FLAT=0; +$RSYNCOPTS='--no-o --no-g --chmod=ugo=rwX'; + +$RSYNCRETRIES=3; + +$CONFIG='';$REQUESTCONFIG=$ARGV[0]; # load configuration + +for ($opt_c,"/db/etc/mbackup.conf",$ENV{'HOME'}."/etc/mbackup.conf",$ENV{'HOME'}."/.mbackup.conf") { + if (-f) { + $confile=$_; + last; + } +} + +require $confile; + + +for (keys(%GROUPS)) { # build group list + if ($_ eq $REQUESTCONFIG) { + push(@GROUP,@{$GROUPS{$_}}); + $CONFIG=$REQUESTCONFIG; + } +} + + +if ($CONFIG=~/^\s*$/) { # check for valid config + &log("ERROR: config '$REQUESTCONFIG' not found",1); + exit; +} +$REMOTE=0;$REMOTE=1 if ($TARGETDIR!~/^\//); + + +if ($opt_s) { # show configuration + if (@GROUP) { + print "\n"; + print "mode: group\n\n"; + print "group sleep: $GROUPSLEEP\n\n" if ($GROUPSLEEP>0); + + for $job (@GROUP) { + print "/db/bin/mbackup -c $confile $job\n"; + } + print "\n"; + } else { + print "\n"; + if ($FLAT==1) { + print "mode: flat\n"; + } else { + print "mode: $MAX{'daily'} daily, $MAX{'weekly'} weekly, "; + print "$MAX{'monthly'} monthly, $MAX{'yearly'} yearly\n"; + } + if ($#EXCLUDE>-1) { + print "\n"; + $tmp="";$tmp.="$_, " for (@EXCLUDE);$tmp=~s/\,\s+$//; + print "exclude: $tmp\n"; + } + print "\n"; + $l=0; + for (keys(%SRC)) { + $l=length($_) if length($_)>$l; + } + printf "%-${l}s -> %s\/%s\n",$_,$TARGETDIR,$SRC{$_} for (keys(%SRC)); + print "\n"; + } + exit; +} + + +if (@GROUP) { # run backup group + for $job (@GROUP) { + $cmd="/db/bin/mbackup -c $confile $job"; + + &log("{$CONFIG} $cmd",1); + system($cmd); + + if ($GROUPSLEEP>0 && $job ne $GROUP[-1]) { + &log("group loop sleep ($GROUPSLEEP seconds)",1); + sleep($GROUPSLEEP); + } + + } + exit; +} + + + +if ($MY_LOG) { # mysql loging + use DBI; + $dbh=DBI->connect("DBI:mysql:$MY_DB:$MY_HOST:",$MY_USER,$MY_PASSWD,{RaiseError=>1,PrintError=>1}); +} + + +$mode=''; # set mode (daily,weekly,monthly,yearly) +my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday)=localtime($NOW); +$mon++;$year+=1900; +$z=sprintf("%02d\.%02d\.%04d %02d\:%02d",$mday,$mon,$year,$hour,$min); +$mode='daily' if ( $MAX{'daily'}>0); +$mode='weekly' if ( $wday==0 && $MAX{'weekly'}>0); +$mode='monthly' if ( $mday==1 && $MAX{'monthly'}>0); +$mode='yearly' if ( $yday==0 && $MAX{'yearly'}>0); + + +$mode='daily' if ($opt_D); # set mode manual +$mode='weekly' if ($opt_W); +$mode='monthly' if ($opt_M); +$mode='yearly' if ($opt_Y); + + +if (defined($PING)) { # check if host is reachable + if (!Net::Ping->new("icmp", 15)->ping($PING)) { + &log("ERROR: host $PING not reachable",1);exit; + } +} + + +if (!-d "$TARGETDIR" && $REMOTE==0) { # check target dir + if ($opt_f) { + system("mkdir $TARGETDIR"); + if (!-d "$TARGETDIR") { + &log("ERROR: target dir creation failed (mkdir $TARGETDIR)",1); + exit; + } + } else { + &log("ERROR: can not access target dir (mkdir $TARGETDIR)",1); + exit; + } +} + + +for $srcdir (keys(%SRC)) { # check source dir + if ($srcdir=~/^\// && !-d $srcdir) { + &log("ERROR: mising source dir '$srcdir'",1); + exit; + } +} + + +undef(%keycount); # check for duplicate source keys +for $srcdir (keys(%SRC)) { + $keycount{$SRC{$srcdir}}++; + if ($keycount{$SRC{$srcdir}}>1) { + &log("ERROR: duplicate source key '$SRC{$srcdir}'",1); + exit; + } +} + + +if ($FLAT==1 || $REMOTE==1) { # flat mode + $toterr=0;$totfiles=0;$tottfi=0;$totbytes=0;$tottby=0;$totrt=0; + + for $srcdir (keys(%SRC)) { + $subname=$SRC{$srcdir}; + + $cmd="/usr/bin/rsync -av $RSYNCOPTS --stats --delete " . + &exf() . " --numeric-ids $srcdir/. $TARGETDIR/$subname"; + + ($err,$fi,$tfi,$by,$tby,$rt,$try)=&rsync($cmd); + + &log("[$CONFIG] $srcdir,$TARGETDIR ($err,$tfi,$fi,$tby,$by,$rt)",1); + + if ($MY_LOG) { # mysql logging + $sql="INSERT INTO mbackup VALUES(0,now(),'$HOST','$VERSION','$CONFIG',". + "'$srcdir','$TARGETDIR',$fi,$tfi,$by,$tby,$rt,$err,$try)"; + $dbh->do($sql); + } + + if ($HTTP_LOG!~/^\s*$/) { # http logging + $tmp= "MBACKUP,$HOST,$VERSION,$CONFIG,$srcdir,$TARGETDIR,$fi,$tfi,$by,$tby,$rt,$err,$try"; + use LWP::UserAgent; + my $ua = new LWP::UserAgent(); + $response = $ua->post("http://$HTTP_LOG", Content => $tmp); + } + + $toterr+=$err;$totfi+=$fi;$tottfi+=$tfi;$totby+=$by;$tottby+=$tby;$totrt+=$rt; + &log("rsync error $err in $srcdir/. -> $TARGETDIR/$subname") if ($err); + } + if ($toterr==0) { + &log("[$CONFIG] mbackup successful finished ($tottfi,$totfi,$tottby,$totby,$totrt)",1) + } + exit; +} + + +if ($mode eq '') { # check if mode is defiend otherwise exit + &log("ERROR: undefined mode",1); + exit; +} + + +$yweekly=0;$ymonthly=0;$yyearly=0; # search for missing snapshot +opendir(DIR,$TARGETDIR); +while ($file=readdir(DIR)) { + my(@stat)=stat("$TARGETDIR/$file"); + + if ($file=~/^weekly\.\d+$/) { + $yweekly=$stat[9] if ($stat[9]>$yweekly); + } + if ($file=~/^monthly\.\d+$/) { + $ymonthly=$stat[9] if ($stat[9]>$ymonthly); + } + if ($file=~/^yearly\.\d+$/) { + $yyearly=$stat[9] if ($stat[9]>$yyearly); + } +} +closedir(DIR); +if ($NOW-$yweekly>86400*10 && $yweekly!=0 && $MAX{'weekly'}>0) { + &log("WARNING: no weekly snapshot for more than 10 days",1); +} +if ($NOW-$ymonthly>86400*40 && $ymonthly!=0 && $MAX{'monthly'}>0) { + &log("WARNING: no monthly snapshot for more than 40 days",1); +} +if ($NOW-$yyearly>86400*400 && $yyearly!=0 && $MAX{'yearly'}>0) { + &log("WARNING: no yearly snapshot for more than 400 days",1); +} + + +undef(%SNAPLIST); # read snapshot list for current mode +opendir(DIR,$TARGETDIR); +while ($file=readdir(DIR)) { + my(@stat)=stat("$TARGETDIR/$file"); + $SNAPLIST{$1}=$stat[9] if ($file=~/^$mode\.(\d+)/); +} +closedir(DIR); + + +for $n (sort {$b<=>$a} keys(%SNAPLIST)) { # snapshot cycling + $m=$n+1; + if (-d "$TARGETDIR/$mode.$n" && !-e "$TARGETDIR/$mode.$m") { + + if ($m>=$MAX{$mode}) { + &cmd("rm -rf $TARGETDIR/$mode.$n"); + } else { + &cmd("mv $TARGETDIR/$mode.$n $TARGETDIR/$mode.$m"); + } + } else { + $tmp=""; + $tmp="($TARGETDIR/$mode.$n not found)" if (!-d "$TARGETDIR/$mode.$n"); + $tmp="($TARGETDIR/$mode.$m exists)" if (-e "$TARGETDIR/$mode.$m"); + &log("ERROR: error while snapshot cycling $tmp",1);exit; + } +} + + +$youngest='';$y=0; # search for youngest snapshot +opendir(DIR,$TARGETDIR); +while ($file=readdir(DIR)) { + my(@stat)=stat("$TARGETDIR/$file"); + if ($file=~/^((daily|weekly|monthly|yearly)\.\d+)/) { + if ($stat[9]>$y) { + $y=$stat[9]; + $youngest=$file; + } + } +} +closedir(DIR); + + +&cmd("mkdir -m 0755 -p $TARGETDIR/$mode.tmp/"); # create new $mode.0 +&cmd("touch $TARGETDIR/$mode.tmp/"); + + +if (-d "$TARGETDIR/$mode.tmp") { # build new snapshot + $toterr=0;$totfi=0;$tottfi=0;$totbytes=0;$tottby=0; + + for $srcdir (keys(%SRC)) { + $subname=$SRC{$srcdir}; + + $linkdest=""; + if ($youngest!~/^\s*$/) { + if (-d "$TARGETDIR/$youngest" && -d "$TARGETDIR/$youngest/$subname") { + $linkdest="--link-dest=$TARGETDIR/$youngest/$subname" + } + } + + $cmd="/usr/bin/rsync -av $RSYNCOPTS --no-o --no-g --chmod=ugo=rwX --stats --delete " . + &exf() . " --numeric-ids $linkdest $srcdir/. $TARGETDIR/$mode.tmp/$subname"; + + ($err,$fi,$tfi,$by,$tby,$rt,$try)=&rsync($cmd); + + &log("[$CONFIG] $srcdir,$TARGETDIR ($err,$tfi,$fi,$tby,$by,$rt)",1); + + if ($MY_LOG) { # mysql logging + $sql="INSERT INTO mbackup VALUES(0,now(),'$HOST','$VERSION','$CONFIG',". + "'$srcdir','$TARGETDIR',$fi,$tfi,$by,$tby,$rt,$err,$try)"; + $dbh->do($sql); + } + + if ($HTTP_LOG!~/^\s*$/) { # http logging + $tmp= "MBACKUP,$HOST,$VERSION,$CONFIG,$srcdir,$TARGETDIR,$fi,$tfi,$by,$tby,$rt,$err,$try"; + use LWP::UserAgent; + my $ua = new LWP::UserAgent(); + $response = $ua->post("http://$HTTP_LOG", Content => $tmp); + } + + + $toterr+=$err;$totfi+=$fi;$tottfi+=$tfi;$totby+=$by;$tottby+=$tby;$totrt+=$rt; + } + + if ($toterr==0) { + + &log("[$CONFIG] mbackup successful finished ($tottfi,$totfi,$tby,$by,$totrt)",1); + &cmd("mv $TARGETDIR/$mode.tmp $TARGETDIR/$mode.0"); + + utime $NOW,$NOW,"$TARGETDIR/$mode.0"; + } + +} else { + &log("ERROR: can not access $mode.tmp",1); +} + + +######################################################################################################## SUPPORT + +sub cmd() { # run command + my($cmd)=@_; + &log($cmd); + system($cmd); +} + +sub log() { # write logs + my($str,$forceprint)=@_; + my(@z)=localtime(time());$z[4]+=1;$z[5]-=100;$z[6]+=1; + $ts=sprintf("%02d\.%02d\.%02d %02d\:%02d",$z[3],$z[4],$z[5],$z[2],$z[1]); + + if ($LOGFILE!~/^\s+$/) { + open(LOG,">> $LOGFILE"); + flock(LOG, LOCK_EX); + print LOG "$ts $$/$VERSION/$CONFIG $str\n"; + close(LOG); + } + print "$str\n" if ($opt_v || $forceprint); +} + +sub rsync() { # run rsync + my($rsynccmd)=@_; + + my($files)=0;my($tfi)=0;my($bytes)=0;my($tby)=0;my($error)=0;my($try)=0; + + $runtime=time(); + $retries=0; + + for $try (1..$RSYNCRETRIES) { + $rsynclog=""; + + open(RSYNC,"$rsynccmd |");while() { + print if ($opt_V); + if (/Number of files:\s*([\d\,]+)/) {;$files=$1;$files=~s/,//g;} + if (/Number of regular files transferred:\s*([\d\,]+)/) {;$tfi=$1;$tfi=~s/,//g;} + if (/Total file size:\s*([\d\,]*)\s*bytes/) {;$bytes=$1;$bytes=~s/,//g;} + if (/Total transferred file size:\s*([\d\,]*)\s*bytes/) {;$tby=$1;$tby=~s/,//g;} + } + close(RSYNC); + $error=($? >> 8); + $runtime=time()-$runtime; + + if ($error==0) { + &log("$rsynccmd (successful)"); + } else { + &log("$rsynccmd (error $error in try $try)") + } + + last if ($error==0); + + $retries++; + } + + return ($error,$files,$tfi,$bytes,$tby,$runtime,$retries); +} + +sub exf() { # exclude file + $ex=''; + if ($#EXCLUDE>-1) { + $exfile="/tmp/mbackup.exclude.$CONFIG"; + open(OUT,"> $exfile"); + print OUT "$_\n" for (@EXCLUDE); + close(OUT); + $ex="--exclude-from $exfile --delete-excluded"; + } + return $ex; +} + +sub buildsrc() { # build source list (used in config) + my($base,@paths)=@_; + for $path (@paths) { + if ($path=~/\/([^\/]+)$/) { + $SRC{"$base$path"}=$1; + } + } +} + +sub sc() { # build simple configuration (used in config) + my($uhd,$dirs,$exclude,$grp,$opt)=@_; + + $mode=0; + if ($uhd=~/^([^\.]+)\.(.*)\:\:(.*)$/) {;$user=$3;$config=$1;$domain=$2;$mode=1;} + if ($uhd=~/^(\w+)\@([^\.]+)\.(.*)$/) {;$user=$1;$config=$2;$domain=$3;$mode=2;} + + if ($mode>0) { + %opt=%$opt; + $config=$opt{name} if ($opt{name}); + + @grp=@$grp; + for $g (@grp) { + push(@{$GROUPS{$g}},$config) + } + + if ($REQUESTCONFIG eq $config) { + + $RSYNCOPTS=$opt{rsync} if ($opt{rsync}); + $PING=$opt{ping} if ($opt{ping}); + $TARGETBASE=$opt{target} if ($opt{target}); + + if ($opt{versions}=~/(\d+):(\d+):(\d+):(\d+)/) { + $MAX{'daily'}=$1; + $MAX{'weekly'}=$2; + $MAX{'monthly'}=$3; + $MAX{'yearly'}=$4; + $FLAT=0; + } else { + $FLAT=1; + } + + @DIRS=@$dirs; + @EXCLUDE=@$exclude; + $TARGETDIR="$TARGETBASE/$config"; + for $path (@DIRS) { + $tpath=$path;$tpath=~s/^\s*\///;$tpath=~s/\//\./g; + $SRC{"$uhd$path"}=$tpath if ($mode==1); + $SRC{"$uhd:$path"}=$tpath if ($mode==2); + } + + $CONFIG=$REQUESTCONFIG; + } + } +} + +sub help() { # help +print "mbackup v$VERSION\n"; +print <<'ENDOFHELP'; + + USAGE: + ------ + mbackup [-v] [-V] [-DWMY] + mbackup -h + + -D force daily mode + -W force weekly mode + -M force monthly mode + -Y force yearly mode + -v verbose output + -V very verbose output + -f force creation of target directory + -h this help + + CONFIG FILE (/db/etc/mbackup.conf) GLOBAL OPTIONS: + -------------------------------------------------- + $LOGFILE = "/var/log/mbackup.log"; # logfile location + + $TARGETBASE = "/data/backup"; # targetbase for simple config + + $HTTP_LOG = 'log.mxwx.org'; # http logging server + + $MY_LOG = 1; # enable/disable mysql logging (deprecated) + $MY_HOST = 'localhost'; + $MY_USER = ''; + $MY_PASSWD = ''; + $MY_DB = ''; + + SIMPLE BACKUP JOB CONFIGURATION (/db/etc/mbackup.conf): + ------------------------------------------------------- + + &sc(target,[paths],[exclude],[groups],{ option=>value, .. } + + example: + + &sc('root@host.domain',['/etc','/var','/home'],['/lib/lxcfs'],['all']); + &sc('host.domain::root',['/etc','/var','/home'],[],['all'], { rsync=>"-e 'ssh -p 2234'" }); + &sc('root@host.domain',['/etc','/var','/home'],[],[] { versions=>'7:4:12:3' }); + + options: + + name => 'name' # set configuration name + rsync => 'rsync options' # set additional rsync options + ping => 'ip address' # apply ping test before backup + version => 'daily:weekly:monthly:yearly' # define backup versioning + target => '/path/to/mbackup' # define backup destination + + BACKUP JOB CONFIGURATION (/db/etc/mbackup.conf): + ------------------------------------------------ + if ($REQUESTCONFIG eq 'NAME') { # basic backup job config + + $CONFIG=$REQUESTCONFIG; + } + + if ($REQUESTCONFIG eq 'NAME') { # backup group definition + @GROUP=('NAME1','NAME2',...); + $CONFIG=$REQUESTCONFIG; + } + + push(@{$GROUPS{'all'}},'NAME'); # add config to group + + BACKUP JOB OPTIONS: + ------------------- + # backup target definition (use only once) + $TARGETDIR='/backup/NAME' # local traget directory + $TARGETDIR='10.0.1.1::root/backup/NAME' # rsync protocol target + $TARGETDIR='root@10.0.1.1:/backup/NAME' # ssh traget directory + + + # backup source definition (multiple allowd, different keys required) + $SRC{'/etc'} = 'etc1'; # local source + $SRC{'10.0.1.1::root/etc'} = 'etc2'; # remote source (rsync protocol) + $SRC{'root@10.0.1.1:/etc'} = 'etc3'; # remote source (ssh) + + # define eculsions (absolut path definitions from source path) + @EXCLUDE=('/path1','/path2',...); + + # define number of backups to keep, at least one value must be greater than 0 + $MAX{'daily'} = 7; # keep n daily backup (default=7) + $MAX{'weekly'} = 4; # keep n weekly backup (default=4) + $MAX{'monthly'} = 12; # keep n monthly backup (default=12) + $MAX{'yearly'} = 3; # keep n yearly backup (default=3) + + $FLAT=1; # only keep one backup (default=0) + $PING='10.0.1.1'; # perform ping test before backup run + $RSYNCOPTS="-e 'ssh -p 2234'"; # add extra options for rsync + $RSYNCRETRIES=3; # number of retries if rsync fails + + MYSQL LOGGING TABLE: + -------------------- + CREATE TABLE `mbackup` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `ts` timestamp NULL DEFAULT NULL, + `host` varchar(255) DEFAULT NULL, + `version` varchar(255) DEFAULT NULL, + `config` varchar(255) DEFAULT NULL, + `source` varchar(255) DEFAULT NULL, + `target` varchar(255) DEFAULT NULL, + `files` bigint(11) DEFAULT NULL, + `transfiles` bigint(11) DEFAULT NULL, + `bytes` bigint(11) DEFAULT NULL, + `transbytes` bigint(11) DEFAULT NULL, + `runtime` int(11) DEFAULT NULL, + `error` int(11) DEFAULT NULL, + `retries` int(11) DEFAULT '0', + PRIMARY KEY (`id`) + ) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +ENDOFHELP +exit; +} + +############################################################################################################ END + diff --git a/files/mgsh b/files/mgsh new file mode 100755 index 0000000..dcb9970 --- /dev/null +++ b/files/mgsh @@ -0,0 +1,525 @@ +#!/usr/bin/perl +################################################################################################ mgsh (mwx'2023) +use Sys::Hostname qw(hostname);use Socket; +use Config; +use Time::HiRes qw( usleep ualarm gettimeofday tv_interval ); +use File::Compare; + +$VERSION='3.1.5'; +$INFO="mwx'2023"; + +$BASE="$ENV{HOME}/Source"; +$BASE="/db/src" if ($Config{osname}=~/linux/i); +die "$BASE not found" if (!-d $BASE); + +$PRJ=$ARGV[0] if (-d "$BASE/$ARGV[0]"); + +$GITHOST = '141.14.128.56'; +$GITPORT = '2234'; +$GITUSER = 'git'; +$GITKEY = 'mgit_rsa'; +$GITPATH ="/home/git"; + +$URL = "ssh://$GITUSER\@$GITHOST:$GITPORT$GITPATH"; +$SSH = "ssh -p $GITPORT $GITUSER\@$GITHOST"; + +$IP = inet_ntoa( (gethostbyname(hostname()))[4] ); +$HOST=hostname();$HOST=~s/([^\.]+)\..*$/$1/; +$USER=getpwuid( $< ); + +use Date::Parse; # date hashes +@D=('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); +@M=('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); + + +&cmd("git config --global user.name 'Michael Wesemann'",1); # git settings +&cmd("git config --global user.email mike\@pstbx.org",1); +&cmd("git config --global push.default matching",1); + +print "mgsh v$VERSION $INFO, $BASE\n"; # ready to start + +for (;;) { # main mgsh loop + if ($PRJ!~/^\s*$/ && -d "$BASE/$PRJ") { # set current working directory/project + + $DIR="$BASE/$PRJ"; + + $BPLSTATE=''; + if (-l "$DIR/build.pl") { + chomp($rlf=`readlink $DIR/build.pl`); + $BPLSTATE='/OFF' if ($rlf=~/\.off$/); + } + + $p=$1 if ($BASE=~/\/([^\/]+)$/);$prompt="$p/$PRJ/$I$BPLSTATE"; + } else { + $DIR="$BASE"; + $p=$1 if ($BASE=~/\/([^\/]+)$/);$prompt="$p"; + } + + + chomp($REMURL= `cd $DIR; git config remote.origin.url`); + $REPO=$1 if ($REMURL=~/$url\/(.*)\.git\/?$/); + + + $prompt=~s/\/\s*$//;$cmd=&readline("$prompt > ","",1); # read command from command line + + + @tmpcmd=split(' ',$cmd);undef(@cmd);undef(%OPT); # get commandline options + for (@tmpcmd) {if (/\-(\w)/) {$OPT{$1}="-$1";} else {push(@cmd,$_);}} + + if ($cmd[0] eq 'dist') { ########################################################################### list [-a] + $CP='/bin/cp'; + $CP='/opt/homebrew/bin/gcp' if (-f '/opt/homebrew/bin/gcp'); + + $DDIR="$BASE/dist/$PRJ"; + $DDIR=$cmd[1] if ($cmd[1]!~/^\s*$/); + + if (-d $DDIR) { + chdir($DIR); + $n=0; + open(LS,"cd $DIR;git ls-files |"); + while() { + chomp(); + if (!/^private/) { + if (compare($_,"$DDIR/$_")!=0) { + print "$_\n"; + cmd("$CP --parents $_ $DDIR",1); + $n++; + } + } + } + print "$n files copied to $DDIR\n"; + } else { + print "dist path not found ($DDIR)\n"; + } + + close(LS); + } + + elsif ($cmd[0] eq 'list') { ########################################################################### list [-a] + + $path=".";$path="./archive" if ($OPT{a}); + + open(LS,"$SSH /bin/ls -ltr $path |"); + while() { + if ($cmd[1]=~/^\s*$/ || /$cmd[1]/i) { + if ($OPT{a}) { + print "$1\n" if (/git\s+git\s+\d+\s+(.*)\.git.tar.gz$/); + } else { + print "$1\n" if (/git\s+git\s+\d+\s+(.*)\.git$/); + } + } + } + close(LS); + + } + + elsif ($cmd[0] eq 'show') { ############################################################################# show + $prj=$PRJ if ($PRJ!~/^\s*$/); + $prj=$cmd[1] if ($cmd[1]!~/^\s*$/); + + $path="."; + $found=0; + open(LS,"$SSH /bin/ls $path |"); + while() { + $found++ if (/^$prj\.git$/); + } + close(LS); + + if ($found==1) { + open($FH,"$SSH \"cd $GITPATH/$prj\.git && git log --reverse --format='%h %cd %s'\" |"); + &repolog($FH); + } else { + print "repository not found\n"; + } + + } + + elsif ($cmd[0] eq 'log' && $PRJ!~/^\s*$/) { ############################################################## log + if (-d "$DIR/.git") { + open($FH,"cd $DIR;git log --reverse --format='%h %cd %s' |"); + &repolog($FH); + } else { + print "repository not found"; + } + } + + elsif ($cmd[0] eq 'push' && $PRJ!~/^\s*$/) { ################################################## push [comment] + + if (-f "$DIR/push.pl") { + &shell("perl $DIR/push.pl"); + } + + $comment='';$comment.="$cmd[$_] " for (1..$#cmd);$comment=~s/\s+$//; + $comment=~s/\s{2}/ /g; + + if (-d "$DIR/.git") { + &shell("git add --all ."); + $msg="[$USER\@$HOST] $comment";$msg=~s/^\s+//;$msg=~s/\s+$//; + &shell("git commit -m '$msg'"); + &shell("git push"); + &shell("$SSH touch $GITPATH/${PRJ}.git"); + } else { + print "error, no repository (.git) found"; + } + + } + + elsif ($cmd[0] eq 'edit' && $PRJ!~/^\s*$/) { ################################################### edit [number] + + $num=10;$num=$cmd[1] if ($cmd[1]=~/^\d+$/); + if (-d "$DIR/.git") { + &shell("git rebase -i HEAD~$num"); + &shell("git push --force"); + } else { + print "error, no repository (.git) found"; + } + + } + + elsif ($cmd[0] eq 'archive' && $PRJ!~/^\s*$/) { ############################################ archive [comment] + $comment='';$comment.="$cmd[$_] " for (1..$#cmd);$comment=~s/\s+$//; + $comment=~s/[\,\;\:\\\/\=\'\"\|\?\>\<\-]+/ /g; + $comment=~s/\s{2}/ /g; + $comment=~s/\s+/\_/g; + + my(@z)=localtime(time());$z[4]+=1;$z[5]-=100;$z[6]+=1; + $z=sprintf("%02d%02d%02d.%02d%02d",$z[3],$z[4],$z[5],$z[2],$z[1]); + + if ($comment=~/^\s*$/) { + &shell(sprintf("$SSH 'cp -r ${PRJ}.git archive/${PRJ}_$z.git'")); + &shell(sprintf("$SSH 'cd archive;tar cvzf ${PRJ}_$z.git.tar.gz ${PRJ}_$z.git'")); + &shell("$SSH 'rm -rf archive/${PRJ}_$z.git'"); + } else { + &shell(sprintf("$SSH cp -r ${PRJ}.git archive/${PRJ}_${z}_$comment.git")); + &shell(sprintf("$SSH 'cd archive;tar cvzf ${PRJ}_${z}_$comment.git.tar.gz ${PRJ}_${z}_$comment.git'")); + &shell("$SSH 'rm -rf archive/${PRJ}_${z}_$comment.git'"); + } + } + + elsif ($cmd[0] eq 'init' && $PRJ!~/^\s*$/) { ############################################################ init + + &shell("perl $DIR/push.pl") if (-f "$DIR/push.pl"); + if ($REPO=~/^\s*$/ || yesno('overwrite existing repository?',0)) { + &shell("$SSH 'rm -rf $GITPATH/${PRJ}.git'"); + &shell("$SSH 'mkdir $GITPATH/${PRJ}.git;chdir $GITPATH/${PRJ}.git;git --bare init'"); + + if (!-f ".gitignore" || yesno('overwrite existing .gitignore?',0)) { + open(OUT,"> .gitignore"); + print OUT &gitignore(); + close(OUT); + } + + &shell("rm -rf .git"); + &shell("git init"); + &shell("git remote add origin $URL/${PRJ}.git/"); + &shell("git add ."); + &shell("git commit -m 'initial commit [$IP,$USER]'"); + &shell("git push -u origin master"); + } + } + + elsif ($cmd[0] eq 'login') { ########################################################################### login + &cmd("$SSH"); + } + + elsif ($cmd[0] eq 'cd' && $cmd[1]!~/^\./) { ############################################################### cd + $PRJ=''; + $PRJ=$cmd[1] if (-d "$BASE/$cmd[1]"); + } + + elsif ($cmd[0] eq 'checkout' && $PRJ!~/^\s*$/) { ###################################### checkout [git options] + &shell("git checkout $cmd[1]"); + } + + elsif ($cmd[0] eq 'clone') { ###################################################################### clone [-a] + $prj=$PRJ if ($PRJ!~/^\s*$/); + $prj=$cmd[1] if ($cmd[1]!~/^\s*$/); + + $DIR="$BASE";chdir($DIR); + + my($path)=".";my($path)="./archive" if ($OPT{a}); + my($found)=0; + open(LS,"$SSH /bin/ls $path |"); + while() { + if ($OPT{a}) { + $found++ if (/^$prj\.git.tar.gz$/); + } else { + $found++ if (/^$prj\.git$/); + } + } + close(LS); + + if ($found==1) { + if (-d "$DIR/$prj") { + if (yesno('overwrite existing directory?',0)) { + &cmd("rm -rf $DIR/$prj") + } else { + goto exitclone; + } + } + + &shell("git clone $URL/$prj.git") if (!$OPT{a}); + if ($OPT{a}) { + &cmd("$SSH 'cd archive;tar xvzf $prj.git.tar.gz'"); + &cmd("git clone $URL/archive/$prj.git"); + &cmd("$SSH 'rm -rf archive/$prj.git'"); + } + } else { + print "repository not found, try 'list [-a]'"; + } + + $PRJ=$prj if (-d "$BASE/$prj"); + exitclone:; + } + + elsif ($cmd[0] eq 'cloneall') { ##################################################################### cloneall + $prj=$PRJ if ($PRJ!~/^\s*$/); + $prj=$cmd[1] if ($cmd[1]!~/^\s*$/); + + $DIR="$BASE";chdir($DIR); + + my($path)=".";my($path)="./archive" if ($OPT{a}); + my($found)=0; + open(LS,"$SSH /bin/ls $path |"); + while() { + if (/^(.*)\.git$/) { + print "-$1-\n"; + &shell("git clone $URL/$1.git"); + + } + } + close(LS); + } + + elsif ($cmd[0] eq 'open' || $cmd[0] eq 'view'){ ######################################################### open + $prj=$PRJ if ($PRJ!~/^\s*$/); + $prj=$cmd[1] if ($cmd[1]!~/^\s*$/); + + if (-d "$BASE/$prj") { + $DIR="$BASE/$prj";chdir($DIR); + + $xws='';$xprj='';opendir(DIR,$DIR); + while($file=readdir(DIR)) { + $xws=$file if ($file=~/.xcworkspace$/); + $xprj=$file if ($file=~/.xcodeproj$/); + } + close(DIR); + + $xprj='' if ($xws!~/^\s*$/ && $xprj!~/^\s*$/); + + &shell("open $xws") if ($xws!~/^\s*$/ && -d "$DIR/$xws"); + &shell("open $xprj") if ($xprj!~/^\s*$/ && -d "$DIR/$xprj"); + + &shell("coda $DIR") if ($xws=~/^\s*$/ && $xprj=~/^\s*$/); + + $PRJ=$prj if ($cmd[0] eq 'open'); + + } else { + print "not found\n"; + } + } + + elsif ($cmd[0] eq 'count') { ##################################################################### count lines + &count($DIR); + } + + elsif ($cmd[0] eq 'do') { ############################################################### execute extra script + &shell("perl $DIR/do.$cmd[1].pl") if (-f "$DIR/do.$cmd[1].pl"); + } + + elsif ($cmd[0] eq 'tag') { # manage tag + if ($cmd[1] eq 'add' && $cmd[2]!~/^\s*$/) { + &shell("git tag -a '$cmd[2]' -m '$cmd[2]'"); + &shell("git push origin '$cmd[2]'"); + } elsif ($cmd[1] eq 'checkout' && $cmd[2]!~/^\s*$/) { + &shell("git checkout 'tags/$cmd[2]'"); + } elsif ($cmd[1] eq 'delete' && $cmd[2]!~/^\s*$/) { + &shell("git tag -d '$cmd[2]'"); + &shell("git push origin ':refs/tags/$cmd[2]'"); + } else { + if ($cmd[1]!~/^\s*$/) { + print "unkown tag subcommand\n"; + } else { + &shell("git tag -l --format=\"%(taggerdate:short): %(refname:short)\""); + } + } + } + + elsif ($cmd[0] eq 'help') { ############################################################################# help + +print <<"ENDOFHELP"; + +mgsh (git shell) $VERSION $INFO, builtin commands: + + cd [project] change project + open [project] open project + init make new repository from current directory + push [comment] push changes to git server + edit [number] edit last [number] commits (default is 10) + clone [-a] clone repository from git server (-a for archive) + cloneall> clone all repository from git server + checkout [git options] forward checkout to git + log show log + archive [comment] archive current repository + list [-a] [pattern] list repositories on git server (-a for archive) + show show repository log on git server + dist cp changed files to other directory/repository + login connect to git server + do execute extra script with name do..pl + count count lines in project + tag show tags + tag add add tag + tag checkout checkout tag + tag delete delete tag + +ENDOFHELP + + } + + else { ###################################################################### forward unknown command to shell + &shell($cmd) if ($cmd!~/^\s*$/); + } + +} + +######################################################################################################## SUPPORT + +sub shell() { # shell + my($cmd)=@_; + chdir $DIR; + system($cmd); +} + +sub cmd() { # execute command + my($cmd,$quiet)=@_; + print "$cmd\n" if (!$quiet); + system($cmd); +} + +sub readline { # readline + my($prompt,$input,$mode)=@_; use Term::ReadLine; + BEGIN{ $ENV{PERL_RL} = 'Perl o=0' }; + + if (!$term) { + $term = new Term::ReadLine 'term'; + open(IN,"$BASE/.mgsh_history"); + while() { + chomp(); + push(@history,$_); + } + close(IN); + $term->SetHistory(@history); + } + + my($txt)=$term->readline($prompt,$input); + + my(@history)=$term->GetHistory(); + shift(@history) while($#history>=10); + open(OUT,"> $BASE/.mgsh_history"); + print OUT "$_\n" for (@history); + close(OUT); + + return $txt; +} + +sub yesno { # request yes/no answer + my($prom,$def)=@_; + my($ans); + if ($def) {;$ans=&getkey("$prom Y/n ? ");} + else {;$ans=&getkey("$prom y/N ? ");} + if ($ans=~/^\s*$/) { + if ($def) {;return(1);} + else {;return(0);} + } + if ($ans=~/^\s*y\s*$/i || $ans=~/^\s*yes\s*$/i) { + return 1; + } + return 0; +} + +sub getkey { # get key from keyboard + $|=1; + print "$_[0]"; + system "stty", '-icanon', '-echo', 'eol', "\001"; + $key = getc(STDIN);$key=~s/[\r\n\t]//g; + system "stty", 'icanon', 'echo', 'eol', "^@"; + print "$key\n"; + return $key; +} + +sub count() { # count lines in project + my($dir)=@_; + use File::Find; + $lines=0; + find(\&counting,$dir); + sub counting { + $f=$File::Find::name; + if (-f $f) { + if ($f=~/\.[hmc]$/ || $f=~/\.xib$/ || $f=~/\.lm$/ || $f=~/\.ym$/ || $f=~/\.pl$/ || $f=~/\.php$/ || + (-T $f && $f=~/\/bin\//)) { + open(WC,"/usr/bin/wc -l '$f' |"); + while() {; + $lines+=$1 if (/^\s*(\d*)\s+$f/); + } + close(WC); + } + + } + } + print "$lines lines total in $PRJ\n"; +} + +sub repolog() { # show repository log + my($FH)=@_; + my($o)='';my($os)='';my($oss)='';my($n)=0;my($ns)=0; + my($z)='';my($zs)='';my($zss)=''; + + while(<$FH>) { + chomp(); + @tmp=split(' '); + $t=str2time($tmp[1]); + my(@z)=localtime($t);$z[4]+=1;$z[5]+=1900;$z[6]+=1; + + if (time()-$t<86400) { + $z=sprintf(" %02d\:%02d",$z[2],$z[1]); + $zs=sprintf(" %02d\:%02d",$z[2],$z[1]); + $zss=sprintf("%02d\:%02d",$z[2],$z[1]); + } elsif (time()-$t<86400*7) { + $z=sprintf(" %s, %02d\:%02d",$D[$z[6]-1],$z[2],$z[1]); + $zs=sprintf("%s, %02d\:%02d",$D[$z[6]-1],$z[2],$z[1]); + $ns++; + } else { + $z=sprintf("%s, %02d %s %4d, %02d\:%02d",$D[$z[6]-1],$z[3],$M[$z[4]-1],$z[5],$z[2],$z[1]); + $n++; + } + + $o.="$tmp[0] $z $tmp[2]\n"; + $os.="$tmp[0] $zs $tmp[2]\n"; + $oss.="$tmp[0] $zss $tmp[2]\n"; + } + + if ($n==0 && $ns==0) { + print $oss; + } elsif ($n==0 && $ns>0) { + print $os; + } else { + print $o; + } +} + +sub gitignore() { +return << "ENDOFGITIGNORE"; +.DS_Store +.AppleDouble +.LSOverride +._* +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +ENDOFGITIGNORE +} + + +############################################################################################################ END diff --git a/files/mybackup b/files/mybackup new file mode 100755 index 0000000..c40dc0b --- /dev/null +++ b/files/mybackup @@ -0,0 +1,195 @@ +#!/usr/bin/perl +################################################################################ mysql/mariadb backup (mwx'2021) +use Getopt::Std;getopts('bza'); +use DBI; +use Term::ReadKey; + +$VERSION='4.0.0'; + +$HOST = 'localhost'; # settings +$USER = 'mybackup'; +$PASSWD = 'iexae3aitathoo4k'; +$PATH = '/db/backup/mysql'; +$KEEPDAILYBACKUPS = 21; + +$TAR = "/bin/tar"; +$RM = "/bin/rm"; +$MYSQLDUMP = "/usr/bin/mysqldump"; +$GZIP = "/bin/gzip"; + + +if (!$opt_a && !$opt_b && !$opt_z) { # show usage +print <<"ENDOFHELP"; +mybackup, MySQL/MariaDB backup, mwx'2021, v$VERSION +usage: mybackup -a add backup user to db (root password required) + mybackup -b run database backup + mybackup -z run database backup and compress output +ENDOFHELP +exit(0); +} + +if ($opt_a) { # add backup user to db + use Term::ReadPassword; + $rootdbpw = read_password('Enter password: '); + $dbh=DBI->connect("DBI:mysql:mysql:localhost:","root",$rootdbpw,{RaiseError=>1,PrintError=>1}); + + $dbh->do("CREATE USER 'mybackup' IDENTIFIED BY '$PASSWD'"); + $dbh->do("GRANT SELECT, SHOW VIEW, LOCK TABLES, RELOAD,REPLICATION CLIENT ON *.* TO 'mybackup'"); + +# +# +# +# CREATE USER 'mybackup' IDENTIFIED BY 'Yooch0esh9Ah'; +# +# +# $sth=$dbh->prepare("SHOW COLUMNS FROM user");$sth->execute; # find authentication fields +# $HASPW=0;$HASAS=0; +# while ($dat = $sth->fetchrow_hashref) { +# $HASPW=1 if ($$dat{Field} eq 'Password'); +# $HASAS=1 if ($$dat{Field} eq 'authentication_string'); +# } +# +# $sql="INSERT INTO user SET User='$USER',Host='localhost',"; +# $sql.="Password=password('$PASSWD')," if ($HASPW); +# $sql.="authentication_string=password('$PASSWD')," if ($HASAS); +# $sql.="ssl_cipher='',x509_issuer='',x509_subject='',". +# "Select_priv='Y',Reload_priv='Y',Lock_tables_priv='Y',Show_view_priv='Y',Process_priv='Y'"; +# +# $dbh->do($sql); + $dbh->do("flush privileges"); + + if (&yesno('Write /root/.my.cnf file',1)) { + system("rm -f /root/.my.cnf"); + open(OUT,"> /root/.my.cnf"); + print OUT "[client]\nuser=root\npassword=$rootdbpw\n[mysqldump]\nuser=mybackup\npassword=$PASSWD\n"; + close(OUT); + system("chmod 600 /root/.my.cnf"); + } + + &setupcron(); + + exit; +} + +&cleanup(); + +@DBS=&autogetdbs(); + +my(@z)=localtime(time());$z[4]+=1;$z[6]+=1;$z[5]-=100; +$z=sprintf("%02d%02d%02d%02d%02d%02d",$z[3],$z[4],$z[5],$z[2],$z[1],$z[0]); + + +if (!-d "$PATH/$z") { # make target dir + mkdir("$PATH/$z",448); +} + + +for $db (@DBS) { # dump databaeses + if ($db ne 'information_schema' && $db ne 'performance_schema' && $db ne 'sys') { + my($fdb)=$db;$fdb=~s/\s/\./g; + if (!$IGNOREDB{$db}) { + if ($DBPARAM{$db}) {;$db=$DBPARAM{$db};} + &cmd("$MYSQLDUMP -h $HOST -u $USER -f -F -R --skip-extended-insert $db >$PATH/$z/$fdb.mysql"); + } + } +} + + +$cmd="$MYSQLDUMP -h $HOST -u $USER -c -f -F -R --skip-extended-insert -A -v >$PATH/$z.mysql"; +&cmd($cmd); + + +&cmd("$GZIP $PATH/$z.mysql"); +chdir($PATH); +if (-d "$PATH/$z" && $opt_z) { + &cmd("$TAR czvf $z.tar.gz $z"); + &cmd("$RM -rf $PATH/$z"); +} + +######################################################################################################## SUPPORT + +sub cleanup() { + use Date::Parse; + + opendir(DIR,"$PATH"); + while($file=readdir(DIR)) { + + if (-f "$PATH/$file" && $file=~/(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/) { + $m=$1; + + $a=$3+2000; + $time = str2time("$a/$2/$1 $4:$5:$6"); + + my(@z)=localtime($time);$z[4]+=1;$z[5]-=100;$z[6]+=1; + $z=sprintf("%02d\.%02d\.%02d %02d\:%02d\:%02d",$z[3],$z[4],$z[5],$z[2],$z[1],$z[0]); + + $t=(time()-$time)/86400; + + if ($m!=1 && $t>$KEEPDAILYBACKUPS) { + &cmd("/bin/rm -f $PATH/$file") if (-f "$PATH/$file"); + } + } + } +} + +sub setupcron() { + open(CRON,"crontab -l |"); + while() { + chomp(); + push(@CRON,$_) if (!/\/db\/bin\/mybackup/); + } + + push(@CRON,"0 12 * * * /db/bin/mybackup -z > /dev/null 2>&1"); + + open(OUT,"> /tmp/cron.$$"); + for (@CRON) { + print OUT "$_\n"; + } + close(OUT); + system("/usr/bin/crontab /tmp/cron.$$"); + system("rm -f /tmp/cron.$$"); +} + +sub cmd() { + my($cmd)=@_; + print "$cmd\n"; + system($cmd); +} + +sub autogetdbs() { + my(@dbs); + $dbh=DBI->connect("DBI:mysql::$HOST:",$USER,$PASSWD,{RaiseError=>1,PrintError=>1}); + + $sth=$dbh->prepare("SHOW DATABASES");$sth->execute ; + while ($dat = $sth->fetchrow_hashref) { + push(@dbs,$$dat{Database}); + } + return (@dbs); +} + +sub yesno { + my($prom,$def)=@_; + my($ans); + if ($def) {;$ans=&getkey("$prom Y/n ? ");} + else {;$ans=&getkey("$prom y/N ? ");} + if ($ans=~/^\s*$/) { + if ($def) {;return(1);} + else {;return(0);} + } + if ($ans=~/^\s*y\s*$/i || $ans=~/^\s*yes\s*$/i) { + return 1; + } + return 0; +} + +sub getkey { + $|=1; + print "$_[0]"; + system "stty", '-icanon', '-echo', 'eol', "\001"; + $key = getc(STDIN);$key=~s/[\r\n\t]//g; + system "stty", 'icanon', 'echo', 'eol', "^@"; + print "$key\n"; + return $key; +} + +############################################################################################################ END diff --git a/files/myuser b/files/myuser new file mode 100755 index 0000000..6d75c43 --- /dev/null +++ b/files/myuser @@ -0,0 +1,43 @@ +#!/usr/bin/perl +########################################################################## mysql/mariadb user manager (mwx'2021) +use DBI; +use Getopt::Std;getopts('hd:x'); + +$VERSION='4.0.0'; + +&help() if ($ARGV[0]=~/^\s*$/ || $opt_h); + +$USER=$DB=$ARGV[0]; +$DB=$opt_d if ($opt_d!~/^\s*$/); + +$PW=sprintf("$USER%03d",int(rand(100000))); + +my $dsn = "DBI:mysql:mysql;mysql_read_default_file=$ENV{HOME}/.my.cnf"; +$dbh=DBI->connect($dsn,undef,undef,{PrintError=>1}); + +&sqldo("CREATE DATABASE IF NOT EXISTS $DB") if (!$opt_x); +&sqldo("DROP USER IF EXISTS '$USER'"); +&sqldo("CREATE USER '$USER' IDENTIFIED BY '$PW'"); +&sqldo("GRANT ALL PRIVILEGES ON $DB.* TO '$USER'"); + +sub sqldo() { + my($sql)=@_; + print "$sql\n"; + $dbh->do($sql); +} + +sub help() { +print <<"ENDOFHELP"; + +myuser - mariadb user manager (v$VERSION) + +myuser add user and database with the same name to mariadb +myuser -d add user and database to mariadb +myuser -x add only user to mariadb + +ENDOFHELP +exit(); +} + +############################################################################################################ END + diff --git a/files/psmem b/files/psmem new file mode 100755 index 0000000..074e824 --- /dev/null +++ b/files/psmem @@ -0,0 +1,611 @@ +#!/usr/bin/env python + +# Try to determine how much RAM is currently being used per program. +# Note per _program_, not per process. So for example this script +# will report RAM used by all httpd process together. In detail it reports: +# sum(private RAM for program processes) + sum(Shared RAM for program processes) +# The shared RAM is problematic to calculate, and this script automatically +# selects the most accurate method available for your kernel. + +# Licence: LGPLv2 +# Author: P@draigBrady.com +# Source: http://www.pixelbeat.org/scripts/ps_mem.py + +# V1.0 06 Jul 2005 Initial release +# V1.1 11 Aug 2006 root permission required for accuracy +# V1.2 08 Nov 2006 Add total to output +# Use KiB,MiB,... for units rather than K,M,... +# V1.3 22 Nov 2006 Ignore shared col from /proc/$pid/statm for +# 2.6 kernels up to and including 2.6.9. +# There it represented the total file backed extent +# V1.4 23 Nov 2006 Remove total from output as it's meaningless +# (the shared values overlap with other programs). +# Display the shared column. This extra info is +# useful, especially as it overlaps between programs. +# V1.5 26 Mar 2007 Remove redundant recursion from human() +# V1.6 05 Jun 2007 Also report number of processes with a given name. +# Patch from riccardo.murri@gmail.com +# V1.7 20 Sep 2007 Use PSS from /proc/$pid/smaps if available, which +# fixes some over-estimation and allows totalling. +# Enumerate the PIDs directly rather than using ps, +# which fixes the possible race between reading +# RSS with ps, and shared memory with this program. +# Also we can show non truncated command names. +# V1.8 28 Sep 2007 More accurate matching for stats in /proc/$pid/smaps +# as otherwise could match libraries causing a crash. +# Patch from patrice.bouchand.fedora@gmail.com +# V1.9 20 Feb 2008 Fix invalid values reported when PSS is available. +# Reported by Andrey Borzenkov +# V3.9 07 Mar 2017 +# http://github.com/pixelb/scripts/commits/master/scripts/ps_mem.py + +# Notes: +# +# All interpreted programs where the interpreter is started +# by the shell or with env, will be merged to the interpreter +# (as that's what's given to exec). For e.g. all python programs +# starting with "#!/usr/bin/env python" will be grouped under python. +# You can change this by using the full command line but that will +# have the undesirable affect of splitting up programs started with +# differing parameters (for e.g. mingetty tty[1-6]). +# +# For 2.6 kernels up to and including 2.6.13 and later 2.4 redhat kernels +# (rmap vm without smaps) it can not be accurately determined how many pages +# are shared between processes in general or within a program in our case: +# http://lkml.org/lkml/2005/7/6/250 +# A warning is printed if overestimation is possible. +# In addition for 2.6 kernels up to 2.6.9 inclusive, the shared +# value in /proc/$pid/statm is the total file-backed extent of a process. +# We ignore that, introducing more overestimation, again printing a warning. +# Since kernel 2.6.23-rc8-mm1 PSS is available in smaps, which allows +# us to calculate a more accurate value for the total RAM used by programs. +# +# Programs that use CLONE_VM without CLONE_THREAD are discounted by assuming +# they're the only programs that have the same /proc/$PID/smaps file for +# each instance. This will fail if there are multiple real instances of a +# program that then use CLONE_VM without CLONE_THREAD, or if a clone changes +# its memory map while we're checksumming each /proc/$PID/smaps. +# +# I don't take account of memory allocated for a program +# by other programs. For e.g. memory used in the X server for +# a program could be determined, but is not. +# +# FreeBSD is supported if linprocfs is mounted at /compat/linux/proc/ +# FreeBSD 8.0 supports up to a level of Linux 2.6.16 + +import getopt +import time +import errno +import os +import sys + +# The following exits cleanly on Ctrl-C or EPIPE +# while treating other exceptions as before. +def std_exceptions(etype, value, tb): + sys.excepthook = sys.__excepthook__ + if issubclass(etype, KeyboardInterrupt): + pass + elif issubclass(etype, IOError) and value.errno == errno.EPIPE: + pass + else: + sys.__excepthook__(etype, value, tb) +sys.excepthook = std_exceptions + +# +# Define some global variables +# + +PAGESIZE = os.sysconf("SC_PAGE_SIZE") / 1024 #KiB +our_pid = os.getpid() + +have_pss = 0 +have_swap_pss = 0 + +class Proc: + def __init__(self): + uname = os.uname() + if uname[0] == "FreeBSD": + self.proc = '/compat/linux/proc' + else: + self.proc = '/proc' + + def path(self, *args): + return os.path.join(self.proc, *(str(a) for a in args)) + + def open(self, *args): + try: + if sys.version_info < (3,): + return open(self.path(*args)) + else: + return open(self.path(*args), errors='ignore') + except (IOError, OSError): + val = sys.exc_info()[1] + if (val.errno == errno.ENOENT or # kernel thread or process gone + val.errno == errno.EPERM or + val.errno == errno.EACCES): + raise LookupError + raise + +proc = Proc() + + +# +# Functions +# + +def parse_options(): + try: + long_options = [ + 'split-args', + 'help', + 'total', + 'discriminate-by-pid', + 'swap' + ] + opts, args = getopt.getopt(sys.argv[1:], "shtdSp:w:", long_options) + except getopt.GetoptError: + sys.stderr.write(help()) + sys.exit(3) + + if len(args): + sys.stderr.write("Extraneous arguments: %s\n" % args) + sys.exit(3) + + # ps_mem.py options + split_args = False + pids_to_show = None + discriminate_by_pid = False + show_swap = False + watch = None + only_total = False + + for o, a in opts: + if o in ('-s', '--split-args'): + split_args = True + if o in ('-t', '--total'): + only_total = True + if o in ('-d', '--discriminate-by-pid'): + discriminate_by_pid = True + if o in ('-S', '--swap'): + show_swap = True + if o in ('-h', '--help'): + sys.stdout.write(help()) + sys.exit(0) + if o in ('-p',): + try: + pids_to_show = [int(x) for x in a.split(',')] + except: + sys.stderr.write(help()) + sys.exit(3) + if o in ('-w',): + try: + watch = int(a) + except: + sys.stderr.write(help()) + sys.exit(3) + + return ( + split_args, + pids_to_show, + watch, + only_total, + discriminate_by_pid, + show_swap + ) + + +def help(): + help_msg = 'Usage: ps_mem [OPTION]...\n' \ + 'Show program core memory usage\n' \ + '\n' \ + ' -h, -help Show this help\n' \ + ' -p [,pid2,...pidN] Only show memory usage PIDs in the '\ + 'specified list\n' \ + ' -s, --split-args Show and separate by, all command line'\ + ' arguments\n' \ + ' -t, --total Show only the total value\n' \ + ' -d, --discriminate-by-pid Show by process rather than by program\n' \ + ' -S, --swap Show swap information\n' \ + ' -w Measure and show process memory every'\ + ' N seconds\n' + + return help_msg + + +# (major,minor,release) +def kernel_ver(): + kv = proc.open('sys/kernel/osrelease').readline().split(".")[:3] + last = len(kv) + if last == 2: + kv.append('0') + last -= 1 + while last > 0: + for char in "-_": + kv[last] = kv[last].split(char)[0] + try: + int(kv[last]) + except: + kv[last] = 0 + last -= 1 + return (int(kv[0]), int(kv[1]), int(kv[2])) + + +#return Private,Shared +#Note shared is always a subset of rss (trs is not always) +def getMemStats(pid): + global have_pss + global have_swap_pss + mem_id = pid #unique + Private_lines = [] + Shared_lines = [] + Pss_lines = [] + Rss = (int(proc.open(pid, 'statm').readline().split()[1]) + * PAGESIZE) + Swap_lines = [] + Swap_pss_lines = [] + + Swap = 0 + Swap_pss = 0 + + if os.path.exists(proc.path(pid, 'smaps')): # stat + lines = proc.open(pid, 'smaps').readlines() # open + # Note we checksum smaps as maps is usually but + # not always different for separate processes. + mem_id = hash(''.join(lines)) + for line in lines: + if line.startswith("Shared"): + Shared_lines.append(line) + elif line.startswith("Private"): + Private_lines.append(line) + elif line.startswith("Pss"): + have_pss = 1 + Pss_lines.append(line) + elif line.startswith("Swap:"): + Swap_lines.append(line) + elif line.startswith("SwapPss:"): + have_swap_pss = 1 + Swap_pss_lines.append(line) + Shared = sum([int(line.split()[1]) for line in Shared_lines]) + Private = sum([int(line.split()[1]) for line in Private_lines]) + #Note Shared + Private = Rss above + #The Rss in smaps includes video card mem etc. + if have_pss: + pss_adjust = 0.5 # add 0.5KiB as this avg error due to truncation + Pss = sum([float(line.split()[1])+pss_adjust for line in Pss_lines]) + Shared = Pss - Private + # Note that Swap = Private swap + Shared swap. + Swap = sum([int(line.split()[1]) for line in Swap_lines]) + if have_swap_pss: + # The kernel supports SwapPss, that shows proportional swap share. + # Note that Swap - SwapPss is not Private Swap. + Swap_pss = sum([int(line.split()[1]) for line in Swap_pss_lines]) + elif (2,6,1) <= kernel_ver() <= (2,6,9): + Shared = 0 #lots of overestimation, but what can we do? + Private = Rss + else: + Shared = int(proc.open(pid, 'statm').readline().split()[2]) + Shared *= PAGESIZE + Private = Rss - Shared + return (Private, Shared, mem_id, Swap, Swap_pss) + + +def getCmdName(pid, split_args, discriminate_by_pid): + cmdline = proc.open(pid, 'cmdline').read().split("\0") + if cmdline[-1] == '' and len(cmdline) > 1: + cmdline = cmdline[:-1] + + path = proc.path(pid, 'exe') + try: + path = os.readlink(path) + # Some symlink targets were seen to contain NULs on RHEL 5 at least + # https://github.com/pixelb/scripts/pull/10, so take string up to NUL + path = path.split('\0')[0] + except OSError: + val = sys.exc_info()[1] + if (val.errno == errno.ENOENT or # either kernel thread or process gone + val.errno == errno.EPERM or + val.errno == errno.EACCES): + raise LookupError + raise + + if split_args: + return ' '.join(cmdline).replace('\n', ' ') + if path.endswith(" (deleted)"): + path = path[:-10] + if os.path.exists(path): + path += " [updated]" + else: + #The path could be have prelink stuff so try cmdline + #which might have the full path present. This helped for: + #/usr/libexec/notification-area-applet.#prelink#.fX7LCT (deleted) + if os.path.exists(cmdline[0]): + path = cmdline[0] + " [updated]" + else: + path += " [deleted]" + exe = os.path.basename(path) + cmd = proc.open(pid, 'status').readline()[6:-1] + if exe.startswith(cmd): + cmd = exe #show non truncated version + #Note because we show the non truncated name + #one can have separated programs as follows: + #584.0 KiB + 1.0 MiB = 1.6 MiB mozilla-thunder (exe -> bash) + # 56.0 MiB + 22.2 MiB = 78.2 MiB mozilla-thunderbird-bin + if sys.version_info >= (3,): + cmd = cmd.encode(errors='replace').decode() + if discriminate_by_pid: + cmd = '%s [%d]' % (cmd, pid) + return cmd + + +#The following matches "du -h" output +#see also human.py +def human(num, power="Ki", units=None): + if units is None: + powers = ["Ki", "Mi", "Gi", "Ti"] + while num >= 1000: #4 digits + num /= 1024.0 + power = powers[powers.index(power)+1] + return "%.1f %sB" % (num, power) + else: + return "%.f" % ((num * 1024) / units) + + +def cmd_with_count(cmd, count): + if count > 1: + return "%s (%u)" % (cmd, count) + else: + return cmd + +#Warn of possible inaccuracies +#2 = accurate & can total +#1 = accurate only considering each process in isolation +#0 = some shared mem not reported +#-1= all shared mem not reported +def shared_val_accuracy(): + """http://wiki.apache.org/spamassassin/TopSharedMemoryBug""" + kv = kernel_ver() + pid = os.getpid() + if kv[:2] == (2,4): + if proc.open('meminfo').read().find("Inact_") == -1: + return 1 + return 0 + elif kv[:2] == (2,6): + if os.path.exists(proc.path(pid, 'smaps')): + if proc.open(pid, 'smaps').read().find("Pss:")!=-1: + return 2 + else: + return 1 + if (2,6,1) <= kv <= (2,6,9): + return -1 + return 0 + elif kv[0] > 2 and os.path.exists(proc.path(pid, 'smaps')): + return 2 + else: + return 1 + +def show_shared_val_accuracy( possible_inacc, only_total=False ): + level = ("Warning","Error")[only_total] + if possible_inacc == -1: + sys.stderr.write( + "%s: Shared memory is not reported by this system.\n" % level + ) + sys.stderr.write( + "Values reported will be too large, and totals are not reported\n" + ) + elif possible_inacc == 0: + sys.stderr.write( + "%s: Shared memory is not reported accurately by this system.\n" % level + ) + sys.stderr.write( + "Values reported could be too large, and totals are not reported\n" + ) + elif possible_inacc == 1: + sys.stderr.write( + "%s: Shared memory is slightly over-estimated by this system\n" + "for each program, so totals are not reported.\n" % level + ) + sys.stderr.close() + if only_total and possible_inacc != 2: + sys.exit(1) + + +def get_memory_usage(pids_to_show, split_args, discriminate_by_pid, + include_self=False, only_self=False): + cmds = {} + shareds = {} + mem_ids = {} + count = {} + swaps = {} + shared_swaps = {} + for pid in os.listdir(proc.path('')): + if not pid.isdigit(): + continue + pid = int(pid) + + # Some filters + if only_self and pid != our_pid: + continue + if pid == our_pid and not include_self: + continue + if pids_to_show is not None and pid not in pids_to_show: + continue + + try: + cmd = getCmdName(pid, split_args, discriminate_by_pid) + except LookupError: + #operation not permitted + #kernel threads don't have exe links or + #process gone + continue + + try: + private, shared, mem_id, swap, swap_pss = getMemStats(pid) + except RuntimeError: + continue #process gone + if shareds.get(cmd): + if have_pss: #add shared portion of PSS together + shareds[cmd] += shared + elif shareds[cmd] < shared: #just take largest shared val + shareds[cmd] = shared + else: + shareds[cmd] = shared + cmds[cmd] = cmds.setdefault(cmd, 0) + private + if cmd in count: + count[cmd] += 1 + else: + count[cmd] = 1 + mem_ids.setdefault(cmd, {}).update({mem_id: None}) + + # Swap (overcounting for now...) + swaps[cmd] = swaps.setdefault(cmd, 0) + swap + if have_swap_pss: + shared_swaps[cmd] = shared_swaps.setdefault(cmd, 0) + swap_pss + else: + shared_swaps[cmd] = 0 + + # Total swaped mem for each program + total_swap = 0 + + # Total swaped shared mem for each program + total_shared_swap = 0 + + # Add shared mem for each program + total = 0 + + for cmd in cmds: + cmd_count = count[cmd] + if len(mem_ids[cmd]) == 1 and cmd_count > 1: + # Assume this program is using CLONE_VM without CLONE_THREAD + # so only account for one of the processes + cmds[cmd] /= cmd_count + if have_pss: + shareds[cmd] /= cmd_count + cmds[cmd] = cmds[cmd] + shareds[cmd] + total += cmds[cmd] # valid if PSS available + total_swap += swaps[cmd] + if have_swap_pss: + total_shared_swap += shared_swaps[cmd] + + sorted_cmds = sorted(cmds.items(), key=lambda x:x[1]) + sorted_cmds = [x for x in sorted_cmds if x[1]] + + return sorted_cmds, shareds, count, total, swaps, shared_swaps, \ + total_swap, total_shared_swap + + +def print_header(show_swap, discriminate_by_pid): + output_string = " Private + Shared = RAM used" + if show_swap: + if have_swap_pss: + output_string += " " * 5 + "Shared Swap" + output_string += " Swap used" + output_string += "\tProgram" + if discriminate_by_pid: + output_string += "[pid]" + output_string += "\n\n" + sys.stdout.write(output_string) + + +def print_memory_usage(sorted_cmds, shareds, count, total, swaps, total_swap, + shared_swaps, total_shared_swap, show_swap): + for cmd in sorted_cmds: + + output_string = "%9s + %9s = %9s" + output_data = (human(cmd[1]-shareds[cmd[0]]), + human(shareds[cmd[0]]), human(cmd[1])) + if show_swap: + if have_swap_pss: + output_string += "\t%9s" + output_data += (human(shared_swaps[cmd[0]]),) + output_string += " %9s" + output_data += (human(swaps[cmd[0]]),) + output_string += "\t%s\n" + output_data += (cmd_with_count(cmd[0], count[cmd[0]]),) + + sys.stdout.write(output_string % output_data) + + if have_pss: + if show_swap: + if have_swap_pss: + sys.stdout.write("%s\n%s%9s%s%9s%s%9s\n%s\n" % + ("-" * 61, " " * 24, human(total), " " * 7, + human(total_shared_swap), " " * 3, + human(total_swap), "=" * 61)) + else: + sys.stdout.write("%s\n%s%9s%s%9s\n%s\n" % + ("-" * 45, " " * 24, human(total), " " * 3, + human(total_swap), "=" * 45)) + else: + sys.stdout.write("%s\n%s%9s\n%s\n" % + ("-" * 33, " " * 24, human(total), "=" * 33)) + + +def verify_environment(pids_to_show): + if os.geteuid() != 0 and not pids_to_show: + sys.stderr.write("Sorry, root permission required, or specify pids with -p\n") + sys.stderr.close() + sys.exit(1) + + try: + kernel_ver() + except (IOError, OSError): + val = sys.exc_info()[1] + if val.errno == errno.ENOENT: + sys.stderr.write( + "Couldn't access " + proc.path('') + "\n" + "Only GNU/Linux and FreeBSD (with linprocfs) are supported\n") + sys.exit(2) + else: + raise + +def main(): + split_args, pids_to_show, watch, only_total, discriminate_by_pid, \ + show_swap = parse_options() + + verify_environment(pids_to_show) + + if not only_total: + print_header(show_swap, discriminate_by_pid) + + if watch is not None: + try: + sorted_cmds = True + while sorted_cmds: + sorted_cmds, shareds, count, total, swaps, shared_swaps, \ + total_swap, total_shared_swap = \ + get_memory_usage(pids_to_show, split_args, + discriminate_by_pid) + if only_total and have_pss: + sys.stdout.write(human(total, units=1)+'\n') + elif not only_total: + print_memory_usage(sorted_cmds, shareds, count, total, + swaps, total_swap, shared_swaps, + total_shared_swap, show_swap) + + sys.stdout.flush() + time.sleep(watch) + else: + sys.stdout.write('Process does not exist anymore.\n') + except KeyboardInterrupt: + pass + else: + # This is the default behavior + sorted_cmds, shareds, count, total, swaps, shared_swaps, total_swap, \ + total_shared_swap = get_memory_usage(pids_to_show, split_args, + discriminate_by_pid) + if only_total and have_pss: + sys.stdout.write(human(total, units=1)+'\n') + elif not only_total: + print_memory_usage(sorted_cmds, shareds, count, total, swaps, + total_swap, shared_swaps, total_shared_swap, + show_swap) + + # We must close explicitly, so that any EPIPE exception + # is handled by our excepthook, rather than the default + # one which is reenabled after this script finishes. + sys.stdout.close() + + vm_accuracy = shared_val_accuracy() + show_shared_val_accuracy( vm_accuracy, only_total ) + +if __name__ == '__main__': main() diff --git a/files/rc.local.debian b/files/rc.local.debian new file mode 100644 index 0000000..352cc5d --- /dev/null +++ b/files/rc.local.debian @@ -0,0 +1,3 @@ +#!/bin/sh -e + +exit 0 \ No newline at end of file diff --git a/files/rc.local.ubuntu b/files/rc.local.ubuntu new file mode 100644 index 0000000..f13c61f --- /dev/null +++ b/files/rc.local.ubuntu @@ -0,0 +1,6 @@ +#!/bin/sh -e + +find /etc/update-motd.d -type f,l ! -name '98*' -delete +/bin/run-parts /etc/update-motd.d + +exit 0 \ No newline at end of file diff --git a/files/rt b/files/rt new file mode 100755 index 0000000..6c616af --- /dev/null +++ b/files/rt @@ -0,0 +1,289 @@ +#!/usr/bin/perl +################################################################################ rt - restic wrapper (mwx'2026) +use File::Basename;use Term::ReadKey;use Getopt::Std;getopts('c:n:i:t:p:'); + +$VERSION='1.5.6'; + +$CONFIG='default';$CONFIG=$opt_c if ($opt_c!~/^\s*$/); # set deault options options +chomp($host=`hostname`);$host=~s/^([^\.]+).*/$1/; +$NAME=$host; +$POLICY='--keep-daily 14 --keep-weekly 12 --keep-monthly 12 --keep-yearly 100'; + +for ('/db/etc/rt.conf',$ENV{"HOME"}.'/.rt.conf') { $CONF=$_ if (-f $_);} # find/load/check configuration +die "Fatal: no config file found\n" if ($CONF=~/^\s*$/); + +require($CONF); + +$NAME = $opt_n if ($opt_n!~/^\s*$/); # overwrite options with commandline (name, id, tag, password) +$ID = $opt_i if ($opt_i!~/^\s*$/); +$TAG = $opt_t if ($opt_t!~/^\s*$/); +$PASSWORD = $opt_p if ($opt_p!~/^\s*$/); + +for ('$NAME','$TARGET','$SRC','$RESTIC','$LOG') { + die "Fatal: missing $_ in config\n" if (eval($_)=~/^\s*$/); +} + +$ID='0' if ($ID=~/^\s*$/); # set repository +$REPOSITORY="$TARGET/$NAME.$ID"; + + +print "rt $VERSION, Name: $NAME, Repository: $REPOSITORY, Config: $CONFIG\n"; + + +open(PW,"> $PWFILE");print PW "$PASSWORD\n";close(PW); + +$ENV{'RESTIC_REPOSITORY'} = $REPOSITORY; # set environment +$ENV{'RESTIC_PASSWORD_FILE'} = $PWFILE; + +$r=`$RESTIC version`; # find restic version +if ($r=~/restic\s+([\d\.]+)\s+compiled/) { + $RVERSION=$1; + @RV=split('\.',$1);$RVN=sprintf("%02d%02d%02d",$RV[0],$RV[1],$RV[2]); +} + +$TMP="/tmp"; + +my(@z)=localtime(time());$z[4]+=1;$z[5]-=100;$z[6]+=1; +$z=sprintf("%02d\.%02d\.%02d %02d\:%02d",$z[3],$z[4],$z[5],$z[2],$z[1]); + + +if ($ARGV[0] eq 'cleanup') { # ----------------------------------------------------------- forget, prune, check + + $ts=time(); + + print "$RESTIC -r $REPOSITORY forget $POLICY --prune\n"; # forget & prune + + $rms=0; + open(IN,"$RESTIC forget $POLICY --prune |"); + while() { + print; + $rms=$1 if (/^(\d+)\s+snapshots\s+have\s+been\s+removed/) + } + + print "$RESTIC -r $REPOSITORY check\n"; # check + + open(IN,"$RESTIC check |"); + while() { + print; + chomp($lastline=$_); + } + + $rt=time()-$ts; + + if ($HTTP_LOG!~/^\s*$/) { # http loging + $tmp= "RTC,$VERSION/$RVERSION,$NAME,$ID,$CONFIG,$TAG,$REPOSITORY,$lastline,$rms,$rt"; + use LWP::UserAgent; + my $ua = new LWP::UserAgent(); + $response = $ua->post("https://$HTTP_LOG", Content => $tmp); + } + + if ($MY_HOST!~/^\s*$/) { # mysql loging + use DBI; + $dbh=DBI->connect("DBI:mysql:$MY_DB:$MY_HOST:$MY_PORT",$MY_USER,$MY_PASSWD,{RaiseError=>1,PrintError=>1}); + $sql="INSERT INTO resticcleanup VALUES(now(),'$VERSION/$RVERSION', + '$NAME','$ID','$CONFIG','$TAG','$REPOSITORY','$lastline',$rms,$rt)"; + $dbh->do($sql); + } + +} elsif ($ARGV[0] eq 'backup' || $ARGV[0] eq 'delaybackup') { # ----------------------------------- run backup + $snap='';$added='';$total=''; + + if ($ARGV[0] eq 'delaybackup') { + printf "$z --- delaybackup (%d sec) ---\n",&dfn($NAME); + sleep(&dfn($NAME)) + } else { + printf "$z --- backup ---\n"; + } + + print "$RESTIC -r $REPOSITORY -vv backup $EXCLUDE $SRC\n"; + + $ts=time(); + open(IN,"$RESTIC -vv backup $EXCLUDE $SRC |"); + while() { + print if (!/^unchanged/); + + if (/Files:\s*(\d+)\s*new,\s*(\d+)\s*changed,\s*(\d+)\s*unmodified/) { + $fn+=$1;$fc+=$2;$fu+=$3; + } + if (/Dirs:\s*(\d+)\s*new,\s*(\d+)\s*changed,\s*(\d+)\s*unmodified/) { + $fn+=$1;$fc+=$2;$fu+=$3; + } + $snap=$1 if (/snapshot\s+([^\s]+)\s+saved/); + $added=&deform($1) if (/Added\s+to\s+the\s+repo:\s+(.*)/); + $added=&deform($1) if (/Added\s+to\s+the\s+repository:\s+([^\(]*)/); + + $total=&deform($1) if (/processed\s+\d+\s+files,\s+(.*)\s+in/); + $files=$1 if (/processed\s+(\d+)\s+files,\s+.*\s+in/); + } + + if ($snap!~/^\s*$/ && $added!~/^\s*$/ && $total!~/^\s*$/) { + $rt=time()-$ts; + + open(LOG,">> $LOG"); # write logfile + print LOG "$z [$NAME/$snap], Files: $files, New: $fn, Changed: $fc, ". + "Unmodified: $fu, Added: $added, Total: $total, Runtime: $rt\n"; + close(LOG); + + if ($HTTP_LOG!~/^\s*$/) { # http loging + $tmp= "RT,$VERSION/$RVERSION,$NAME,$ID,$CONFIG,$TAG,$REPOSITORY,". + "$snap,$files,$fn,$fc,$fu,$added,$total,$rt"; + use LWP::UserAgent; + my $ua = new LWP::UserAgent(); + $response = $ua->post("https://$HTTP_LOG", Content => $tmp); + } + + if ($MY_HOST!~/^\s*$/) { # mysql loging + use DBI; + $dbh=DBI->connect("DBI:mysql:$MY_DB:$MY_HOST:$MY_PORT",$MY_USER,$MY_PASSWD,{RaiseError=>1,PrintError=>1}); + $sql="INSERT INTO restic VALUES(now(),'$VERSION/$RVERSION', + '$NAME','$ID','$CONFIG','$TAG','$REPOSITORY','$snap',$files,$fn,$fc,$fu,$added,$total,$rt)"; + $dbh->do($sql); + } + } + + +} elsif ($ARGV[0] eq 'password') { # ----------------------------------------------- setup restic password file + system("mkdir -p ".&dirname($PWFILE)) if (!-d &dirname($PWFILE)); + + print "new repository password: "; + chomp($pwd = &ReadLine(0)); + + if ($pwd!~/^\s*$/) { + open(OUT,"> $PWFILE");print OUT "$pwd\n";close(OUT); + } + + +} elsif ($ARGV[0] eq 'help' || $ARGV[0]=~/^\s*$/) { # ----------------------------------------------- show help + + &help(); + &advhelp() if ($ARGV[0] eq 'help'); + + +} else { # ------------------------------------------------------------------------------ other restic commands + + system("$RESTIC @ARGV"); + + if ($ARGV[0] eq 'init') { + system("rm -f /var/log/restic.log /var/log/rt.log"); + } + +} + +####################################################################################################### SUPPORT + +sub deform() { # transform sizes + my($s)=@_; + return $1<<40 if ($s=~/([\d\.]+)\s*TiB/i); + return $1<<30 if ($s=~/([\d\.]+)\s*GiB/i); + return $1<<20 if ($s=~/([\d\.]+)\s*MiB/i); + return $1<<10 if ($s=~/([\d\.]+)\s*KiB/i); + return $1 if ($s=~/([\d\.]+)\s*B/i); +} + +sub dfn() { # calculate delay from string + my($s)=@_;my $v=0;my $n=1; + $v+=ord($_)*$n++ for (split('',$s)); + return ($v%24)*5*60; +} + +sub help() { # help +print "\nrt v$VERSION - restic wrapper (mwx'2022)\n"; +print <<'ENDOFHELP'; + + USAGE: + ------ + rt [options] backup run restic backup + rt [options] delaybackup run delayed restic backup + rt [options] cleanup run forget, prune and check + rt [options] password setup restic password file + rt [options] init initialize restic repository + rt help advanced help + + rt other commands will be forwarded directly to restic + + options: -c sets $CONFIG (default is 'default') + -n overwrite $NAME + -i overwrite $ID + -t overwrite $TAG + -p overwrite $PASSWORD + +ENDOFHELP +} + +sub advhelp() { # advanced help +print <<'ENDOFHELP'; + CONFIG FILE (/db/etc/rt.conf) + ----------------------------- + $NAME = 'NAME'; # backup name + $ID = '0'; # repository id (optional, default is 0) + $TAG = 'TAG'; # custom tag for logging (optional) + + $TARGET = "/backup/restic"; # restic target + = "s3:http://188.68.34.116:9234/restic"; + = "b2:mwx002:restic/server"; + + $SRC = '/etc /db /var /root /home /usr/local /opt'; # source paths + + $EXCLUDE = '-e /var/lib/lxcfs -e /var/log/journal'; # exclude options + + $RESTIC = '/db/bin/restic'; # restic binary + $LOG = '/var/log/restic.log'; # log file + $PWFILE = '/db/etc/restic.pw'; # restic password file + + $HTTP_LOG = 'HOST'; # host for logging via https + + $MY_HOST = 'HOST'; # mysql host + $MY_PORT = 'PORT'; # mysql port + $MY_USER = 'USER'; # mysql user + $MY_PASSWD = 'PASSWORD'; # mysql password + $MY_DB = 'DATABASE'; # mysql database + + + $ENV{'AWS_ACCESS_KEY_ID'} = '123456'; # S3 token example + $ENV{'AWS_SECRET_ACCESS_KEY'} = 'abcdefg'; + + $ENV{'B2_ACCOUNT_ID'} = '123456'; # B2 token example + $ENV{'B2_ACCOUNT_KEY'} = 'abcdefg'; + + MYSQL LOGGING TABLES: + --------------------- + CREATE TABLE `restic` ( + `ts` timestamp NULL DEFAULT NULL, + `version` varchar(255) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `id` int(11) DEFAULT NULL, + `config` varchar(255) DEFAULT NULL, + `tag` varchar(255) DEFAULT NULL, + `repository` varchar(255) DEFAULT NULL, + `snapshot` varchar(255) DEFAULT NULL, + `files` bigint(11) DEFAULT NULL, + `new` bigint(11) DEFAULT NULL, + `changed` bigint(11) DEFAULT NULL, + `unmodified` bigint(11) DEFAULT NULL, + `added` bigint(11) DEFAULT NULL, + `total` bigint(11) DEFAULT NULL, + `runtime` int(11) DEFAULT NULL + ) ENGINE=InnoDB DEFAULT CHARSET=latin1; + + CREATE TABLE `resticcleanup` ( + `ts` timestamp NULL DEFAULT NULL, + `version` varchar(255) DEFAULT NULL, + `name` varchar(255) DEFAULT NULL, + `id` int(11) DEFAULT NULL, + `config` varchar(255) DEFAULT NULL, + `tag` varchar(255) DEFAULT NULL, + `repository` varchar(255) DEFAULT NULL, + `txt` varchar(255) DEFAULT NULL, + `rmsnap` int(11) DEFAULT NULL, + `runtime` int(11) DEFAULT NULL + ) ENGINE=InnoDB DEFAULT CHARSET=latin1; + + CRONTAB ENTRIES: + --------------- + 0 2 * * * /db/bin/rt delaybackup >> /var/log/rt.log 2>&1 + 0 7 * * 6 /db/bin/rt cleanup >> /var/log/rt.log 2>&1 + +ENDOFHELP +} + +########################################################################################################### END diff --git a/files/telemetry b/files/telemetry new file mode 100755 index 0000000..f9bb0f6 --- /dev/null +++ b/files/telemetry @@ -0,0 +1,43 @@ +#!/usr/bin/perl +####################################################################### telemetry collector - v1.0.0 (mwx'2020) +use LWP::UserAgent; +chomp($host=`hostname`);$host=~s/\..*$//i; + +$url = 'http://monitor.rz-berlin.mpg.de/telemetry.php'; + +############################################################################################ collect disk usage + +$data = "df,$host,"; + +open(IN,"/bin/df -k -T |"); +while() { + @df=split(' '); + if ($df[1]=~/^ext/ || $df[1]=~/^nfs/) { + $total=($df[2]/1024/1024); + $avail=($df[4]/1024/1024); + $used=$total - $avail; + $per=$used*100/$total; + $data.=sprintf("$df[6],%.3f,%.3f,%.3f,%.2f,",$total,$avail,$used,$per); + } +} + +$data .= time(); + +print "$data\n"; +my $ua = new LWP::UserAgent(); +$response = $ua->post($url, Content => $data); + +########################################################################################### collect system load + +open(UPTIME,"/usr/bin/uptime |");chomp($_=); +if (/load\s*averages*\:\s*[\d\.]+\,\s*[\d\.]+\,\s*([\d\.]+)/) { + $load=$1; +} + +$data = "load,$host,$load,".time(); + +print "$data\n"; +my $ua = new LWP::UserAgent(); +$response = $ua->post($url, Content => $data); + +########################################################################################################### END diff --git a/files/timesyncd.conf b/files/timesyncd.conf new file mode 100644 index 0000000..795125f --- /dev/null +++ b/files/timesyncd.conf @@ -0,0 +1,26 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 2.1 of the License, or (at your option) +# any later version. +# +# Entries in this file show the compile time defaults. Local configuration +# should be created by either modifying this file (or a copy of it placed in +# /etc/ if the original file is shipped in /usr/), or by creating "drop-ins" in +# the /etc/systemd/timesyncd.conf.d/ directory. The latter is generally +# recommended. Defaults can be restored by simply deleting the main +# configuration file and all drop-ins located in /etc/. +# +# Use 'systemd-analyze cat-config systemd/timesyncd.conf' to display the full config. +# +# See timesyncd.conf(5) for details. + +[Time] +NTP=de.pool.ntp.org +FallbackNTP=ptbtime1.ptb.de 0.debian.pool.ntp.org 1.debian.pool.ntp.org 2.debian.pool.ntp.org 3.debian.pool.ntp.org +#RootDistanceMaxSec=5 +#PollIntervalMinSec=32 +#PollIntervalMaxSec=2048 +#ConnectionRetrySec=30 +#SaveIntervalSec=60 diff --git a/files/zshrc b/files/zshrc new file mode 100644 index 0000000..70a7f8c --- /dev/null +++ b/files/zshrc @@ -0,0 +1,96 @@ + +unsetopt always_last_prompt +autoload -U colors && colors +zle_highlight+=(paste:none) +unsetopt BEEP +autoload -U compinit +compinit + +bindkey "\e[3~" delete-char +bindkey '^[[F' end-of-line +bindkey '^[[H' beginning-of-line +bindkey '^[[6~' end-of-line +bindkey '^[[5~' beginning-of-line + +HISTFILE=~/.zsh_history +HISTSIZE=10000 +SAVEHIST=10000 +setopt HIST_REDUCE_BLANKS +setopt EXTENDED_HISTORY +setopt INC_APPEND_HISTORY +setopt HIST_EXPIRE_DUPS_FIRST +setopt HIST_IGNORE_DUPS +setopt HIST_IGNORE_ALL_DUPS +setopt HIST_IGNORE_SPACE +setopt HIST_SAVE_NO_DUPS +setopt HIST_REDUCE_BLANKS +setopt HIST_VERIFY +setopt HIST_BEEP +setopt SHARE_HISTORY + +HN=`hostname -s` + +PP=">"; if [[ $USER == "root" ]] then PP=">>" fi +PROMPT="%n@${HN}:%{$fg[white]%}%~%{$reset_color%} $PP " + +alias a='alias' +alias h='history -d -10000' +alias L='last -16' +alias ls='ls -F' +alias ll='ls -lsh' +alias lt='ls -ltrh' +alias lla='ls -lsah' +alias lta='ls -ltrah' +alias s='ssh' +alias sr='ssh -l root' +alias rs='rsync -va --delete --stats' +alias p='ps -ef | grep ${LOGNAME}' +alias P='ps -ef' +alias af='apt-cache search' +alias ai='apt-get install' +alias sd='lsblk -o NAME,FSTYPE,SIZE,MOUNTPOINT,LABEL' + +alias ga='git add -v .' +alias gb='git branch' +alias gs='git status' +alias gl="git log -32 --reverse --date=local --format='%h %cd %s'" +alias gc='git commit -m' +alias gu='git checkout' +alias gp='git push' +alias y='yazi' +alias f='fzf' + +export TERM=xterm-256color +export COLORTERM=truecolor + + +PATH=/db/bin:"$PATH" +if [ -f /db/go/bin/go ]; then + PATH="$PATH":/db/go/bin:$(/db/go/bin/go env GOPATH)/bin + export CGO_ENABLED=0 +fi + +tcsh_autolist() { if [[ -z ${LBUFFER// } ]] + then BUFFER="ls " CURSOR=3 zle list-choices + else zle expand-or-complete-prefix; fi } +zle -N tcsh_autolist +bindkey '^I' tcsh_autolist + +if [ -f /etc/zshcomp ]; then + source /etc/zshcom +fi + +[ -f /etc/zsh/zshcomp ] && source /etc/zsh/zshcomp + +if [ -f /db/etc/omp.json ]; then + if (( $+commands[oh-my-posh] )); then + eval "$(oh-my-posh init zsh --config /db/etc/omp.json )"; + fi +fi + +if (( $+commands[lsd] )); then + alias lx='lsd --icon never --tree -la' + alias ll='lsd --icon never -la' + alias lt='lsd --icon never -latr' + alias ls='lsd --icon never -a' +fi diff --git a/go.setup b/go.setup new file mode 100755 index 0000000..f333097 --- /dev/null +++ b/go.setup @@ -0,0 +1,25 @@ +#!/usr/bin/bash + +# Fetch latest version name (e.g., go1.26.2) +RELEASE=$(curl -sL https://go.dev/VERSION?m=text | head -n 1) + +# Detect OS and Architecture +OS=$(uname -s | tr '[:upper:]' '[:lower:]') +ARCH=$(uname -m) +[ "$ARCH" == "x86_64" ] && ARCH="amd64" +[ "$ARCH" == "aarch64" ] && ARCH="arm64" + +# Download and Extract + +FILE="${RELEASE}.${OS}-${ARCH}.tar.gz" +URL="https://go.dev/dl/$FILE" +echo "Downloading $FILE $URL..." + +wget $URL + +rm -rf /db/go && tar -C /db -xzf $FILE + +export PATH=/db/go/bin:~/go/bin:$PATH +export CGO_ENABLED=0 + +/db/go/bin/go install golang.org/x/tools/cmd/goimports@latest diff --git a/perlmodules/MD5-1.7/Changes b/perlmodules/MD5-1.7/Changes new file mode 100644 index 0000000..0acf87c --- /dev/null +++ b/perlmodules/MD5-1.7/Changes @@ -0,0 +1,83 @@ +Revision history for Perl extension MD5. + +*** 96/06/20 Version 1.7 + +MD5 is now completely 64-bit clean (I hope). The basic MD5 code uses +32-bit quantities and requires a typedef UINT4 to be defined in +global.h. Perl configuration data (the value of BYTEORDER) is used to +determine if unsigned longs have 4 or 8 bytes. On 64-bit platforms (eg +DEC Alpha) then it assumes that "unsigned int" will be a 32-bit type. +If this is incorrect then adding -DUINT4_IS_LONG to the DEFINES line in +Makefile.PL will override this. + +On some machines (at least Cray that I know of) there is no 32-bit +integer type. In this case defining TRUNCATE_UINT4 (which is done +automatically for a Cray) will ensure that 64-bit values are masked +down to 32 bits. I have done my best to test this but without easy +access to a true 64-bit machine I can not totally guarantee it (unless +anyone wants to lend me a spare Cray :-) + +There is one remaining limitation for 64-bit enabled processors. The +amount of data passed to any single call to the underlying MD5 +routines is limited to (2^32 - 1) bytes -- that's 4 gigabytes. I'm +sorry if that's a real problem for you ... + +And finally, a minor complilation warning (unsigned char * used with +function having char * prototype) has also been eliminated. + +*** 96/04/09 Version 1.6 + +Re-generated module framework using h2xs to pick up the latest module +conventions for versions etc. You can now say "use MD5 1.6;" and things +should work correctly. MD5.pod has been integrated into MD5.pm and +CHANGES renamed to Changes. There is a fairly comprehensive test.pl +which can be invoked via "make test". There are no functional changes +to the MD5 routines themselves. + +*** 96/03/14 Version 1.5.3 + +Fixed addfile method to accept type-glob references for the file-handle +(eg \*STDOUT). This is more consistent with other routines and is now the +recommended way of passing file-handles. The documentation now gives more +examples as to how the routines might be used. + +*** 96/03/12 Version 1.5.2 + +Minor fixes from Christopher J Madsen to provide +support for building on OS/2 (and to work arround a perl -w bug). + +Remove warning about possible difference between add('foo', 'bar') and +add('foobar'). This is not true (it may have been true in the earliest +version of the module but is no longer the case). + +*** 96/03/08 Version 1.5.1 + +Add CHANGES file to make it easier for people to figure out what has +been going on. (Meant to do this as part of 1.5) + +*** 96/03/05 Version 1.5 + +Add hash() and hexhash() methods at the suggestion/request of Gary +Howland before inclusion in a wider library +of cryptography modules. + +*** 96/02/27 Version 1.4 + +Finally fixed the pesky Solaris dynamic loading bug. All kudos to Ken +Pizzini ! + +*** 95/11/29 Version 1.3.1 + +Add explanations of current known problems. + +*** 95/06/02 Version 1.3 + +Fix problems with scope resolution in addfile() reported by +Jean-Claude Giese . Basically ARGV is +always implicitly in package main while other filehandles aren't. + +*** 95/05/23 Version 1.2.1 + +[Changes pre 1.2.1 not recorded] + +SCCS ID @(#)Changes 1.5 96/06/28 diff --git a/perlmodules/MD5-1.7/MANIFEST b/perlmodules/MD5-1.7/MANIFEST new file mode 100644 index 0000000..1b2cddd --- /dev/null +++ b/perlmodules/MD5-1.7/MANIFEST @@ -0,0 +1,13 @@ +README Guess what? +MANIFEST This file +MD5.pm MD5 Perl Module +MD5.xs MD5 Perl 'XS' source file +typemap Supplementary typemap +Makefile.PL Perl Makefile builder +md5c.c MD5 C source from RFC 1321 +md5.h Header for above +global.h ditto +test.pl Test suite using standard Perl conventions +Changes Version history +examples/mddriver.pl Example driver script after mddriver.c in RFC 1321 +examples/twdigest.pl Example code to format a digest like Tripwire diff --git a/perlmodules/MD5-1.7/MD5.pm b/perlmodules/MD5-1.7/MD5.pm new file mode 100644 index 0000000..3c71d5e --- /dev/null +++ b/perlmodules/MD5-1.7/MD5.pm @@ -0,0 +1,263 @@ +# SCCS ID @(#)MD5.pm 1.9 96/06/28 +package MD5; + +use strict; +use vars qw($VERSION @ISA @EXPORT); + +require Exporter; +require DynaLoader; +require AutoLoader; + +@ISA = qw(Exporter AutoLoader DynaLoader); +# Items to export into callers namespace by default. Note: do not export +# names by default without a very good reason. Use EXPORT_OK instead. +# Do not simply export all your public functions/methods/constants. +@EXPORT = qw( + +); +$VERSION = '1.7'; + +bootstrap MD5 $VERSION; + +# Preloaded methods go here. + +sub addfile +{ + no strict 'refs'; # Countermand any strct refs in force so that we + # can still handle file-handle names. + + my ($self, $handle) = @_; + my ($package, $file, $line) = caller; + my ($data) = ''; + + if (!ref($handle)) + { + # Old-style passing of filehandle by name. We need to add + # the calling package scope qualifier, if there is not one + # supplied already. + + $handle = $package . '::' . $handle unless ($handle =~ /(\:\:|\')/); + } + + while (read($handle, $data, 1024)) + { + $self->add($data); + } +} + +sub hexdigest +{ + my ($self) = shift; + + unpack("H*", ($self->digest())); +} + +sub hash +{ + my ($self, $data) = @_; + + if (ref($self)) + { + # This is an instance method call so reset the current context + + $self->reset(); + } + else + { + # This is a static method invocation, create a temporary MD5 context + + $self = new MD5; + } + + # Now do the hash + + $self->add($data); + $self->digest(); +} + +sub hexhash +{ + my ($self, $data) = @_; + + unpack("H*", ($self->hash($data))); +} + +# Autoload methods go after =cut, and are processed by the autosplit program. + +1; +__END__ + +=head1 NAME + +MD5 - Perl interface to the RSA Data Security Inc. MD5 Message-Digest Algorithm + +=head1 SYNOPSIS + + use MD5; + + $context = new MD5; + $context->reset(); + + $context->add(LIST); + $context->addfile(HANDLE); + + $digest = $context->digest(); + $string = $context->hexdigest(); + + $digest = MD5->hash(SCALAR); + $string = MD5->hexhash(SCALAR); + +=head1 DESCRIPTION + +The B module allows you to use the RSA Data Security Inc. MD5 +Message Digest algorithm from within Perl programs. + +A new MD5 context object is created with the B operation. +Multiple simultaneous digest contexts can be maintained, if desired. +The context is updated with the B operation which adds the +strings contained in the I parameter. Note, however, that +C, C followed by C and +C should all give the same result. + +The final message digest value is returned by the B operation +as a 16-byte binary string. This operation delivers the result of +B operations since the last B or B operation. Note +that the B operation is effectively a destructive, read-once +operation. Once it has been performed, the context must be B +before being used to calculate another digest value. + +Several convenience functions are also provided. The B +operation takes an open file-handle and reads it until end-of file in +1024 byte blocks adding the contents to the context. The file-handle +can either be specified by name or passed as a type-glob reference, as +shown in the examples below. The B operation calls +B and returns the result as a printable string of hexdecimal +digits. This is exactly the same operation as performed by the +B operation in the examples below. + +The B operation can act as either a static member function (ie +you invoke it on the MD5 class as in the synopsis above) or as a +normal virtual function. In both cases it performs the complete MD5 +cycle (reset, add, digest) on the supplied scalar value. This is +convenient for handling small quantities of data. When invoked on the +class a temporary context is created. When invoked through an already +created context object, this context is used. The latter form is +slightly more efficient. The B operation is analogous to +B. + +=head1 EXAMPLES + + use MD5; + + $md5 = new MD5; + $md5->add('foo', 'bar'); + $md5->add('baz'); + $digest = $md5->digest(); + + print("Digest is " . unpack("H*", $digest) . "\n"); + +The above example would print out the message + + Digest is 6df23dc03f9b54cc38a0fc1483df6e21 + +provided that the implementation is working correctly. + +Remembering the Perl motto ("There's more than one way to do it"), the +following should all give the same result: + + use MD5; + $md5 = new MD5; + + die "Can't open /etc/passwd ($!)\n" unless open(P, "/etc/passwd"); + + seek(P, 0, 0); + $md5->reset; + $md5->addfile(P); + $d = $md5->hexdigest; + print "addfile (handle name) = $d\n"; + + seek(P, 0, 0); + $md5->reset; + $md5->addfile(\*P); + $d = $md5->hexdigest; + print "addfile (type-glob reference) = $d\n"; + + seek(P, 0, 0); + $md5->reset; + while (

) + { + $md5->add($_); + } + $d = $md5->hexdigest; + print "Line at a time = $d\n"; + + seek(P, 0, 0); + $md5->reset; + $md5->add(

); + $d = $md5->hexdigest; + print "All lines at once = $d\n"; + + seek(P, 0, 0); + $md5->reset; + while (read(P, $data, (rand % 128) + 1)) + { + $md5->add($data); + } + $d = $md5->hexdigest; + print "Random chunks = $d\n"; + + seek(P, 0, 0); + $md5->reset; + undef $/; + $data =

; + $d = $md5->hexhash($data); + print "Single string = $d\n"; + + close(P); + +=head1 NOTE + +The MD5 extension may be redistributed under the same terms as Perl. +The MD5 algorithm is defined in RFC1321. The basic C code implementing +the algorithm is derived from that in the RFC and is covered by the +following copyright: + +=over 8 + +Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + +=back + +This copyright does not prohibit distribution of any version of Perl +containing this extension under the terms of the GNU or Artistic +licences. + +=head1 AUTHOR + +The MD5 interface was written by Neil Winton +(C). + +=head1 SEE ALSO + +perl(1). + +=cut diff --git a/perlmodules/MD5-1.7/MD5.xs b/perlmodules/MD5-1.7/MD5.xs new file mode 100644 index 0000000..c4a4ea2 --- /dev/null +++ b/perlmodules/MD5-1.7/MD5.xs @@ -0,0 +1,101 @@ +/* +** Perl Extension for the +** +** RSA Data Security Inc. MD5 Message-Digest Algorithm +** +** This module by Neil Winton (N.Winton@axion.bt.co.uk) +** SCCS ID @(#)MD5.xs 1.7 96/06/28 +** +** This extension may be distributed under the same terms +** as Perl. The MD5 code is covered by separate copyright and +** licence, but this does not prohibit distribution under the +** GNU or Artistic licences. See the file md5c.c or MD5.pm +** for more details. +*/ + +#ifdef __cplusplus +extern "C" { +#endif +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +#include "global.h" +#include "md5.h" + +/* +** The following macro re-definitions added to work around a problem on +** Solaris where the original MD5 routines are already in /lib/libnsl.a. +** This causes dynamic linking of the module to fail. +** Thanks to Ken Pizzini (ken@spry.com) for finally nailing this one! +*/ + +#define MD5Init MD5Init_perl +#define MD5Update MD5Update_perl +#define MD5Final MD5Final_perl + +typedef MD5_CTX *MD5; + +#ifdef __cplusplus +} +#endif + + +MODULE = MD5 PACKAGE = MD5 + +PROTOTYPES: DISABLE + +MD5 +new(packname = "MD5") + char * packname + CODE: + { + RETVAL = (MD5_CTX *)safemalloc(sizeof(MD5_CTX)); + MD5Init(RETVAL); + } + OUTPUT: + RETVAL + +void +DESTROY(context) + MD5 context + CODE: + { + safefree((char *)context); + } + +void +reset(context) + MD5 context + CODE: + { + MD5Init(context); + } + +void +add(context, ...) + MD5 context + CODE: + { + SV *svdata; + STRLEN len; + unsigned char *data; + int i; + + for (i = 1; i < items; i++) + { + data = (unsigned char *)(SvPV(ST(i), len)); + MD5Update(context, data, len); + } + } + +SV * +digest(context) + MD5 context + CODE: + { + unsigned char digeststr[16]; + + MD5Final(digeststr, context); + ST(0) = sv_2mortal(newSVpv((char *)digeststr, 16)); + } diff --git a/perlmodules/MD5-1.7/Makefile.PL b/perlmodules/MD5-1.7/Makefile.PL new file mode 100644 index 0000000..da6b4bb --- /dev/null +++ b/perlmodules/MD5-1.7/Makefile.PL @@ -0,0 +1,13 @@ +# SCCS ID @(#)Makefile.PL 1.10 96/06/28 +use ExtUtils::MakeMaker; +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. +WriteMakefile( + 'NAME' => 'MD5', + 'VERSION_FROM' => 'MD5.pm', # finds $VERSION + 'LIBS' => [''], # e.g., '-lm' + 'CONFIG' => ['byteorder'], # Used to determine 64-bitness + 'DEFINE' => '-DPERL_BYTEORDER=$(BYTEORDER)', + 'INC' => '', # e.g., '-I/usr/include/other' + 'OBJECT' => q[MD5$(OBJ_EXT) md5c$(OBJ_EXT)], +); diff --git a/perlmodules/MD5-1.7/Makefile.old b/perlmodules/MD5-1.7/Makefile.old new file mode 100644 index 0000000..94e939c --- /dev/null +++ b/perlmodules/MD5-1.7/Makefile.old @@ -0,0 +1,1027 @@ +# This Makefile is for the MD5 extension to perl. +# +# It was generated automatically by MakeMaker version +# 7.0401 (Revision: 70401) from the contents of +# Makefile.PL. Don't edit this file, edit Makefile.PL instead. +# +# ANY CHANGES MADE HERE WILL BE LOST! +# +# MakeMaker ARGV: () +# + +# MakeMaker Parameters: + +# BUILD_REQUIRES => { } +# CONFIG => [q[byteorder], q[ar], q[cc], q[cccdlflags], q[ccdlflags], q[dlext], q[dlsrc], q[exe_ext], q[full_ar], q[ld], q[lddlflags], q[ldflags], q[libc], q[lib_ext], q[obj_ext], q[osname], q[osvers], q[ranlib], q[sitelibexp], q[sitearchexp], q[so], q[vendorarchexp], q[vendorlibexp]] +# CONFIGURE_REQUIRES => { } +# DEFINE => q[-DPERL_BYTEORDER=$(BYTEORDER)] +# INC => q[] +# LIBS => [q[]] +# NAME => q[MD5] +# OBJECT => q[MD5$(OBJ_EXT) md5c$(OBJ_EXT)] +# PREREQ_PM => { } +# TEST_REQUIRES => { } +# VERSION_FROM => q[MD5.pm] + +# --- MakeMaker post_initialize section: + + +# --- MakeMaker const_config section: + +# These definitions are from config.sh (via /usr/lib/x86_64-linux-gnu/perl/5.22/Config.pm). +# They may have been overridden via Makefile.PL or on the command line. +BYTEORDER = 12345678 +AR = ar +CC = x86_64-linux-gnu-gcc +CCCDLFLAGS = -fPIC +CCDLFLAGS = -Wl,-E +DLEXT = so +DLSRC = dl_dlopen.xs +EXE_EXT = +FULL_AR = /usr/bin/ar +LD = x86_64-linux-gnu-gcc +LDDLFLAGS = -shared -L/usr/local/lib -fstack-protector-strong +LDFLAGS = -fstack-protector-strong -L/usr/local/lib +LIBC = libc-2.23.so +LIB_EXT = .a +OBJ_EXT = .o +OSNAME = linux +OSVERS = 3.16.0 +RANLIB = : +SITELIBEXP = /usr/local/share/perl/5.22.1 +SITEARCHEXP = /usr/local/lib/x86_64-linux-gnu/perl/5.22.1 +SO = so +VENDORARCHEXP = /usr/lib/x86_64-linux-gnu/perl5/5.22 +VENDORLIBEXP = /usr/share/perl5 + + +# --- MakeMaker constants section: +AR_STATIC_ARGS = cr +DIRFILESEP = / +DFSEP = $(DIRFILESEP) +NAME = MD5 +NAME_SYM = MD5 +VERSION = 1.7 +VERSION_MACRO = VERSION +VERSION_SYM = 1_7 +DEFINE_VERSION = -D$(VERSION_MACRO)=\"$(VERSION)\" +XS_VERSION = 1.7 +XS_VERSION_MACRO = XS_VERSION +XS_DEFINE_VERSION = -D$(XS_VERSION_MACRO)=\"$(XS_VERSION)\" +INST_ARCHLIB = blib/arch +INST_SCRIPT = blib/script +INST_BIN = blib/bin +INST_LIB = blib/lib +INST_MAN1DIR = blib/man1 +INST_MAN3DIR = blib/man3 +MAN1EXT = 1p +MAN3EXT = 3pm +INSTALLDIRS = site +DESTDIR = +PREFIX = $(SITEPREFIX) +PERLPREFIX = /usr +SITEPREFIX = /usr/local +VENDORPREFIX = /usr +INSTALLPRIVLIB = /usr/share/perl/5.22 +DESTINSTALLPRIVLIB = $(DESTDIR)$(INSTALLPRIVLIB) +INSTALLSITELIB = /usr/local/share/perl/5.22.1 +DESTINSTALLSITELIB = $(DESTDIR)$(INSTALLSITELIB) +INSTALLVENDORLIB = /usr/share/perl5 +DESTINSTALLVENDORLIB = $(DESTDIR)$(INSTALLVENDORLIB) +INSTALLARCHLIB = /usr/lib/x86_64-linux-gnu/perl/5.22 +DESTINSTALLARCHLIB = $(DESTDIR)$(INSTALLARCHLIB) +INSTALLSITEARCH = /usr/local/lib/x86_64-linux-gnu/perl/5.22.1 +DESTINSTALLSITEARCH = $(DESTDIR)$(INSTALLSITEARCH) +INSTALLVENDORARCH = /usr/lib/x86_64-linux-gnu/perl5/5.22 +DESTINSTALLVENDORARCH = $(DESTDIR)$(INSTALLVENDORARCH) +INSTALLBIN = /usr/bin +DESTINSTALLBIN = $(DESTDIR)$(INSTALLBIN) +INSTALLSITEBIN = /usr/local/bin +DESTINSTALLSITEBIN = $(DESTDIR)$(INSTALLSITEBIN) +INSTALLVENDORBIN = /usr/bin +DESTINSTALLVENDORBIN = $(DESTDIR)$(INSTALLVENDORBIN) +INSTALLSCRIPT = /usr/bin +DESTINSTALLSCRIPT = $(DESTDIR)$(INSTALLSCRIPT) +INSTALLSITESCRIPT = /usr/local/bin +DESTINSTALLSITESCRIPT = $(DESTDIR)$(INSTALLSITESCRIPT) +INSTALLVENDORSCRIPT = /usr/bin +DESTINSTALLVENDORSCRIPT = $(DESTDIR)$(INSTALLVENDORSCRIPT) +INSTALLMAN1DIR = /usr/share/man/man1 +DESTINSTALLMAN1DIR = $(DESTDIR)$(INSTALLMAN1DIR) +INSTALLSITEMAN1DIR = /usr/local/man/man1 +DESTINSTALLSITEMAN1DIR = $(DESTDIR)$(INSTALLSITEMAN1DIR) +INSTALLVENDORMAN1DIR = /usr/share/man/man1 +DESTINSTALLVENDORMAN1DIR = $(DESTDIR)$(INSTALLVENDORMAN1DIR) +INSTALLMAN3DIR = /usr/share/man/man3 +DESTINSTALLMAN3DIR = $(DESTDIR)$(INSTALLMAN3DIR) +INSTALLSITEMAN3DIR = /usr/local/man/man3 +DESTINSTALLSITEMAN3DIR = $(DESTDIR)$(INSTALLSITEMAN3DIR) +INSTALLVENDORMAN3DIR = /usr/share/man/man3 +DESTINSTALLVENDORMAN3DIR = $(DESTDIR)$(INSTALLVENDORMAN3DIR) +PERL_LIB = /usr/share/perl/5.22 +PERL_ARCHLIB = /usr/lib/x86_64-linux-gnu/perl/5.22 +PERL_ARCHLIBDEP = /usr/lib/x86_64-linux-gnu/perl/5.22 +LIBPERL_A = libperl.a +FIRST_MAKEFILE = Makefile +MAKEFILE_OLD = Makefile.old +MAKE_APERL_FILE = Makefile.aperl +PERLMAINCC = $(CC) +PERL_INC = /usr/lib/x86_64-linux-gnu/perl/5.22/CORE +PERL_INCDEP = /usr/lib/x86_64-linux-gnu/perl/5.22/CORE +PERL = "/usr/bin/perl" +FULLPERL = "/usr/bin/perl" +ABSPERL = $(PERL) +PERLRUN = $(PERL) +FULLPERLRUN = $(FULLPERL) +ABSPERLRUN = $(ABSPERL) +PERLRUNINST = $(PERLRUN) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)" +FULLPERLRUNINST = $(FULLPERLRUN) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)" +ABSPERLRUNINST = $(ABSPERLRUN) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)" +PERL_CORE = 0 +PERM_DIR = 755 +PERM_RW = 644 +PERM_RWX = 755 + +MAKEMAKER = /usr/share/perl/5.22/ExtUtils/MakeMaker.pm +MM_VERSION = 7.0401 +MM_REVISION = 70401 + +# FULLEXT = Pathname for extension directory (eg Foo/Bar/Oracle). +# BASEEXT = Basename part of FULLEXT. May be just equal FULLEXT. (eg Oracle) +# PARENT_NAME = NAME without BASEEXT and no trailing :: (eg Foo::Bar) +# DLBASE = Basename part of dynamic library. May be just equal BASEEXT. +MAKE = make +FULLEXT = MD5 +BASEEXT = MD5 +PARENT_NAME = +DLBASE = $(BASEEXT) +VERSION_FROM = MD5.pm +INC = +DEFINE = -DPERL_BYTEORDER=$(BYTEORDER) +OBJECT = MD5$(OBJ_EXT) md5c$(OBJ_EXT) +LDFROM = $(OBJECT) +LINKTYPE = dynamic +BOOTDEP = + +# Handy lists of source code files: +XS_FILES = MD5.xs +C_FILES = MD5.c \ + md5c.c +O_FILES = MD5.o \ + md5c.o +H_FILES = global.h \ + md5.h +MAN1PODS = +MAN3PODS = MD5.pm + +# Where is the Config information that we are using/depend on +CONFIGDEP = $(PERL_ARCHLIBDEP)$(DFSEP)Config.pm $(PERL_INCDEP)$(DFSEP)config.h + +# Where to build things +INST_LIBDIR = $(INST_LIB) +INST_ARCHLIBDIR = $(INST_ARCHLIB) + +INST_AUTODIR = $(INST_LIB)/auto/$(FULLEXT) +INST_ARCHAUTODIR = $(INST_ARCHLIB)/auto/$(FULLEXT) + +INST_STATIC = $(INST_ARCHAUTODIR)/$(BASEEXT)$(LIB_EXT) +INST_DYNAMIC = $(INST_ARCHAUTODIR)/$(DLBASE).$(DLEXT) +INST_BOOT = $(INST_ARCHAUTODIR)/$(BASEEXT).bs + +# Extra linker info +EXPORT_LIST = +PERL_ARCHIVE = +PERL_ARCHIVEDEP = +PERL_ARCHIVE_AFTER = + + +TO_INST_PM = MD5.pm + +PM_TO_BLIB = MD5.pm \ + $(INST_LIB)/MD5.pm + + +# --- MakeMaker platform_constants section: +MM_Unix_VERSION = 7.0401 +PERL_MALLOC_DEF = -DPERL_EXTMALLOC_DEF -Dmalloc=Perl_malloc -Dfree=Perl_mfree -Drealloc=Perl_realloc -Dcalloc=Perl_calloc + + +# --- MakeMaker tool_autosplit section: +# Usage: $(AUTOSPLITFILE) FileToSplit AutoDirToSplitInto +AUTOSPLITFILE = $(ABSPERLRUN) -e 'use AutoSplit; autosplit($$$$ARGV[0], $$$$ARGV[1], 0, 1, 1)' -- + + + +# --- MakeMaker tool_xsubpp section: + +XSUBPPDIR = /usr/share/perl/5.22/ExtUtils +XSUBPP = "$(XSUBPPDIR)$(DFSEP)xsubpp" +XSUBPPRUN = $(PERLRUN) $(XSUBPP) +XSPROTOARG = +XSUBPPDEPS = /usr/share/perl/5.22/ExtUtils/typemap typemap /usr/share/perl/5.22/ExtUtils$(DFSEP)xsubpp +XSUBPPARGS = -typemap "/usr/share/perl/5.22/ExtUtils/typemap" -typemap "typemap" +XSUBPP_EXTRA_ARGS = + + +# --- MakeMaker tools_other section: +SHELL = /bin/sh +CHMOD = chmod +CP = cp +MV = mv +NOOP = $(TRUE) +NOECHO = @ +RM_F = rm -f +RM_RF = rm -rf +TEST_F = test -f +TOUCH = touch +UMASK_NULL = umask 0 +DEV_NULL = > /dev/null 2>&1 +MKPATH = $(ABSPERLRUN) -MExtUtils::Command -e 'mkpath' -- +EQUALIZE_TIMESTAMP = $(ABSPERLRUN) -MExtUtils::Command -e 'eqtime' -- +FALSE = false +TRUE = true +ECHO = echo +ECHO_N = echo -n +UNINST = 0 +VERBINST = 0 +MOD_INSTALL = $(ABSPERLRUN) -MExtUtils::Install -e 'install([ from_to => {@ARGV}, verbose => '\''$(VERBINST)'\'', uninstall_shadows => '\''$(UNINST)'\'', dir_mode => '\''$(PERM_DIR)'\'' ]);' -- +DOC_INSTALL = $(ABSPERLRUN) -MExtUtils::Command::MM -e 'perllocal_install' -- +UNINSTALL = $(ABSPERLRUN) -MExtUtils::Command::MM -e 'uninstall' -- +WARN_IF_OLD_PACKLIST = $(ABSPERLRUN) -MExtUtils::Command::MM -e 'warn_if_old_packlist' -- +MACROSTART = +MACROEND = +USEMAKEFILE = -f +FIXIN = $(ABSPERLRUN) -MExtUtils::MY -e 'MY->fixin(shift)' -- +CP_NONEMPTY = $(ABSPERLRUN) -MExtUtils::Command::MM -e 'cp_nonempty' -- + + +# --- MakeMaker makemakerdflt section: +makemakerdflt : all + $(NOECHO) $(NOOP) + + +# --- MakeMaker dist section: +TAR = tar +TARFLAGS = cvf +ZIP = zip +ZIPFLAGS = -r +COMPRESS = gzip --best +SUFFIX = .gz +SHAR = shar +PREOP = $(NOECHO) $(NOOP) +POSTOP = $(NOECHO) $(NOOP) +TO_UNIX = $(NOECHO) $(NOOP) +CI = ci -u +RCS_LABEL = rcs -Nv$(VERSION_SYM): -q +DIST_CP = best +DIST_DEFAULT = tardist +DISTNAME = MD5 +DISTVNAME = MD5-1.7 + + +# --- MakeMaker macro section: + + +# --- MakeMaker depend section: + + +# --- MakeMaker cflags section: + +CCFLAGS = -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fwrapv -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 +OPTIMIZE = -O2 -g +PERLTYPE = +MPOLLUTE = + + +# --- MakeMaker const_loadlibs section: + +# MD5 might depend on some other libraries: +# See ExtUtils::Liblist for details +# + + +# --- MakeMaker const_cccmd section: +CCCMD = $(CC) -c $(PASTHRU_INC) $(INC) \ + $(CCFLAGS) $(OPTIMIZE) \ + $(PERLTYPE) $(MPOLLUTE) $(DEFINE_VERSION) \ + $(XS_DEFINE_VERSION) + +# --- MakeMaker post_constants section: + + +# --- MakeMaker pasthru section: + +PASTHRU = LIBPERL_A="$(LIBPERL_A)"\ + LINKTYPE="$(LINKTYPE)"\ + OPTIMIZE="$(OPTIMIZE)"\ + LD="$(LD)"\ + PREFIX="$(PREFIX)"\ + PASTHRU_DEFINE="$(PASTHRU_DEFINE)"\ + PASTHRU_INC="$(PASTHRU_INC)" + + +# --- MakeMaker special_targets section: +.SUFFIXES : .xs .c .C .cpp .i .s .cxx .cc $(OBJ_EXT) + +.PHONY: all config static dynamic test linkext manifest blibdirs clean realclean disttest distdir + + + +# --- MakeMaker c_o section: + +.c.i: + x86_64-linux-gnu-gcc -E -c $(PASTHRU_INC) $(INC) \ + $(CCFLAGS) $(OPTIMIZE) \ + $(PERLTYPE) $(MPOLLUTE) $(DEFINE_VERSION) \ + $(XS_DEFINE_VERSION) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c > $*.i + +.c.s: + $(CCCMD) -S $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c + +.c$(OBJ_EXT): + $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c + +.cpp$(OBJ_EXT): + $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.cpp + +.cxx$(OBJ_EXT): + $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.cxx + +.cc$(OBJ_EXT): + $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.cc + +.C$(OBJ_EXT): + $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.C + + +# --- MakeMaker xs_c section: + +.xs.c: + $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(XSUBPP_EXTRA_ARGS) $*.xs > $*.xsc && $(MV) $*.xsc $*.c + + +# --- MakeMaker xs_o section: + +.xs$(OBJ_EXT): + $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.xsc && $(MV) $*.xsc $*.c + $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c + + +# --- MakeMaker top_targets section: +all :: pure_all manifypods + $(NOECHO) $(NOOP) + + +pure_all :: config pm_to_blib subdirs linkext + $(NOECHO) $(NOOP) + +subdirs :: $(MYEXTLIB) + $(NOECHO) $(NOOP) + +config :: $(FIRST_MAKEFILE) blibdirs + $(NOECHO) $(NOOP) + +$(O_FILES): $(H_FILES) + +help : + perldoc ExtUtils::MakeMaker + + +# --- MakeMaker blibdirs section: +blibdirs : $(INST_LIBDIR)$(DFSEP).exists $(INST_ARCHLIB)$(DFSEP).exists $(INST_AUTODIR)$(DFSEP).exists $(INST_ARCHAUTODIR)$(DFSEP).exists $(INST_BIN)$(DFSEP).exists $(INST_SCRIPT)$(DFSEP).exists $(INST_MAN1DIR)$(DFSEP).exists $(INST_MAN3DIR)$(DFSEP).exists + $(NOECHO) $(NOOP) + +# Backwards compat with 6.18 through 6.25 +blibdirs.ts : blibdirs + $(NOECHO) $(NOOP) + +$(INST_LIBDIR)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_LIBDIR) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_LIBDIR) + $(NOECHO) $(TOUCH) $(INST_LIBDIR)$(DFSEP).exists + +$(INST_ARCHLIB)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_ARCHLIB) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_ARCHLIB) + $(NOECHO) $(TOUCH) $(INST_ARCHLIB)$(DFSEP).exists + +$(INST_AUTODIR)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_AUTODIR) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_AUTODIR) + $(NOECHO) $(TOUCH) $(INST_AUTODIR)$(DFSEP).exists + +$(INST_ARCHAUTODIR)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_ARCHAUTODIR) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_ARCHAUTODIR) + $(NOECHO) $(TOUCH) $(INST_ARCHAUTODIR)$(DFSEP).exists + +$(INST_BIN)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_BIN) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_BIN) + $(NOECHO) $(TOUCH) $(INST_BIN)$(DFSEP).exists + +$(INST_SCRIPT)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_SCRIPT) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_SCRIPT) + $(NOECHO) $(TOUCH) $(INST_SCRIPT)$(DFSEP).exists + +$(INST_MAN1DIR)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_MAN1DIR) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_MAN1DIR) + $(NOECHO) $(TOUCH) $(INST_MAN1DIR)$(DFSEP).exists + +$(INST_MAN3DIR)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_MAN3DIR) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_MAN3DIR) + $(NOECHO) $(TOUCH) $(INST_MAN3DIR)$(DFSEP).exists + + + +# --- MakeMaker linkext section: + +linkext :: $(LINKTYPE) + $(NOECHO) $(NOOP) + + +# --- MakeMaker dlsyms section: + + +# --- MakeMaker dynamic_bs section: +BOOTSTRAP = $(BASEEXT).bs + +# As Mkbootstrap might not write a file (if none is required) +# we use touch to prevent make continually trying to remake it. +# The DynaLoader only reads a non-empty file. +$(BOOTSTRAP) : $(FIRST_MAKEFILE) $(BOOTDEP) $(INST_ARCHAUTODIR)$(DFSEP).exists + $(NOECHO) $(ECHO) "Running Mkbootstrap for $(NAME) ($(BSLOADLIBS))" + $(NOECHO) $(PERLRUN) \ + "-MExtUtils::Mkbootstrap" \ + -e "Mkbootstrap('$(BASEEXT)','$(BSLOADLIBS)');" + $(NOECHO) $(TOUCH) "$@" + $(CHMOD) $(PERM_RW) "$@" + + +# --- MakeMaker dynamic section: + +dynamic :: $(FIRST_MAKEFILE) $(BOOTSTRAP) $(INST_DYNAMIC) + $(NOECHO) $(NOOP) + + +# --- MakeMaker dynamic_lib section: + +# This section creates the dynamically loadable $(INST_DYNAMIC) +# from $(OBJECT) and possibly $(MYEXTLIB). +ARMAYBE = : +OTHERLDFLAGS = +INST_DYNAMIC_DEP = +INST_DYNAMIC_FIX = + +$(INST_DYNAMIC): $(OBJECT) $(MYEXTLIB) $(INST_ARCHAUTODIR)$(DFSEP).exists $(EXPORT_LIST) $(PERL_ARCHIVEDEP) $(PERL_ARCHIVE_AFTER) $(INST_DYNAMIC_DEP) + $(RM_F) $@ + $(LD) $(LDDLFLAGS) $(LDFROM) $(OTHERLDFLAGS) -o $@ $(MYEXTLIB) \ + $(PERL_ARCHIVE) $(LDLOADLIBS) $(PERL_ARCHIVE_AFTER) $(EXPORT_LIST) \ + $(INST_DYNAMIC_FIX) + $(CHMOD) $(PERM_RWX) $@ + $(NOECHO) $(RM_RF) $(BOOTSTRAP) + - $(CP_NONEMPTY) $(BOOTSTRAP) $(INST_BOOT) $(PERM_RW) + + +# --- MakeMaker static section: + +## $(INST_PM) has been moved to the all: target. +## It remains here for awhile to allow for old usage: "make static" +static :: $(FIRST_MAKEFILE) $(INST_STATIC) + $(NOECHO) $(NOOP) + + +# --- MakeMaker static_lib section: + +$(INST_STATIC) : $(OBJECT) $(MYEXTLIB) $(INST_ARCHAUTODIR)$(DFSEP).exists + $(RM_RF) $@ + $(AR) $(AR_STATIC_ARGS) $@ $(OBJECT) && $(RANLIB) $@ + $(CHMOD) $(PERM_RWX) $@ + $(NOECHO) $(ECHO) "$(EXTRALIBS)" > "$(INST_ARCHAUTODIR)/extralibs.ld" + + +# --- MakeMaker manifypods section: + +POD2MAN_EXE = $(PERLRUN) "-MExtUtils::Command::MM" -e pod2man "--" +POD2MAN = $(POD2MAN_EXE) + + +manifypods : pure_all \ + MD5.pm + $(NOECHO) $(POD2MAN) --section=$(MAN3EXT) --perm_rw=$(PERM_RW) -u \ + MD5.pm $(INST_MAN3DIR)/MD5.$(MAN3EXT) + + + + +# --- MakeMaker processPL section: + + +# --- MakeMaker installbin section: + + +# --- MakeMaker subdirs section: + +# none + +# --- MakeMaker clean_subdirs section: +clean_subdirs : + $(NOECHO) $(NOOP) + + +# --- MakeMaker clean section: + +# Delete temporary files but do not touch installed files. We don't delete +# the Makefile here so a later make realclean still has a makefile to use. + +clean :: clean_subdirs + - $(RM_F) \ + $(BASEEXT).bso $(BASEEXT).def \ + $(BASEEXT).exp $(BASEEXT).x \ + $(BOOTSTRAP) $(INST_ARCHAUTODIR)/extralibs.all \ + $(INST_ARCHAUTODIR)/extralibs.ld $(MAKE_APERL_FILE) \ + *$(LIB_EXT) *$(OBJ_EXT) \ + *perl.core MD5.c \ + MYMETA.json MYMETA.yml \ + blibdirs.ts core \ + core.*perl.*.? core.[0-9] \ + core.[0-9][0-9] core.[0-9][0-9][0-9] \ + core.[0-9][0-9][0-9][0-9] core.[0-9][0-9][0-9][0-9][0-9] \ + lib$(BASEEXT).def mon.out \ + perl perl$(EXE_EXT) \ + perl.exe perlmain.c \ + pm_to_blib pm_to_blib.ts \ + so_locations tmon.out + - $(RM_RF) \ + blib + $(NOECHO) $(RM_F) $(MAKEFILE_OLD) + - $(MV) $(FIRST_MAKEFILE) $(MAKEFILE_OLD) $(DEV_NULL) + + +# --- MakeMaker realclean_subdirs section: +realclean_subdirs : + $(NOECHO) $(NOOP) + + +# --- MakeMaker realclean section: +# Delete temporary files (via clean) and also delete dist files +realclean purge :: clean realclean_subdirs + - $(RM_F) \ + $(OBJECT) $(MAKEFILE_OLD) \ + $(FIRST_MAKEFILE) + - $(RM_RF) \ + $(DISTVNAME) + + +# --- MakeMaker metafile section: +metafile : create_distdir + $(NOECHO) $(ECHO) Generating META.yml + $(NOECHO) $(ECHO) '---' > META_new.yml + $(NOECHO) $(ECHO) 'abstract: unknown' >> META_new.yml + $(NOECHO) $(ECHO) 'author:' >> META_new.yml + $(NOECHO) $(ECHO) ' - unknown' >> META_new.yml + $(NOECHO) $(ECHO) 'build_requires:' >> META_new.yml + $(NOECHO) $(ECHO) ' ExtUtils::MakeMaker: '\''0'\''' >> META_new.yml + $(NOECHO) $(ECHO) 'configure_requires:' >> META_new.yml + $(NOECHO) $(ECHO) ' ExtUtils::MakeMaker: '\''0'\''' >> META_new.yml + $(NOECHO) $(ECHO) 'dynamic_config: 1' >> META_new.yml + $(NOECHO) $(ECHO) 'generated_by: '\''ExtUtils::MakeMaker version 7.0401, CPAN::Meta::Converter version 2.150001'\''' >> META_new.yml + $(NOECHO) $(ECHO) 'license: unknown' >> META_new.yml + $(NOECHO) $(ECHO) 'meta-spec:' >> META_new.yml + $(NOECHO) $(ECHO) ' url: http://module-build.sourceforge.net/META-spec-v1.4.html' >> META_new.yml + $(NOECHO) $(ECHO) ' version: '\''1.4'\''' >> META_new.yml + $(NOECHO) $(ECHO) 'name: MD5' >> META_new.yml + $(NOECHO) $(ECHO) 'no_index:' >> META_new.yml + $(NOECHO) $(ECHO) ' directory:' >> META_new.yml + $(NOECHO) $(ECHO) ' - t' >> META_new.yml + $(NOECHO) $(ECHO) ' - inc' >> META_new.yml + $(NOECHO) $(ECHO) 'requires: {}' >> META_new.yml + $(NOECHO) $(ECHO) 'version: '\''1.7'\''' >> META_new.yml + -$(NOECHO) $(MV) META_new.yml $(DISTVNAME)/META.yml + $(NOECHO) $(ECHO) Generating META.json + $(NOECHO) $(ECHO) '{' > META_new.json + $(NOECHO) $(ECHO) ' "abstract" : "unknown",' >> META_new.json + $(NOECHO) $(ECHO) ' "author" : [' >> META_new.json + $(NOECHO) $(ECHO) ' "unknown"' >> META_new.json + $(NOECHO) $(ECHO) ' ],' >> META_new.json + $(NOECHO) $(ECHO) ' "dynamic_config" : 1,' >> META_new.json + $(NOECHO) $(ECHO) ' "generated_by" : "ExtUtils::MakeMaker version 7.0401, CPAN::Meta::Converter version 2.150001",' >> META_new.json + $(NOECHO) $(ECHO) ' "license" : [' >> META_new.json + $(NOECHO) $(ECHO) ' "unknown"' >> META_new.json + $(NOECHO) $(ECHO) ' ],' >> META_new.json + $(NOECHO) $(ECHO) ' "meta-spec" : {' >> META_new.json + $(NOECHO) $(ECHO) ' "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",' >> META_new.json + $(NOECHO) $(ECHO) ' "version" : "2"' >> META_new.json + $(NOECHO) $(ECHO) ' },' >> META_new.json + $(NOECHO) $(ECHO) ' "name" : "MD5",' >> META_new.json + $(NOECHO) $(ECHO) ' "no_index" : {' >> META_new.json + $(NOECHO) $(ECHO) ' "directory" : [' >> META_new.json + $(NOECHO) $(ECHO) ' "t",' >> META_new.json + $(NOECHO) $(ECHO) ' "inc"' >> META_new.json + $(NOECHO) $(ECHO) ' ]' >> META_new.json + $(NOECHO) $(ECHO) ' },' >> META_new.json + $(NOECHO) $(ECHO) ' "prereqs" : {' >> META_new.json + $(NOECHO) $(ECHO) ' "build" : {' >> META_new.json + $(NOECHO) $(ECHO) ' "requires" : {' >> META_new.json + $(NOECHO) $(ECHO) ' "ExtUtils::MakeMaker" : "0"' >> META_new.json + $(NOECHO) $(ECHO) ' }' >> META_new.json + $(NOECHO) $(ECHO) ' },' >> META_new.json + $(NOECHO) $(ECHO) ' "configure" : {' >> META_new.json + $(NOECHO) $(ECHO) ' "requires" : {' >> META_new.json + $(NOECHO) $(ECHO) ' "ExtUtils::MakeMaker" : "0"' >> META_new.json + $(NOECHO) $(ECHO) ' }' >> META_new.json + $(NOECHO) $(ECHO) ' },' >> META_new.json + $(NOECHO) $(ECHO) ' "runtime" : {' >> META_new.json + $(NOECHO) $(ECHO) ' "requires" : {}' >> META_new.json + $(NOECHO) $(ECHO) ' }' >> META_new.json + $(NOECHO) $(ECHO) ' },' >> META_new.json + $(NOECHO) $(ECHO) ' "release_status" : "stable",' >> META_new.json + $(NOECHO) $(ECHO) ' "version" : "1.7"' >> META_new.json + $(NOECHO) $(ECHO) '}' >> META_new.json + -$(NOECHO) $(MV) META_new.json $(DISTVNAME)/META.json + + +# --- MakeMaker signature section: +signature : + cpansign -s + + +# --- MakeMaker dist_basics section: +distclean :: realclean distcheck + $(NOECHO) $(NOOP) + +distcheck : + $(PERLRUN) "-MExtUtils::Manifest=fullcheck" -e fullcheck + +skipcheck : + $(PERLRUN) "-MExtUtils::Manifest=skipcheck" -e skipcheck + +manifest : + $(PERLRUN) "-MExtUtils::Manifest=mkmanifest" -e mkmanifest + +veryclean : realclean + $(RM_F) *~ */*~ *.orig */*.orig *.bak */*.bak *.old */*.old + + + +# --- MakeMaker dist_core section: + +dist : $(DIST_DEFAULT) $(FIRST_MAKEFILE) + $(NOECHO) $(ABSPERLRUN) -l -e 'print '\''Warning: Makefile possibly out of date with $(VERSION_FROM)'\''' \ + -e ' if -e '\''$(VERSION_FROM)'\'' and -M '\''$(VERSION_FROM)'\'' < -M '\''$(FIRST_MAKEFILE)'\'';' -- + +tardist : $(DISTVNAME).tar$(SUFFIX) + $(NOECHO) $(NOOP) + +uutardist : $(DISTVNAME).tar$(SUFFIX) + uuencode $(DISTVNAME).tar$(SUFFIX) $(DISTVNAME).tar$(SUFFIX) > $(DISTVNAME).tar$(SUFFIX)_uu + $(NOECHO) $(ECHO) 'Created $(DISTVNAME).tar$(SUFFIX)_uu' + +$(DISTVNAME).tar$(SUFFIX) : distdir + $(PREOP) + $(TO_UNIX) + $(TAR) $(TARFLAGS) $(DISTVNAME).tar $(DISTVNAME) + $(RM_RF) $(DISTVNAME) + $(COMPRESS) $(DISTVNAME).tar + $(NOECHO) $(ECHO) 'Created $(DISTVNAME).tar$(SUFFIX)' + $(POSTOP) + +zipdist : $(DISTVNAME).zip + $(NOECHO) $(NOOP) + +$(DISTVNAME).zip : distdir + $(PREOP) + $(ZIP) $(ZIPFLAGS) $(DISTVNAME).zip $(DISTVNAME) + $(RM_RF) $(DISTVNAME) + $(NOECHO) $(ECHO) 'Created $(DISTVNAME).zip' + $(POSTOP) + +shdist : distdir + $(PREOP) + $(SHAR) $(DISTVNAME) > $(DISTVNAME).shar + $(RM_RF) $(DISTVNAME) + $(NOECHO) $(ECHO) 'Created $(DISTVNAME).shar' + $(POSTOP) + + +# --- MakeMaker distdir section: +create_distdir : + $(RM_RF) $(DISTVNAME) + $(PERLRUN) "-MExtUtils::Manifest=manicopy,maniread" \ + -e "manicopy(maniread(),'$(DISTVNAME)', '$(DIST_CP)');" + +distdir : create_distdir distmeta + $(NOECHO) $(NOOP) + + + +# --- MakeMaker dist_test section: +disttest : distdir + cd $(DISTVNAME) && $(ABSPERLRUN) Makefile.PL + cd $(DISTVNAME) && $(MAKE) $(PASTHRU) + cd $(DISTVNAME) && $(MAKE) test $(PASTHRU) + + + +# --- MakeMaker dist_ci section: + +ci : + $(PERLRUN) "-MExtUtils::Manifest=maniread" \ + -e "@all = keys %{ maniread() };" \ + -e "print(qq{Executing $(CI) @all\n}); system(qq{$(CI) @all});" \ + -e "print(qq{Executing $(RCS_LABEL) ...\n}); system(qq{$(RCS_LABEL) @all});" + + +# --- MakeMaker distmeta section: +distmeta : create_distdir metafile + $(NOECHO) cd $(DISTVNAME) && $(ABSPERLRUN) -MExtUtils::Manifest=maniadd -e 'exit unless -e q{META.yml};' \ + -e 'eval { maniadd({q{META.yml} => q{Module YAML meta-data (added by MakeMaker)}}) }' \ + -e ' or print "Could not add META.yml to MANIFEST: $$$${'\''@'\''}\n"' -- + $(NOECHO) cd $(DISTVNAME) && $(ABSPERLRUN) -MExtUtils::Manifest=maniadd -e 'exit unless -f q{META.json};' \ + -e 'eval { maniadd({q{META.json} => q{Module JSON meta-data (added by MakeMaker)}}) }' \ + -e ' or print "Could not add META.json to MANIFEST: $$$${'\''@'\''}\n"' -- + + + +# --- MakeMaker distsignature section: +distsignature : create_distdir + $(NOECHO) cd $(DISTVNAME) && $(ABSPERLRUN) -MExtUtils::Manifest=maniadd -e 'eval { maniadd({q{SIGNATURE} => q{Public-key signature (added by MakeMaker)}}) }' \ + -e ' or print "Could not add SIGNATURE to MANIFEST: $$$${'\''@'\''}\n"' -- + $(NOECHO) cd $(DISTVNAME) && $(TOUCH) SIGNATURE + cd $(DISTVNAME) && cpansign -s + + + +# --- MakeMaker install section: + +install :: pure_install doc_install + $(NOECHO) $(NOOP) + +install_perl :: pure_perl_install doc_perl_install + $(NOECHO) $(NOOP) + +install_site :: pure_site_install doc_site_install + $(NOECHO) $(NOOP) + +install_vendor :: pure_vendor_install doc_vendor_install + $(NOECHO) $(NOOP) + +pure_install :: pure_$(INSTALLDIRS)_install + $(NOECHO) $(NOOP) + +doc_install :: doc_$(INSTALLDIRS)_install + $(NOECHO) $(NOOP) + +pure__install : pure_site_install + $(NOECHO) $(ECHO) INSTALLDIRS not defined, defaulting to INSTALLDIRS=site + +doc__install : doc_site_install + $(NOECHO) $(ECHO) INSTALLDIRS not defined, defaulting to INSTALLDIRS=site + +pure_perl_install :: all + $(NOECHO) umask 022; $(MOD_INSTALL) \ + "$(INST_LIB)" "$(DESTINSTALLPRIVLIB)" \ + "$(INST_ARCHLIB)" "$(DESTINSTALLARCHLIB)" \ + "$(INST_BIN)" "$(DESTINSTALLBIN)" \ + "$(INST_SCRIPT)" "$(DESTINSTALLSCRIPT)" \ + "$(INST_MAN1DIR)" "$(DESTINSTALLMAN1DIR)" \ + "$(INST_MAN3DIR)" "$(DESTINSTALLMAN3DIR)" + $(NOECHO) $(WARN_IF_OLD_PACKLIST) \ + "$(SITEARCHEXP)/auto/$(FULLEXT)" + + +pure_site_install :: all + $(NOECHO) umask 02; $(MOD_INSTALL) \ + read "$(SITEARCHEXP)/auto/$(FULLEXT)/.packlist" \ + write "$(DESTINSTALLSITEARCH)/auto/$(FULLEXT)/.packlist" \ + "$(INST_LIB)" "$(DESTINSTALLSITELIB)" \ + "$(INST_ARCHLIB)" "$(DESTINSTALLSITEARCH)" \ + "$(INST_BIN)" "$(DESTINSTALLSITEBIN)" \ + "$(INST_SCRIPT)" "$(DESTINSTALLSITESCRIPT)" \ + "$(INST_MAN1DIR)" "$(DESTINSTALLSITEMAN1DIR)" \ + "$(INST_MAN3DIR)" "$(DESTINSTALLSITEMAN3DIR)" + $(NOECHO) $(WARN_IF_OLD_PACKLIST) \ + "$(PERL_ARCHLIB)/auto/$(FULLEXT)" + +pure_vendor_install :: all + $(NOECHO) umask 022; $(MOD_INSTALL) \ + "$(INST_LIB)" "$(DESTINSTALLVENDORLIB)" \ + "$(INST_ARCHLIB)" "$(DESTINSTALLVENDORARCH)" \ + "$(INST_BIN)" "$(DESTINSTALLVENDORBIN)" \ + "$(INST_SCRIPT)" "$(DESTINSTALLVENDORSCRIPT)" \ + "$(INST_MAN1DIR)" "$(DESTINSTALLVENDORMAN1DIR)" \ + "$(INST_MAN3DIR)" "$(DESTINSTALLVENDORMAN3DIR)" + + +doc_perl_install :: all + +doc_site_install :: all + $(NOECHO) $(ECHO) Appending installation info to "$(DESTINSTALLSITEARCH)/perllocal.pod" + -$(NOECHO) umask 02; $(MKPATH) "$(DESTINSTALLSITEARCH)" + -$(NOECHO) umask 02; $(DOC_INSTALL) \ + "Module" "$(NAME)" \ + "installed into" $(INSTALLSITELIB) \ + LINKTYPE "$(LINKTYPE)" \ + VERSION "$(VERSION)" \ + EXE_FILES "$(EXE_FILES)" \ + >> "$(DESTINSTALLSITEARCH)/perllocal.pod" + +doc_vendor_install :: all + + +uninstall :: uninstall_from_$(INSTALLDIRS)dirs + $(NOECHO) $(NOOP) + +uninstall_from_perldirs :: + +uninstall_from_sitedirs :: + $(NOECHO) $(UNINSTALL) "$(SITEARCHEXP)/auto/$(FULLEXT)/.packlist" + +uninstall_from_vendordirs :: + + +# --- MakeMaker force section: +# Phony target to force checking subdirectories. +FORCE : + $(NOECHO) $(NOOP) + + +# --- MakeMaker perldepend section: +PERL_HDRS = \ + $(PERL_INCDEP)/EXTERN.h \ + $(PERL_INCDEP)/INTERN.h \ + $(PERL_INCDEP)/XSUB.h \ + $(PERL_INCDEP)/av.h \ + $(PERL_INCDEP)/bitcount.h \ + $(PERL_INCDEP)/charclass_invlists.h \ + $(PERL_INCDEP)/config.h \ + $(PERL_INCDEP)/cop.h \ + $(PERL_INCDEP)/cv.h \ + $(PERL_INCDEP)/dosish.h \ + $(PERL_INCDEP)/ebcdic_tables.h \ + $(PERL_INCDEP)/embed.h \ + $(PERL_INCDEP)/embedvar.h \ + $(PERL_INCDEP)/fakesdio.h \ + $(PERL_INCDEP)/feature.h \ + $(PERL_INCDEP)/form.h \ + $(PERL_INCDEP)/git_version.h \ + $(PERL_INCDEP)/gv.h \ + $(PERL_INCDEP)/handy.h \ + $(PERL_INCDEP)/hv.h \ + $(PERL_INCDEP)/hv_func.h \ + $(PERL_INCDEP)/inline.h \ + $(PERL_INCDEP)/intrpvar.h \ + $(PERL_INCDEP)/iperlsys.h \ + $(PERL_INCDEP)/keywords.h \ + $(PERL_INCDEP)/l1_char_class_tab.h \ + $(PERL_INCDEP)/malloc_ctl.h \ + $(PERL_INCDEP)/metaconfig.h \ + $(PERL_INCDEP)/mg.h \ + $(PERL_INCDEP)/mg_data.h \ + $(PERL_INCDEP)/mg_raw.h \ + $(PERL_INCDEP)/mg_vtable.h \ + $(PERL_INCDEP)/mydtrace.h \ + $(PERL_INCDEP)/nostdio.h \ + $(PERL_INCDEP)/op.h \ + $(PERL_INCDEP)/op_reg_common.h \ + $(PERL_INCDEP)/opcode.h \ + $(PERL_INCDEP)/opnames.h \ + $(PERL_INCDEP)/overload.h \ + $(PERL_INCDEP)/pad.h \ + $(PERL_INCDEP)/parser.h \ + $(PERL_INCDEP)/patchlevel-debian.h \ + $(PERL_INCDEP)/patchlevel.h \ + $(PERL_INCDEP)/perl.h \ + $(PERL_INCDEP)/perlapi.h \ + $(PERL_INCDEP)/perlio.h \ + $(PERL_INCDEP)/perliol.h \ + $(PERL_INCDEP)/perlsdio.h \ + $(PERL_INCDEP)/perlvars.h \ + $(PERL_INCDEP)/perly.h \ + $(PERL_INCDEP)/pp.h \ + $(PERL_INCDEP)/pp_proto.h \ + $(PERL_INCDEP)/proto.h \ + $(PERL_INCDEP)/reentr.h \ + $(PERL_INCDEP)/regcharclass.h \ + $(PERL_INCDEP)/regcomp.h \ + $(PERL_INCDEP)/regexp.h \ + $(PERL_INCDEP)/regnodes.h \ + $(PERL_INCDEP)/scope.h \ + $(PERL_INCDEP)/sv.h \ + $(PERL_INCDEP)/thread.h \ + $(PERL_INCDEP)/time64.h \ + $(PERL_INCDEP)/time64_config.h \ + $(PERL_INCDEP)/uconfig.h \ + $(PERL_INCDEP)/unicode_constants.h \ + $(PERL_INCDEP)/unixish.h \ + $(PERL_INCDEP)/utf8.h \ + $(PERL_INCDEP)/utfebcdic.h \ + $(PERL_INCDEP)/util.h \ + $(PERL_INCDEP)/uudmap.h \ + $(PERL_INCDEP)/vutil.h \ + $(PERL_INCDEP)/warnings.h + +$(OBJECT) : $(PERL_HDRS) + +MD5.c : $(XSUBPPDEPS) + + +# --- MakeMaker makefile section: + +$(OBJECT) : $(FIRST_MAKEFILE) + +# We take a very conservative approach here, but it's worth it. +# We move Makefile to Makefile.old here to avoid gnu make looping. +$(FIRST_MAKEFILE) : Makefile.PL $(CONFIGDEP) + $(NOECHO) $(ECHO) "Makefile out-of-date with respect to $?" + $(NOECHO) $(ECHO) "Cleaning current config before rebuilding Makefile..." + -$(NOECHO) $(RM_F) $(MAKEFILE_OLD) + -$(NOECHO) $(MV) $(FIRST_MAKEFILE) $(MAKEFILE_OLD) + - $(MAKE) $(USEMAKEFILE) $(MAKEFILE_OLD) clean $(DEV_NULL) + $(PERLRUN) Makefile.PL + $(NOECHO) $(ECHO) "==> Your Makefile has been rebuilt. <==" + $(NOECHO) $(ECHO) "==> Please rerun the $(MAKE) command. <==" + $(FALSE) + + + +# --- MakeMaker staticmake section: + +# --- MakeMaker makeaperl section --- +MAP_TARGET = perl +FULLPERL = "/usr/bin/perl" + +$(MAP_TARGET) :: static $(MAKE_APERL_FILE) + $(MAKE) $(USEMAKEFILE) $(MAKE_APERL_FILE) $@ + +$(MAKE_APERL_FILE) : $(FIRST_MAKEFILE) pm_to_blib + $(NOECHO) $(ECHO) Writing \"$(MAKE_APERL_FILE)\" for this $(MAP_TARGET) + $(NOECHO) $(PERLRUNINST) \ + Makefile.PL DIR="" \ + MAKEFILE=$(MAKE_APERL_FILE) LINKTYPE=static \ + MAKEAPERL=1 NORECURS=1 CCCDLFLAGS= + + +# --- MakeMaker test section: + +TEST_VERBOSE=0 +TEST_TYPE=test_$(LINKTYPE) +TEST_FILE = test.pl +TEST_FILES = +TESTDB_SW = -d + +testdb :: testdb_$(LINKTYPE) + +test :: $(TEST_TYPE) subdirs-test + +subdirs-test :: + $(NOECHO) $(NOOP) + + +test_dynamic :: pure_all + PERL_DL_NONLAZY=1 $(FULLPERLRUN) "-I$(INST_LIB)" "-I$(INST_ARCHLIB)" $(TEST_FILE) + +testdb_dynamic :: pure_all + PERL_DL_NONLAZY=1 $(FULLPERLRUN) $(TESTDB_SW) "-I$(INST_LIB)" "-I$(INST_ARCHLIB)" $(TEST_FILE) + +test_ : test_dynamic + +test_static :: pure_all $(MAP_TARGET) + PERL_DL_NONLAZY=1 ./$(MAP_TARGET) "-I$(INST_LIB)" "-I$(INST_ARCHLIB)" $(TEST_FILE) + +testdb_static :: pure_all $(MAP_TARGET) + PERL_DL_NONLAZY=1 ./$(MAP_TARGET) $(TESTDB_SW) "-I$(INST_LIB)" "-I$(INST_ARCHLIB)" $(TEST_FILE) + + + +# --- MakeMaker ppd section: +# Creates a PPD (Perl Package Description) for a binary distribution. +ppd : + $(NOECHO) $(ECHO) '' > $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) '' >> $(DISTNAME).ppd + + +# --- MakeMaker pm_to_blib section: + +pm_to_blib : $(FIRST_MAKEFILE) $(TO_INST_PM) + $(NOECHO) $(ABSPERLRUN) -MExtUtils::Install -e 'pm_to_blib({@ARGV}, '\''$(INST_LIB)/auto'\'', q[$(PM_FILTER)], '\''$(PERM_DIR)'\'')' -- \ + MD5.pm $(INST_LIB)/MD5.pm + $(NOECHO) $(TOUCH) pm_to_blib + + +# --- MakeMaker selfdocument section: + + +# --- MakeMaker postamble section: + + +# End. diff --git a/perlmodules/MD5-1.7/README b/perlmodules/MD5-1.7/README new file mode 100644 index 0000000..cda738b --- /dev/null +++ b/perlmodules/MD5-1.7/README @@ -0,0 +1,42 @@ +MD5 Extension Version 1.7 + +This is a Perl5 extension interface to the RSA Data Security Inc. MD5 +Message Digest algorithm. Documentation is in MD5.pod. + +To build the extension, unpack this distribution under the ext/ +directory of your Perl source distribution, create the Makefile using +'perl Makefile.PL' and do a 'make'. + +Note that the MD5.xs file uses the "PROTOTYPES: DISABLE" facility +which only became available in late betas pf perl 5.002. If you are +using a version which does not support this then merely remove +this line. + +The mddriver.pl script gives a simple example of how to use the +routines. In particular 'perl mddriver.pl -x' will perform a quick +test of the routines to see if they produce the expected output. The +use of "make test" will perform a more comprehensive test. (WARNING: +You should not run mddriver.pl directly in the MD5 directory when using +dynamic linking as on some systems it will dynamically link to object +files in the current directory which may not give the correct +behaviour. This is believed to affect at least AIX and IRIX. A similar +caveat applies to the direct use of the test.pl script). + +The module is known to work (using static or dynamic linking) on at +least AIX, Solaris, HP-UX and IRIX. It should work on other +"reasonable" UNIX-like platforms (for an unspecified definition of the +word "reasonable" :-) + +Support is also provided for 64-bit platforms. This should be detected +and handled automatically. See the entry for version 1.7 in the +Changes file for further details. + +Bugs, queries, plaudits to + + Neil Winton + +* Neil Winton Post Point P5 * +* N.Winton@axion.bt.co.uk BT Laboratories * +* Tel +44 1473 646079 Martlesham Heath * +* Fax +44 1473 643306 IPSWICH IP5 7RE, UK * + diff --git a/perlmodules/MD5-1.7/examples/mddriver.pl b/perlmodules/MD5-1.7/examples/mddriver.pl new file mode 100644 index 0000000..82c99e5 --- /dev/null +++ b/perlmodules/MD5-1.7/examples/mddriver.pl @@ -0,0 +1,69 @@ +#!/usr/local/bin/perl +# SCCS ID @(#)mddriver.pl 1.3 95/05/01 + +require 'getopts.pl'; +use MD5; +sub DoTest; + +&Getopts('s:x'); + +$md5 = new MD5; + +if (defined($opt_s)) +{ + $md5->add($opt_s); + $digest = $md5->digest(); + print("MD5(\"$opt_s\") = " . unpack("H*", $digest) . "\n"); +} +elsif ($opt_x) +{ + DoTest("", "d41d8cd98f00b204e9800998ecf8427e"); + DoTest("a", "0cc175b9c0f1b6a831c399e269772661"); + DoTest("abc", "900150983cd24fb0d6963f7d28e17f72"); + DoTest("message digest", "f96b697d7cb7938d525a2f31aaf161d0"); + DoTest("abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b"); + DoTest("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "d174ab98d277d9f5a5611c2c9f419d9f"); + DoTest("12345678901234567890123456789012345678901234567890123456789012345678901234567890", + "57edf4a22be3c955ac49da2e2107b67a"); +} +else +{ + if ($#ARGV >= 0) + { + foreach $ARGV (@ARGV) + { + die "Can't open file '$ARGV' ($!)\n" unless open(ARGV, $ARGV); + + $md5->reset(); + $md5->addfile(ARGV); + $hex = $md5->hexdigest(); + print "MD5($ARGV) = $hex\n"; + + close(ARGV); + } + } + else + { + $md5->reset(); + $md5->addfile(STDIN); + $hex = $md5->hexdigest(); + + print "$hex\n"; + } +} + +exit 0; + +sub DoTest +{ + my ($str, $expect) = @_; + my ($digest, $hex); + my $md5 = new MD5; + + $md5->add($str); + $digest = $md5->digest(); + $hex = unpack("H*", $digest); + + print "MD5(\"$str\") =>\nEXPECT: $expect\nRESULT: $hex\n" +} diff --git a/perlmodules/MD5-1.7/examples/twdigest.pl b/perlmodules/MD5-1.7/examples/twdigest.pl new file mode 100644 index 0000000..bf6effb --- /dev/null +++ b/perlmodules/MD5-1.7/examples/twdigest.pl @@ -0,0 +1,35 @@ +#!/usr/local/bin/perl + +use MD5; + +# +# twdigest -- format MD5 digest like TripWire does +# +# This converts the md5->digest binary string to +# 64-radix ascii, given the base-vector: +# 0 - 9, A - Z, a - z, :, . +# + +sub twdigest { + my($digest) = @_; + my(@chunks, $bits); + + # Convert to ASCII bit-string + $bits = unpack("B*", $digest); + + # Round up length to multiple of 6 by prepending zeros + $bits = ("0" x ((6 - (length($bits) % 6)) % 6)) . $bits; + + # Split into 6-bit chunks + @chunks = grep {$_ ne ''} (split(/(.{6})/, $bits, -1)); + + # Convert each 6-bit value to a single character + foreach (@chunks) + { + $_ = pack("B8", "00" . $_); + tr/\000-\011\012-\043\044-\075\076\077/0-9A-Za-z:./; + } + + # Join all of the chunks into one string + join('', @chunks); +} diff --git a/perlmodules/MD5-1.7/global.h b/perlmodules/MD5-1.7/global.h new file mode 100644 index 0000000..741a46f --- /dev/null +++ b/perlmodules/MD5-1.7/global.h @@ -0,0 +1,49 @@ +/* GLOBAL.H - RSAREF types and constants + */ + +/* PROTOTYPES should be set to one if and only if the compiler supports + function argument prototyping. +The following makes PROTOTYPES default to 0 if it has not already + been defined with C compiler flags. + */ +#ifndef PROTOTYPES +#define PROTOTYPES 0 +#endif + +/* POINTER defines a generic pointer type */ +typedef unsigned char *POINTER; + +/* UINT2 defines a two byte word */ +typedef unsigned short int UINT2; + +/* UINT4 defines a four byte word. +We use the Perl byte-order definition to discover if a long has more than + 4 bytes. If so we will try to use an unsigned int. This is OK for DEC + Alpha but may not work everywhere. See the TO32 definition below. + */ +#if (PERL_BYTEORDER <= 4321) || defined(UINT4_IS_LONG) +typedef unsigned long UINT4; +#else +typedef unsigned int UINT4; +#endif + +/* TO32 ensures that UINT4 values are truncated to 32 bits. +A Cray has short, int and long all at 64 bits so we need to apply this + macro to reduce UINT4 values to 32 bits at appropriate places. If UINT4 + really does have 32 bits then this is a no-op. + */ +#if defined(cray) || defined(TRUNCATE_UINT4) +#define TO32(x) ((x) & 0xffffffff) +#else +#define TO32(x) (x) +#endif + +/* PROTO_LIST is defined depending on how PROTOTYPES is defined above. +If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it + returns an empty list. + */ +#if PROTOTYPES +#define PROTO_LIST(list) list +#else +#define PROTO_LIST(list) () +#endif diff --git a/perlmodules/MD5-1.7/md5.h b/perlmodules/MD5-1.7/md5.h new file mode 100644 index 0000000..64c48d8 --- /dev/null +++ b/perlmodules/MD5-1.7/md5.h @@ -0,0 +1,36 @@ +/* MD5.H - header file for MD5C.C + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +/* MD5 context. */ +typedef struct { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +void MD5Init PROTO_LIST ((MD5_CTX *)); +void MD5Update PROTO_LIST + ((MD5_CTX *, unsigned char *, unsigned long)); +void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); diff --git a/perlmodules/MD5-1.7/md5c.c b/perlmodules/MD5-1.7/md5c.c new file mode 100644 index 0000000..67186f4 --- /dev/null +++ b/perlmodules/MD5-1.7/md5c.c @@ -0,0 +1,351 @@ +/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +/* +** The following macro re-definitions added to work around a problem on +** Solaris where the original MD5 routines are already in /lib/libnsl.a. +** This causes dynamic linking of the module to fail. +** +** Thanks to Ken Pizzini (ken@spry.com) for finally nailing this one! +*/ + +#define MD5Init MD5Init_perl +#define MD5Update MD5Update_perl +#define MD5Final MD5Final_perl + +#include "global.h" +#include "md5.h" + +/* Constants for MD5Transform routine. + */ + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64])); +static void Encode PROTO_LIST + ((unsigned char *, UINT4 *, unsigned long)); +static void Decode PROTO_LIST + ((UINT4 *, unsigned char *, unsigned long)); +static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned long)); +static void MD5_memset PROTO_LIST ((POINTER, int, unsigned long)); + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) TO32((((x) & (y)) | ((~x) & (z)))) +#define G(x, y, z) TO32((((x) & (z)) | ((y) & (~z)))) +#define H(x, y, z) TO32(((x) ^ (y) ^ (z))) +#define I(x, y, z) TO32(((y) ^ ((x) | (~z)))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) TO32((((x) << (n)) | (TO32((x)) >> (32-(n))))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + TO32((a)); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + TO32((a)); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + TO32((a)); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + TO32((a)); \ + } + +/* MD5 initialization. Begins an MD5 operation, writing a new context. + */ +void MD5Init (context) +MD5_CTX *context; /* context */ +{ + context->count[0] = context->count[1] = 0; + /* Load magic initialization constants. +*/ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + */ +void MD5Update (context, input, inputLen) +MD5_CTX *context; /* context */ +unsigned char *input; /* input block */ +unsigned long inputLen; /* length of input block */ +{ + unsigned long i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned long)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if (TO32(context->count[0] += (inputLen << 3)) + < TO32(inputLen << 3)) + context->count[1]++; + context->count[1] += (inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. +*/ + if (inputLen >= partLen) { + MD5_memcpy + ((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + MD5_memcpy + ((POINTER)&context->buffer[index], (POINTER)&input[i], + inputLen-i); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + */ +void MD5Final (digest, context) +unsigned char digest[16]; /* message digest */ +MD5_CTX *context; /* context */ +{ + unsigned char bits[8]; + unsigned long index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. +*/ + index = (unsigned long)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update (context, bits, 8); + + /* Store state in digest */ + Encode (digest, context->state, 16); + + /* Zeroize sensitive information. +*/ + MD5_memset ((POINTER)context, 0, sizeof (*context)); +} + +/* MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform (state, block) +UINT4 state[4]; +unsigned char block[64]; +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; TO32(state[0]); + state[1] += b; TO32(state[1]); + state[2] += c; TO32(state[2]); + state[3] += d; TO32(state[3]); + + /* Zeroize sensitive information. + */ + MD5_memset ((POINTER)x, 0, sizeof (x)); +} + +/* Encodes input (UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode (output, input, len) +unsigned char *output; +UINT4 *input; +unsigned long len; +{ + unsigned long i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (UINT4). Assumes len is + a multiple of 4. + */ +static void Decode (output, input, len) +UINT4 *output; +unsigned char *input; +unsigned long len; +{ + unsigned long i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | + (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} + +/* Note: Replace "for loop" with standard memcpy if possible. + */ + +static void MD5_memcpy (output, input, len) +POINTER output; +POINTER input; +unsigned long len; +{ + unsigned long i; + + for (i = 0; i < len; i++) + output[i] = input[i]; +} + +/* Note: Replace "for loop" with standard memset if possible. + */ +static void MD5_memset (output, value, len) +POINTER output; +int value; +unsigned long len; +{ + unsigned long i; + + for (i = 0; i < len; i++) + ((char *)output)[i] = (char)value; +} diff --git a/perlmodules/MD5-1.7/test.pl b/perlmodules/MD5-1.7/test.pl new file mode 100644 index 0000000..2f543e5 --- /dev/null +++ b/perlmodules/MD5-1.7/test.pl @@ -0,0 +1,154 @@ +# SCCS ID @(#)test.pl 1.1 96/04/09 +# Before `make install' is performed this script should be runnable with +# `make test'. After `make install' it should work as `perl test.pl' + +######################### We start with some black magic to print on failure. + +# Change 1..1 below to 1..last_test_to_print . +# (It may become useful if the test is moved to ./t subdirectory.) + +BEGIN {print "1..14\n";} +END {print "not ok 1\n" unless $loaded;} +use MD5; +$loaded = 1; +print "ok 1\n"; + +######################### End of black magic. + +# Insert your test code below (better if it prints "ok 13" +# (correspondingly "not ok 13") depending on the success of chunk 13 +# of the test code): + +package MD5Test; + +# 2: Constructor + +print (($md5 = new MD5) ? "ok 2\n" : "not ok 2\n"); + +# 3: Basic test data as defined in RFC 1321 + +%data = ( + "" => "d41d8cd98f00b204e9800998ecf8427e", + "a" => "0cc175b9c0f1b6a831c399e269772661", + "abc" => "900150983cd24fb0d6963f7d28e17f72", + "message digest" + => "f96b697d7cb7938d525a2f31aaf161d0", + "abcdefghijklmnopqrstuvwxyz" + => "c3fcd3d76192e4007dfb496cca67e13b", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + => "d174ab98d277d9f5a5611c2c9f419d9f", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + => "57edf4a22be3c955ac49da2e2107b67a", +); + +$failed = 0; +foreach (sort(keys(%data))) +{ + $md5->reset; + $md5->add($_); + $digest = $md5->digest; + $hex = unpack("H*", $digest); + if ($hex ne $data{$_}) + { + $failed++; + } +} +print ($failed ? "not ok 3\n" : "ok 3\n"); + +# 4: Various flavours of file-handle to addfile + +open(F, "<$0"); + +$md5->reset; + +$md5->addfile(F); +$hex = $md5->hexdigest; +print ($hex ne '' ? "ok 4\n" : "not ok 4\n"); + +$orig = $hex; + +# 5: Fully qualified with ' operator + +seek(F, 0, 0); +$md5->reset; +$md5->addfile(MD5Test'F); +$hex = $md5->hexdigest; +print ($hex eq $orig ? "ok 5\n" : "not ok 5\n"); + +# 6: Fully qualified with :: operator + +seek(F, 0, 0); +$md5->reset; +$md5->addfile(MD5Test::F); +$hex = $md5->hexdigest; +print ($hex eq $orig ? "ok 6\n" : "not ok 6\n"); + +# 7: Type glob + +seek(F, 0, 0); +$md5->reset; +$md5->addfile(*F); +$hex = $md5->hexdigest; +print ($hex eq $orig ? "ok 7\n" : "not ok 7\n"); + +# 8: Type glob reference (the prefered mechanism) + +seek(F, 0, 0); +$md5->reset; +$md5->addfile(\*F); +$hex = $md5->hexdigest; +print ($hex eq $orig ? "ok 8\n" : "not ok 8\n"); + +# 9: File-handle passed by name (really the same as 6) + +seek(F, 0, 0); +$md5->reset; +$md5->addfile("MD5Test::F"); +$hex = $md5->hexdigest; +print ($hex eq $orig ? "ok 9\n" : "not ok 9\n"); + +# 10: Other ways of reading the data -- line at a time + +seek(F, 0, 0); +$md5->reset; +while () +{ + $md5->add($_); +} +$hex = $md5->hexdigest; +print ($hex eq $orig ? "ok 10\n" : "not ok 10\n"); + +# 11: Input lines as a list to add() + +seek(F, 0, 0); +$md5->reset; +$md5->add(); +$hex = $md5->hexdigest; +print ($hex eq $orig ? "ok 11\n" : "not ok 11\n"); + +# 12: Random chunks up to 128 bytes + +seek(F, 0, 0); +$md5->reset; +while (read(F, $hexata, (rand % 128) + 1)) +{ + $md5->add($hexata); +} +$hex = $md5->hexdigest; +print ($hex eq $orig ? "ok 12\n" : "not ok 12\n"); + +# 13: All the data at once + +seek(F, 0, 0); +$md5->reset; +undef $/; +$data = ; +$hex = $md5->hexhash($data); +print ($hex eq $orig ? "ok 13\n" : "not ok 13\n"); + +close(F); + +# 14: Using static member function + +$hex = MD5->hexhash($data); +print ($hex eq $orig ? "ok 14\n" : "not ok 14\n"); diff --git a/perlmodules/MD5-1.7/typemap b/perlmodules/MD5-1.7/typemap new file mode 100644 index 0000000..5c27408 --- /dev/null +++ b/perlmodules/MD5-1.7/typemap @@ -0,0 +1,3 @@ +# SCCS ID @(#)typemap 1.2 94/11/07 +TYPEMAP +MD5 T_PTROBJ diff --git a/perlmodules/mwx-1.21/Changes b/perlmodules/mwx-1.21/Changes new file mode 100644 index 0000000..f0c0712 --- /dev/null +++ b/perlmodules/mwx-1.21/Changes @@ -0,0 +1,6 @@ +Revision history for Perl extension mwx. + +0.01 Sun Jun 1 18:30:04 2003 + - original version; created by h2xs 1.21 with options + -X -n mwx + diff --git a/perlmodules/mwx-1.21/MANIFEST b/perlmodules/mwx-1.21/MANIFEST new file mode 100644 index 0000000..02dfa30 --- /dev/null +++ b/perlmodules/mwx-1.21/MANIFEST @@ -0,0 +1,6 @@ +Changes +Makefile.PL +MANIFEST +mwx.pm +README +test.pl diff --git a/perlmodules/mwx-1.21/Makefile.PL b/perlmodules/mwx-1.21/Makefile.PL new file mode 100644 index 0000000..b5990ff --- /dev/null +++ b/perlmodules/mwx-1.21/Makefile.PL @@ -0,0 +1,17 @@ +use ExtUtils::MakeMaker; +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. + +WriteMakefile( + 'NAME' => 'mwx', + 'VERSION_FROM' => 'mwx.pm', # finds $VERSION + 'PREREQ_PM' => { Net::SMTP => 0, + MD5 => 0, + Net::NIS => 0, + Math::BigInt => 0, + Time::HiRes => 0, + Term::ReadKey => 0}, + ($] >= 5.005 ? ## Add these new keywords supported since 5.005 + (ABSTRACT_FROM => 'mwx.pm', # retrieve abstract from module + AUTHOR => 'M.Wesemann ') : ()), +); diff --git a/perlmodules/mwx-1.21/Makefile.old b/perlmodules/mwx-1.21/Makefile.old new file mode 100644 index 0000000..fef5f15 --- /dev/null +++ b/perlmodules/mwx-1.21/Makefile.old @@ -0,0 +1,864 @@ +# This Makefile is for the mwx extension to perl. +# +# It was generated automatically by MakeMaker version +# 7.0401 (Revision: 70401) from the contents of +# Makefile.PL. Don't edit this file, edit Makefile.PL instead. +# +# ANY CHANGES MADE HERE WILL BE LOST! +# +# MakeMaker ARGV: () +# + +# MakeMaker Parameters: + +# ABSTRACT_FROM => q[mwx.pm] +# AUTHOR => [q[M.Wesemann ]] +# BUILD_REQUIRES => { } +# CONFIGURE_REQUIRES => { } +# NAME => q[mwx] +# PREREQ_PM => { MD5=>q[0], Math::BigInt=>q[0], Net::NIS=>q[0], Net::SMTP=>q[0], Term::ReadKey=>q[0], Time::HiRes=>q[0] } +# TEST_REQUIRES => { } +# VERSION_FROM => q[mwx.pm] + +# --- MakeMaker post_initialize section: + + +# --- MakeMaker const_config section: + +# These definitions are from config.sh (via /usr/lib/x86_64-linux-gnu/perl/5.22/Config.pm). +# They may have been overridden via Makefile.PL or on the command line. +AR = ar +CC = x86_64-linux-gnu-gcc +CCCDLFLAGS = -fPIC +CCDLFLAGS = -Wl,-E +DLEXT = so +DLSRC = dl_dlopen.xs +EXE_EXT = +FULL_AR = /usr/bin/ar +LD = x86_64-linux-gnu-gcc +LDDLFLAGS = -shared -L/usr/local/lib -fstack-protector-strong +LDFLAGS = -fstack-protector-strong -L/usr/local/lib +LIBC = libc-2.23.so +LIB_EXT = .a +OBJ_EXT = .o +OSNAME = linux +OSVERS = 3.16.0 +RANLIB = : +SITELIBEXP = /usr/local/share/perl/5.22.1 +SITEARCHEXP = /usr/local/lib/x86_64-linux-gnu/perl/5.22.1 +SO = so +VENDORARCHEXP = /usr/lib/x86_64-linux-gnu/perl5/5.22 +VENDORLIBEXP = /usr/share/perl5 + + +# --- MakeMaker constants section: +AR_STATIC_ARGS = cr +DIRFILESEP = / +DFSEP = $(DIRFILESEP) +NAME = mwx +NAME_SYM = mwx +VERSION = 1.21 +VERSION_MACRO = VERSION +VERSION_SYM = 1_21 +DEFINE_VERSION = -D$(VERSION_MACRO)=\"$(VERSION)\" +XS_VERSION = 1.21 +XS_VERSION_MACRO = XS_VERSION +XS_DEFINE_VERSION = -D$(XS_VERSION_MACRO)=\"$(XS_VERSION)\" +INST_ARCHLIB = blib/arch +INST_SCRIPT = blib/script +INST_BIN = blib/bin +INST_LIB = blib/lib +INST_MAN1DIR = blib/man1 +INST_MAN3DIR = blib/man3 +MAN1EXT = 1p +MAN3EXT = 3pm +INSTALLDIRS = site +DESTDIR = +PREFIX = $(SITEPREFIX) +PERLPREFIX = /usr +SITEPREFIX = /usr/local +VENDORPREFIX = /usr +INSTALLPRIVLIB = /usr/share/perl/5.22 +DESTINSTALLPRIVLIB = $(DESTDIR)$(INSTALLPRIVLIB) +INSTALLSITELIB = /usr/local/share/perl/5.22.1 +DESTINSTALLSITELIB = $(DESTDIR)$(INSTALLSITELIB) +INSTALLVENDORLIB = /usr/share/perl5 +DESTINSTALLVENDORLIB = $(DESTDIR)$(INSTALLVENDORLIB) +INSTALLARCHLIB = /usr/lib/x86_64-linux-gnu/perl/5.22 +DESTINSTALLARCHLIB = $(DESTDIR)$(INSTALLARCHLIB) +INSTALLSITEARCH = /usr/local/lib/x86_64-linux-gnu/perl/5.22.1 +DESTINSTALLSITEARCH = $(DESTDIR)$(INSTALLSITEARCH) +INSTALLVENDORARCH = /usr/lib/x86_64-linux-gnu/perl5/5.22 +DESTINSTALLVENDORARCH = $(DESTDIR)$(INSTALLVENDORARCH) +INSTALLBIN = /usr/bin +DESTINSTALLBIN = $(DESTDIR)$(INSTALLBIN) +INSTALLSITEBIN = /usr/local/bin +DESTINSTALLSITEBIN = $(DESTDIR)$(INSTALLSITEBIN) +INSTALLVENDORBIN = /usr/bin +DESTINSTALLVENDORBIN = $(DESTDIR)$(INSTALLVENDORBIN) +INSTALLSCRIPT = /usr/bin +DESTINSTALLSCRIPT = $(DESTDIR)$(INSTALLSCRIPT) +INSTALLSITESCRIPT = /usr/local/bin +DESTINSTALLSITESCRIPT = $(DESTDIR)$(INSTALLSITESCRIPT) +INSTALLVENDORSCRIPT = /usr/bin +DESTINSTALLVENDORSCRIPT = $(DESTDIR)$(INSTALLVENDORSCRIPT) +INSTALLMAN1DIR = /usr/share/man/man1 +DESTINSTALLMAN1DIR = $(DESTDIR)$(INSTALLMAN1DIR) +INSTALLSITEMAN1DIR = /usr/local/man/man1 +DESTINSTALLSITEMAN1DIR = $(DESTDIR)$(INSTALLSITEMAN1DIR) +INSTALLVENDORMAN1DIR = /usr/share/man/man1 +DESTINSTALLVENDORMAN1DIR = $(DESTDIR)$(INSTALLVENDORMAN1DIR) +INSTALLMAN3DIR = /usr/share/man/man3 +DESTINSTALLMAN3DIR = $(DESTDIR)$(INSTALLMAN3DIR) +INSTALLSITEMAN3DIR = /usr/local/man/man3 +DESTINSTALLSITEMAN3DIR = $(DESTDIR)$(INSTALLSITEMAN3DIR) +INSTALLVENDORMAN3DIR = /usr/share/man/man3 +DESTINSTALLVENDORMAN3DIR = $(DESTDIR)$(INSTALLVENDORMAN3DIR) +PERL_LIB = /usr/share/perl/5.22 +PERL_ARCHLIB = /usr/lib/x86_64-linux-gnu/perl/5.22 +PERL_ARCHLIBDEP = /usr/lib/x86_64-linux-gnu/perl/5.22 +LIBPERL_A = libperl.a +FIRST_MAKEFILE = Makefile +MAKEFILE_OLD = Makefile.old +MAKE_APERL_FILE = Makefile.aperl +PERLMAINCC = $(CC) +PERL_INC = /usr/lib/x86_64-linux-gnu/perl/5.22/CORE +PERL_INCDEP = /usr/lib/x86_64-linux-gnu/perl/5.22/CORE +PERL = "/usr/bin/perl" +FULLPERL = "/usr/bin/perl" +ABSPERL = $(PERL) +PERLRUN = $(PERL) +FULLPERLRUN = $(FULLPERL) +ABSPERLRUN = $(ABSPERL) +PERLRUNINST = $(PERLRUN) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)" +FULLPERLRUNINST = $(FULLPERLRUN) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)" +ABSPERLRUNINST = $(ABSPERLRUN) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)" +PERL_CORE = 0 +PERM_DIR = 755 +PERM_RW = 644 +PERM_RWX = 755 + +MAKEMAKER = /usr/share/perl/5.22/ExtUtils/MakeMaker.pm +MM_VERSION = 7.0401 +MM_REVISION = 70401 + +# FULLEXT = Pathname for extension directory (eg Foo/Bar/Oracle). +# BASEEXT = Basename part of FULLEXT. May be just equal FULLEXT. (eg Oracle) +# PARENT_NAME = NAME without BASEEXT and no trailing :: (eg Foo::Bar) +# DLBASE = Basename part of dynamic library. May be just equal BASEEXT. +MAKE = make +FULLEXT = mwx +BASEEXT = mwx +PARENT_NAME = +DLBASE = $(BASEEXT) +VERSION_FROM = mwx.pm +OBJECT = +LDFROM = $(OBJECT) +LINKTYPE = dynamic +BOOTDEP = + +# Handy lists of source code files: +XS_FILES = +C_FILES = +O_FILES = +H_FILES = +MAN1PODS = +MAN3PODS = mwx.pm + +# Where is the Config information that we are using/depend on +CONFIGDEP = $(PERL_ARCHLIBDEP)$(DFSEP)Config.pm $(PERL_INCDEP)$(DFSEP)config.h + +# Where to build things +INST_LIBDIR = $(INST_LIB) +INST_ARCHLIBDIR = $(INST_ARCHLIB) + +INST_AUTODIR = $(INST_LIB)/auto/$(FULLEXT) +INST_ARCHAUTODIR = $(INST_ARCHLIB)/auto/$(FULLEXT) + +INST_STATIC = +INST_DYNAMIC = +INST_BOOT = + +# Extra linker info +EXPORT_LIST = +PERL_ARCHIVE = +PERL_ARCHIVEDEP = +PERL_ARCHIVE_AFTER = + + +TO_INST_PM = mwx.pm + +PM_TO_BLIB = mwx.pm \ + $(INST_LIB)/mwx.pm + + +# --- MakeMaker platform_constants section: +MM_Unix_VERSION = 7.0401 +PERL_MALLOC_DEF = -DPERL_EXTMALLOC_DEF -Dmalloc=Perl_malloc -Dfree=Perl_mfree -Drealloc=Perl_realloc -Dcalloc=Perl_calloc + + +# --- MakeMaker tool_autosplit section: +# Usage: $(AUTOSPLITFILE) FileToSplit AutoDirToSplitInto +AUTOSPLITFILE = $(ABSPERLRUN) -e 'use AutoSplit; autosplit($$$$ARGV[0], $$$$ARGV[1], 0, 1, 1)' -- + + + +# --- MakeMaker tool_xsubpp section: + + +# --- MakeMaker tools_other section: +SHELL = /bin/sh +CHMOD = chmod +CP = cp +MV = mv +NOOP = $(TRUE) +NOECHO = @ +RM_F = rm -f +RM_RF = rm -rf +TEST_F = test -f +TOUCH = touch +UMASK_NULL = umask 0 +DEV_NULL = > /dev/null 2>&1 +MKPATH = $(ABSPERLRUN) -MExtUtils::Command -e 'mkpath' -- +EQUALIZE_TIMESTAMP = $(ABSPERLRUN) -MExtUtils::Command -e 'eqtime' -- +FALSE = false +TRUE = true +ECHO = echo +ECHO_N = echo -n +UNINST = 0 +VERBINST = 0 +MOD_INSTALL = $(ABSPERLRUN) -MExtUtils::Install -e 'install([ from_to => {@ARGV}, verbose => '\''$(VERBINST)'\'', uninstall_shadows => '\''$(UNINST)'\'', dir_mode => '\''$(PERM_DIR)'\'' ]);' -- +DOC_INSTALL = $(ABSPERLRUN) -MExtUtils::Command::MM -e 'perllocal_install' -- +UNINSTALL = $(ABSPERLRUN) -MExtUtils::Command::MM -e 'uninstall' -- +WARN_IF_OLD_PACKLIST = $(ABSPERLRUN) -MExtUtils::Command::MM -e 'warn_if_old_packlist' -- +MACROSTART = +MACROEND = +USEMAKEFILE = -f +FIXIN = $(ABSPERLRUN) -MExtUtils::MY -e 'MY->fixin(shift)' -- +CP_NONEMPTY = $(ABSPERLRUN) -MExtUtils::Command::MM -e 'cp_nonempty' -- + + +# --- MakeMaker makemakerdflt section: +makemakerdflt : all + $(NOECHO) $(NOOP) + + +# --- MakeMaker dist section: +TAR = tar +TARFLAGS = cvf +ZIP = zip +ZIPFLAGS = -r +COMPRESS = gzip --best +SUFFIX = .gz +SHAR = shar +PREOP = $(NOECHO) $(NOOP) +POSTOP = $(NOECHO) $(NOOP) +TO_UNIX = $(NOECHO) $(NOOP) +CI = ci -u +RCS_LABEL = rcs -Nv$(VERSION_SYM): -q +DIST_CP = best +DIST_DEFAULT = tardist +DISTNAME = mwx +DISTVNAME = mwx-1.21 + + +# --- MakeMaker macro section: + + +# --- MakeMaker depend section: + + +# --- MakeMaker cflags section: + + +# --- MakeMaker const_loadlibs section: + + +# --- MakeMaker const_cccmd section: + + +# --- MakeMaker post_constants section: + + +# --- MakeMaker pasthru section: + +PASTHRU = LIBPERL_A="$(LIBPERL_A)"\ + LINKTYPE="$(LINKTYPE)"\ + LD="$(LD)"\ + PREFIX="$(PREFIX)" + + +# --- MakeMaker special_targets section: +.SUFFIXES : .xs .c .C .cpp .i .s .cxx .cc $(OBJ_EXT) + +.PHONY: all config static dynamic test linkext manifest blibdirs clean realclean disttest distdir + + + +# --- MakeMaker c_o section: + + +# --- MakeMaker xs_c section: + + +# --- MakeMaker xs_o section: + + +# --- MakeMaker top_targets section: +all :: pure_all manifypods + $(NOECHO) $(NOOP) + + +pure_all :: config pm_to_blib subdirs linkext + $(NOECHO) $(NOOP) + +subdirs :: $(MYEXTLIB) + $(NOECHO) $(NOOP) + +config :: $(FIRST_MAKEFILE) blibdirs + $(NOECHO) $(NOOP) + +help : + perldoc ExtUtils::MakeMaker + + +# --- MakeMaker blibdirs section: +blibdirs : $(INST_LIBDIR)$(DFSEP).exists $(INST_ARCHLIB)$(DFSEP).exists $(INST_AUTODIR)$(DFSEP).exists $(INST_ARCHAUTODIR)$(DFSEP).exists $(INST_BIN)$(DFSEP).exists $(INST_SCRIPT)$(DFSEP).exists $(INST_MAN1DIR)$(DFSEP).exists $(INST_MAN3DIR)$(DFSEP).exists + $(NOECHO) $(NOOP) + +# Backwards compat with 6.18 through 6.25 +blibdirs.ts : blibdirs + $(NOECHO) $(NOOP) + +$(INST_LIBDIR)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_LIBDIR) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_LIBDIR) + $(NOECHO) $(TOUCH) $(INST_LIBDIR)$(DFSEP).exists + +$(INST_ARCHLIB)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_ARCHLIB) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_ARCHLIB) + $(NOECHO) $(TOUCH) $(INST_ARCHLIB)$(DFSEP).exists + +$(INST_AUTODIR)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_AUTODIR) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_AUTODIR) + $(NOECHO) $(TOUCH) $(INST_AUTODIR)$(DFSEP).exists + +$(INST_ARCHAUTODIR)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_ARCHAUTODIR) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_ARCHAUTODIR) + $(NOECHO) $(TOUCH) $(INST_ARCHAUTODIR)$(DFSEP).exists + +$(INST_BIN)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_BIN) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_BIN) + $(NOECHO) $(TOUCH) $(INST_BIN)$(DFSEP).exists + +$(INST_SCRIPT)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_SCRIPT) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_SCRIPT) + $(NOECHO) $(TOUCH) $(INST_SCRIPT)$(DFSEP).exists + +$(INST_MAN1DIR)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_MAN1DIR) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_MAN1DIR) + $(NOECHO) $(TOUCH) $(INST_MAN1DIR)$(DFSEP).exists + +$(INST_MAN3DIR)$(DFSEP).exists :: Makefile.PL + $(NOECHO) $(MKPATH) $(INST_MAN3DIR) + $(NOECHO) $(CHMOD) $(PERM_DIR) $(INST_MAN3DIR) + $(NOECHO) $(TOUCH) $(INST_MAN3DIR)$(DFSEP).exists + + + +# --- MakeMaker linkext section: + +linkext :: $(LINKTYPE) + $(NOECHO) $(NOOP) + + +# --- MakeMaker dlsyms section: + + +# --- MakeMaker dynamic_bs section: + +BOOTSTRAP = + + +# --- MakeMaker dynamic section: + +dynamic :: $(FIRST_MAKEFILE) $(BOOTSTRAP) $(INST_DYNAMIC) + $(NOECHO) $(NOOP) + + +# --- MakeMaker dynamic_lib section: + + +# --- MakeMaker static section: + +## $(INST_PM) has been moved to the all: target. +## It remains here for awhile to allow for old usage: "make static" +static :: $(FIRST_MAKEFILE) $(INST_STATIC) + $(NOECHO) $(NOOP) + + +# --- MakeMaker static_lib section: + + +# --- MakeMaker manifypods section: + +POD2MAN_EXE = $(PERLRUN) "-MExtUtils::Command::MM" -e pod2man "--" +POD2MAN = $(POD2MAN_EXE) + + +manifypods : pure_all \ + mwx.pm + $(NOECHO) $(POD2MAN) --section=$(MAN3EXT) --perm_rw=$(PERM_RW) -u \ + mwx.pm $(INST_MAN3DIR)/mwx.$(MAN3EXT) + + + + +# --- MakeMaker processPL section: + + +# --- MakeMaker installbin section: + + +# --- MakeMaker subdirs section: + +# none + +# --- MakeMaker clean_subdirs section: +clean_subdirs : + $(NOECHO) $(NOOP) + + +# --- MakeMaker clean section: + +# Delete temporary files but do not touch installed files. We don't delete +# the Makefile here so a later make realclean still has a makefile to use. + +clean :: clean_subdirs + - $(RM_F) \ + $(BASEEXT).bso $(BASEEXT).def \ + $(BASEEXT).exp $(BASEEXT).x \ + $(BOOTSTRAP) $(INST_ARCHAUTODIR)/extralibs.all \ + $(INST_ARCHAUTODIR)/extralibs.ld $(MAKE_APERL_FILE) \ + *$(LIB_EXT) *$(OBJ_EXT) \ + *perl.core MYMETA.json \ + MYMETA.yml blibdirs.ts \ + core core.*perl.*.? \ + core.[0-9] core.[0-9][0-9] \ + core.[0-9][0-9][0-9] core.[0-9][0-9][0-9][0-9] \ + core.[0-9][0-9][0-9][0-9][0-9] lib$(BASEEXT).def \ + mon.out perl \ + perl$(EXE_EXT) perl.exe \ + perlmain.c pm_to_blib \ + pm_to_blib.ts so_locations \ + tmon.out + - $(RM_RF) \ + blib + $(NOECHO) $(RM_F) $(MAKEFILE_OLD) + - $(MV) $(FIRST_MAKEFILE) $(MAKEFILE_OLD) $(DEV_NULL) + + +# --- MakeMaker realclean_subdirs section: +realclean_subdirs : + $(NOECHO) $(NOOP) + + +# --- MakeMaker realclean section: +# Delete temporary files (via clean) and also delete dist files +realclean purge :: clean realclean_subdirs + - $(RM_F) \ + $(MAKEFILE_OLD) $(FIRST_MAKEFILE) + - $(RM_RF) \ + $(DISTVNAME) + + +# --- MakeMaker metafile section: +metafile : create_distdir + $(NOECHO) $(ECHO) Generating META.yml + $(NOECHO) $(ECHO) '---' > META_new.yml + $(NOECHO) $(ECHO) 'abstract: '\''mikes perl tools'\''' >> META_new.yml + $(NOECHO) $(ECHO) 'author:' >> META_new.yml + $(NOECHO) $(ECHO) ' - '\''M.Wesemann '\''' >> META_new.yml + $(NOECHO) $(ECHO) 'build_requires:' >> META_new.yml + $(NOECHO) $(ECHO) ' ExtUtils::MakeMaker: '\''0'\''' >> META_new.yml + $(NOECHO) $(ECHO) 'configure_requires:' >> META_new.yml + $(NOECHO) $(ECHO) ' ExtUtils::MakeMaker: '\''0'\''' >> META_new.yml + $(NOECHO) $(ECHO) 'dynamic_config: 1' >> META_new.yml + $(NOECHO) $(ECHO) 'generated_by: '\''ExtUtils::MakeMaker version 7.0401, CPAN::Meta::Converter version 2.150001'\''' >> META_new.yml + $(NOECHO) $(ECHO) 'license: unknown' >> META_new.yml + $(NOECHO) $(ECHO) 'meta-spec:' >> META_new.yml + $(NOECHO) $(ECHO) ' url: http://module-build.sourceforge.net/META-spec-v1.4.html' >> META_new.yml + $(NOECHO) $(ECHO) ' version: '\''1.4'\''' >> META_new.yml + $(NOECHO) $(ECHO) 'name: mwx' >> META_new.yml + $(NOECHO) $(ECHO) 'no_index:' >> META_new.yml + $(NOECHO) $(ECHO) ' directory:' >> META_new.yml + $(NOECHO) $(ECHO) ' - t' >> META_new.yml + $(NOECHO) $(ECHO) ' - inc' >> META_new.yml + $(NOECHO) $(ECHO) 'requires:' >> META_new.yml + $(NOECHO) $(ECHO) ' MD5: '\''0'\''' >> META_new.yml + $(NOECHO) $(ECHO) ' Math::BigInt: '\''0'\''' >> META_new.yml + $(NOECHO) $(ECHO) ' Net::NIS: '\''0'\''' >> META_new.yml + $(NOECHO) $(ECHO) ' Net::SMTP: '\''0'\''' >> META_new.yml + $(NOECHO) $(ECHO) ' Term::ReadKey: '\''0'\''' >> META_new.yml + $(NOECHO) $(ECHO) ' Time::HiRes: '\''0'\''' >> META_new.yml + $(NOECHO) $(ECHO) 'version: '\''1.21'\''' >> META_new.yml + -$(NOECHO) $(MV) META_new.yml $(DISTVNAME)/META.yml + $(NOECHO) $(ECHO) Generating META.json + $(NOECHO) $(ECHO) '{' > META_new.json + $(NOECHO) $(ECHO) ' "abstract" : "mikes perl tools",' >> META_new.json + $(NOECHO) $(ECHO) ' "author" : [' >> META_new.json + $(NOECHO) $(ECHO) ' "M.Wesemann "' >> META_new.json + $(NOECHO) $(ECHO) ' ],' >> META_new.json + $(NOECHO) $(ECHO) ' "dynamic_config" : 1,' >> META_new.json + $(NOECHO) $(ECHO) ' "generated_by" : "ExtUtils::MakeMaker version 7.0401, CPAN::Meta::Converter version 2.150001",' >> META_new.json + $(NOECHO) $(ECHO) ' "license" : [' >> META_new.json + $(NOECHO) $(ECHO) ' "unknown"' >> META_new.json + $(NOECHO) $(ECHO) ' ],' >> META_new.json + $(NOECHO) $(ECHO) ' "meta-spec" : {' >> META_new.json + $(NOECHO) $(ECHO) ' "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",' >> META_new.json + $(NOECHO) $(ECHO) ' "version" : "2"' >> META_new.json + $(NOECHO) $(ECHO) ' },' >> META_new.json + $(NOECHO) $(ECHO) ' "name" : "mwx",' >> META_new.json + $(NOECHO) $(ECHO) ' "no_index" : {' >> META_new.json + $(NOECHO) $(ECHO) ' "directory" : [' >> META_new.json + $(NOECHO) $(ECHO) ' "t",' >> META_new.json + $(NOECHO) $(ECHO) ' "inc"' >> META_new.json + $(NOECHO) $(ECHO) ' ]' >> META_new.json + $(NOECHO) $(ECHO) ' },' >> META_new.json + $(NOECHO) $(ECHO) ' "prereqs" : {' >> META_new.json + $(NOECHO) $(ECHO) ' "build" : {' >> META_new.json + $(NOECHO) $(ECHO) ' "requires" : {' >> META_new.json + $(NOECHO) $(ECHO) ' "ExtUtils::MakeMaker" : "0"' >> META_new.json + $(NOECHO) $(ECHO) ' }' >> META_new.json + $(NOECHO) $(ECHO) ' },' >> META_new.json + $(NOECHO) $(ECHO) ' "configure" : {' >> META_new.json + $(NOECHO) $(ECHO) ' "requires" : {' >> META_new.json + $(NOECHO) $(ECHO) ' "ExtUtils::MakeMaker" : "0"' >> META_new.json + $(NOECHO) $(ECHO) ' }' >> META_new.json + $(NOECHO) $(ECHO) ' },' >> META_new.json + $(NOECHO) $(ECHO) ' "runtime" : {' >> META_new.json + $(NOECHO) $(ECHO) ' "requires" : {' >> META_new.json + $(NOECHO) $(ECHO) ' "MD5" : "0",' >> META_new.json + $(NOECHO) $(ECHO) ' "Math::BigInt" : "0",' >> META_new.json + $(NOECHO) $(ECHO) ' "Net::NIS" : "0",' >> META_new.json + $(NOECHO) $(ECHO) ' "Net::SMTP" : "0",' >> META_new.json + $(NOECHO) $(ECHO) ' "Term::ReadKey" : "0",' >> META_new.json + $(NOECHO) $(ECHO) ' "Time::HiRes" : "0"' >> META_new.json + $(NOECHO) $(ECHO) ' }' >> META_new.json + $(NOECHO) $(ECHO) ' }' >> META_new.json + $(NOECHO) $(ECHO) ' },' >> META_new.json + $(NOECHO) $(ECHO) ' "release_status" : "stable",' >> META_new.json + $(NOECHO) $(ECHO) ' "version" : "1.21"' >> META_new.json + $(NOECHO) $(ECHO) '}' >> META_new.json + -$(NOECHO) $(MV) META_new.json $(DISTVNAME)/META.json + + +# --- MakeMaker signature section: +signature : + cpansign -s + + +# --- MakeMaker dist_basics section: +distclean :: realclean distcheck + $(NOECHO) $(NOOP) + +distcheck : + $(PERLRUN) "-MExtUtils::Manifest=fullcheck" -e fullcheck + +skipcheck : + $(PERLRUN) "-MExtUtils::Manifest=skipcheck" -e skipcheck + +manifest : + $(PERLRUN) "-MExtUtils::Manifest=mkmanifest" -e mkmanifest + +veryclean : realclean + $(RM_F) *~ */*~ *.orig */*.orig *.bak */*.bak *.old */*.old + + + +# --- MakeMaker dist_core section: + +dist : $(DIST_DEFAULT) $(FIRST_MAKEFILE) + $(NOECHO) $(ABSPERLRUN) -l -e 'print '\''Warning: Makefile possibly out of date with $(VERSION_FROM)'\''' \ + -e ' if -e '\''$(VERSION_FROM)'\'' and -M '\''$(VERSION_FROM)'\'' < -M '\''$(FIRST_MAKEFILE)'\'';' -- + +tardist : $(DISTVNAME).tar$(SUFFIX) + $(NOECHO) $(NOOP) + +uutardist : $(DISTVNAME).tar$(SUFFIX) + uuencode $(DISTVNAME).tar$(SUFFIX) $(DISTVNAME).tar$(SUFFIX) > $(DISTVNAME).tar$(SUFFIX)_uu + $(NOECHO) $(ECHO) 'Created $(DISTVNAME).tar$(SUFFIX)_uu' + +$(DISTVNAME).tar$(SUFFIX) : distdir + $(PREOP) + $(TO_UNIX) + $(TAR) $(TARFLAGS) $(DISTVNAME).tar $(DISTVNAME) + $(RM_RF) $(DISTVNAME) + $(COMPRESS) $(DISTVNAME).tar + $(NOECHO) $(ECHO) 'Created $(DISTVNAME).tar$(SUFFIX)' + $(POSTOP) + +zipdist : $(DISTVNAME).zip + $(NOECHO) $(NOOP) + +$(DISTVNAME).zip : distdir + $(PREOP) + $(ZIP) $(ZIPFLAGS) $(DISTVNAME).zip $(DISTVNAME) + $(RM_RF) $(DISTVNAME) + $(NOECHO) $(ECHO) 'Created $(DISTVNAME).zip' + $(POSTOP) + +shdist : distdir + $(PREOP) + $(SHAR) $(DISTVNAME) > $(DISTVNAME).shar + $(RM_RF) $(DISTVNAME) + $(NOECHO) $(ECHO) 'Created $(DISTVNAME).shar' + $(POSTOP) + + +# --- MakeMaker distdir section: +create_distdir : + $(RM_RF) $(DISTVNAME) + $(PERLRUN) "-MExtUtils::Manifest=manicopy,maniread" \ + -e "manicopy(maniread(),'$(DISTVNAME)', '$(DIST_CP)');" + +distdir : create_distdir distmeta + $(NOECHO) $(NOOP) + + + +# --- MakeMaker dist_test section: +disttest : distdir + cd $(DISTVNAME) && $(ABSPERLRUN) Makefile.PL + cd $(DISTVNAME) && $(MAKE) $(PASTHRU) + cd $(DISTVNAME) && $(MAKE) test $(PASTHRU) + + + +# --- MakeMaker dist_ci section: + +ci : + $(PERLRUN) "-MExtUtils::Manifest=maniread" \ + -e "@all = keys %{ maniread() };" \ + -e "print(qq{Executing $(CI) @all\n}); system(qq{$(CI) @all});" \ + -e "print(qq{Executing $(RCS_LABEL) ...\n}); system(qq{$(RCS_LABEL) @all});" + + +# --- MakeMaker distmeta section: +distmeta : create_distdir metafile + $(NOECHO) cd $(DISTVNAME) && $(ABSPERLRUN) -MExtUtils::Manifest=maniadd -e 'exit unless -e q{META.yml};' \ + -e 'eval { maniadd({q{META.yml} => q{Module YAML meta-data (added by MakeMaker)}}) }' \ + -e ' or print "Could not add META.yml to MANIFEST: $$$${'\''@'\''}\n"' -- + $(NOECHO) cd $(DISTVNAME) && $(ABSPERLRUN) -MExtUtils::Manifest=maniadd -e 'exit unless -f q{META.json};' \ + -e 'eval { maniadd({q{META.json} => q{Module JSON meta-data (added by MakeMaker)}}) }' \ + -e ' or print "Could not add META.json to MANIFEST: $$$${'\''@'\''}\n"' -- + + + +# --- MakeMaker distsignature section: +distsignature : create_distdir + $(NOECHO) cd $(DISTVNAME) && $(ABSPERLRUN) -MExtUtils::Manifest=maniadd -e 'eval { maniadd({q{SIGNATURE} => q{Public-key signature (added by MakeMaker)}}) }' \ + -e ' or print "Could not add SIGNATURE to MANIFEST: $$$${'\''@'\''}\n"' -- + $(NOECHO) cd $(DISTVNAME) && $(TOUCH) SIGNATURE + cd $(DISTVNAME) && cpansign -s + + + +# --- MakeMaker install section: + +install :: pure_install doc_install + $(NOECHO) $(NOOP) + +install_perl :: pure_perl_install doc_perl_install + $(NOECHO) $(NOOP) + +install_site :: pure_site_install doc_site_install + $(NOECHO) $(NOOP) + +install_vendor :: pure_vendor_install doc_vendor_install + $(NOECHO) $(NOOP) + +pure_install :: pure_$(INSTALLDIRS)_install + $(NOECHO) $(NOOP) + +doc_install :: doc_$(INSTALLDIRS)_install + $(NOECHO) $(NOOP) + +pure__install : pure_site_install + $(NOECHO) $(ECHO) INSTALLDIRS not defined, defaulting to INSTALLDIRS=site + +doc__install : doc_site_install + $(NOECHO) $(ECHO) INSTALLDIRS not defined, defaulting to INSTALLDIRS=site + +pure_perl_install :: all + $(NOECHO) umask 022; $(MOD_INSTALL) \ + "$(INST_LIB)" "$(DESTINSTALLPRIVLIB)" \ + "$(INST_ARCHLIB)" "$(DESTINSTALLARCHLIB)" \ + "$(INST_BIN)" "$(DESTINSTALLBIN)" \ + "$(INST_SCRIPT)" "$(DESTINSTALLSCRIPT)" \ + "$(INST_MAN1DIR)" "$(DESTINSTALLMAN1DIR)" \ + "$(INST_MAN3DIR)" "$(DESTINSTALLMAN3DIR)" + $(NOECHO) $(WARN_IF_OLD_PACKLIST) \ + "$(SITEARCHEXP)/auto/$(FULLEXT)" + + +pure_site_install :: all + $(NOECHO) umask 02; $(MOD_INSTALL) \ + read "$(SITEARCHEXP)/auto/$(FULLEXT)/.packlist" \ + write "$(DESTINSTALLSITEARCH)/auto/$(FULLEXT)/.packlist" \ + "$(INST_LIB)" "$(DESTINSTALLSITELIB)" \ + "$(INST_ARCHLIB)" "$(DESTINSTALLSITEARCH)" \ + "$(INST_BIN)" "$(DESTINSTALLSITEBIN)" \ + "$(INST_SCRIPT)" "$(DESTINSTALLSITESCRIPT)" \ + "$(INST_MAN1DIR)" "$(DESTINSTALLSITEMAN1DIR)" \ + "$(INST_MAN3DIR)" "$(DESTINSTALLSITEMAN3DIR)" + $(NOECHO) $(WARN_IF_OLD_PACKLIST) \ + "$(PERL_ARCHLIB)/auto/$(FULLEXT)" + +pure_vendor_install :: all + $(NOECHO) umask 022; $(MOD_INSTALL) \ + "$(INST_LIB)" "$(DESTINSTALLVENDORLIB)" \ + "$(INST_ARCHLIB)" "$(DESTINSTALLVENDORARCH)" \ + "$(INST_BIN)" "$(DESTINSTALLVENDORBIN)" \ + "$(INST_SCRIPT)" "$(DESTINSTALLVENDORSCRIPT)" \ + "$(INST_MAN1DIR)" "$(DESTINSTALLVENDORMAN1DIR)" \ + "$(INST_MAN3DIR)" "$(DESTINSTALLVENDORMAN3DIR)" + + +doc_perl_install :: all + +doc_site_install :: all + $(NOECHO) $(ECHO) Appending installation info to "$(DESTINSTALLSITEARCH)/perllocal.pod" + -$(NOECHO) umask 02; $(MKPATH) "$(DESTINSTALLSITEARCH)" + -$(NOECHO) umask 02; $(DOC_INSTALL) \ + "Module" "$(NAME)" \ + "installed into" $(INSTALLSITELIB) \ + LINKTYPE "$(LINKTYPE)" \ + VERSION "$(VERSION)" \ + EXE_FILES "$(EXE_FILES)" \ + >> "$(DESTINSTALLSITEARCH)/perllocal.pod" + +doc_vendor_install :: all + + +uninstall :: uninstall_from_$(INSTALLDIRS)dirs + $(NOECHO) $(NOOP) + +uninstall_from_perldirs :: + +uninstall_from_sitedirs :: + $(NOECHO) $(UNINSTALL) "$(SITEARCHEXP)/auto/$(FULLEXT)/.packlist" + +uninstall_from_vendordirs :: + + +# --- MakeMaker force section: +# Phony target to force checking subdirectories. +FORCE : + $(NOECHO) $(NOOP) + + +# --- MakeMaker perldepend section: + + +# --- MakeMaker makefile section: +# We take a very conservative approach here, but it's worth it. +# We move Makefile to Makefile.old here to avoid gnu make looping. +$(FIRST_MAKEFILE) : Makefile.PL $(CONFIGDEP) + $(NOECHO) $(ECHO) "Makefile out-of-date with respect to $?" + $(NOECHO) $(ECHO) "Cleaning current config before rebuilding Makefile..." + -$(NOECHO) $(RM_F) $(MAKEFILE_OLD) + -$(NOECHO) $(MV) $(FIRST_MAKEFILE) $(MAKEFILE_OLD) + - $(MAKE) $(USEMAKEFILE) $(MAKEFILE_OLD) clean $(DEV_NULL) + $(PERLRUN) Makefile.PL + $(NOECHO) $(ECHO) "==> Your Makefile has been rebuilt. <==" + $(NOECHO) $(ECHO) "==> Please rerun the $(MAKE) command. <==" + $(FALSE) + + + +# --- MakeMaker staticmake section: + +# --- MakeMaker makeaperl section --- +MAP_TARGET = perl +FULLPERL = "/usr/bin/perl" + +$(MAP_TARGET) :: static $(MAKE_APERL_FILE) + $(MAKE) $(USEMAKEFILE) $(MAKE_APERL_FILE) $@ + +$(MAKE_APERL_FILE) : $(FIRST_MAKEFILE) pm_to_blib + $(NOECHO) $(ECHO) Writing \"$(MAKE_APERL_FILE)\" for this $(MAP_TARGET) + $(NOECHO) $(PERLRUNINST) \ + Makefile.PL DIR="" \ + MAKEFILE=$(MAKE_APERL_FILE) LINKTYPE=static \ + MAKEAPERL=1 NORECURS=1 CCCDLFLAGS= + + +# --- MakeMaker test section: + +TEST_VERBOSE=0 +TEST_TYPE=test_$(LINKTYPE) +TEST_FILE = test.pl +TEST_FILES = +TESTDB_SW = -d + +testdb :: testdb_$(LINKTYPE) + +test :: $(TEST_TYPE) subdirs-test + +subdirs-test :: + $(NOECHO) $(NOOP) + + +test_dynamic :: pure_all + PERL_DL_NONLAZY=1 $(FULLPERLRUN) "-I$(INST_LIB)" "-I$(INST_ARCHLIB)" $(TEST_FILE) + +testdb_dynamic :: pure_all + PERL_DL_NONLAZY=1 $(FULLPERLRUN) $(TESTDB_SW) "-I$(INST_LIB)" "-I$(INST_ARCHLIB)" $(TEST_FILE) + +test_ : test_dynamic + +test_static :: test_dynamic +testdb_static :: testdb_dynamic + + +# --- MakeMaker ppd section: +# Creates a PPD (Perl Package Description) for a binary distribution. +ppd : + $(NOECHO) $(ECHO) '' > $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' mikes perl tools' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' M.Wesemann <mwx@gmx.de>' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) ' ' >> $(DISTNAME).ppd + $(NOECHO) $(ECHO) '' >> $(DISTNAME).ppd + + +# --- MakeMaker pm_to_blib section: + +pm_to_blib : $(FIRST_MAKEFILE) $(TO_INST_PM) + $(NOECHO) $(ABSPERLRUN) -MExtUtils::Install -e 'pm_to_blib({@ARGV}, '\''$(INST_LIB)/auto'\'', q[$(PM_FILTER)], '\''$(PERM_DIR)'\'')' -- \ + mwx.pm $(INST_LIB)/mwx.pm + $(NOECHO) $(TOUCH) pm_to_blib + + +# --- MakeMaker selfdocument section: + + +# --- MakeMaker postamble section: + + +# End. diff --git a/perlmodules/mwx-1.21/README b/perlmodules/mwx-1.21/README new file mode 100644 index 0000000..624a1af --- /dev/null +++ b/perlmodules/mwx-1.21/README @@ -0,0 +1,35 @@ +mwx version 0.01 +================ + +The README is used to introduce the module and provide instructions on +how to install the module, any machine dependencies it may have (for +example C compilers and installed libraries) and any other information +that should be provided before the module is installed. + +A README file is required for CPAN modules since CPAN extracts the +README file from a module distribution so that people browsing the +archive can use it get an idea of the modules uses. It is usually a +good idea to provide version information here so that people can +decide whether fixes for the module are worth downloading. + +INSTALLATION + +To install this module type the following: + + perl Makefile.PL + make + make test + make install + +DEPENDENCIES + +This module requires these other modules and libraries: + + blah blah blah + +COPYRIGHT AND LICENCE + +Put the correct copyright and licence information here. + +Copyright (C) 2003 A. U. Thor blah blah blah + diff --git a/perlmodules/mwx-1.21/mwx.pm b/perlmodules/mwx-1.21/mwx.pm new file mode 100644 index 0000000..f60680f --- /dev/null +++ b/perlmodules/mwx-1.21/mwx.pm @@ -0,0 +1,281 @@ +######################################### mikes perl tools (mwx,11.09.03) ##### +package mwx; + +use 5.006; +use strict; +use warnings; + +require Exporter; +use AutoLoader qw(AUTOLOAD); + +our $VERSION = '1.21'; + +our @ISA = qw(Exporter); +our %EXPORT_TAGS = ( 'all' => [ qw( ) ] ); +our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); + +our @EXPORT = qw( + sendmail + md5 + gnfip + tosql + tsd + fsd + mkdatequery + mknumquery + mkquery + uniqid + shortstr +); + +################################################################### TOOLS ##### + +sub sendmail { ##### send mail ##### + my($from,$to,$subject,$message,$server)=@_; + use Net::SMTP; + my($smtp)=Net::SMTP->new("mail",Debug=>0); + $smtp->mail("<$from>"); + $smtp->recipient($to);$smtp->data(); + $smtp->datasend("To: $to\n"); + $smtp->datasend("From: $from\n"); + $smtp->datasend("Subject: $subject\n"); + $smtp->datasend("$message\n"); + $smtp->dataend(); + $smtp->quit(); +} + +sub md5() { ##### calculate md5 checksum ##### + my($file)=@_; + use Digest::MD5; + open(FILE,$file);binmode(FILE); + my($md5)=Digest::MD5->new->addfile(*FILE)->hexdigest; + close(FILE); + return($md5); +} + +sub gnfip { ##### find hostname for given IP (bug fixed version) ##### + my($ip)=@_; + use Net::DNS; + if ($ip!~/\d+\.\d+\.\d+\.\d+/) {;return $ip;} + my($res) = new Net::DNS::Resolver; + my($query)=$res->query($ip); + if ($query) { + for ($query->answer) { + if ($_->type eq 'PTR') { + my($ip)=$_->ptrdname; + return("$ip"); + } + } + } + else {;return("$ip");} +} + +sub tosql { ##### convert string for SQL ##### + my($str)=@_;my($a)="'";my($b)="`";if(!defined($str)) {;$str="";} + $str=~s/$b/$a$a/g;$str=~s/$a/$a$a/g;$str=~s/\s*$//g;$str=~s/^\s*//g; + return $str; +} + +sub tsd { ##### format date/time to MySQL date/time ##### + my($tmp)=@_;my($y); + $tmp=~s/^\s*//;$tmp=~s/\s*$//;$tmp=~s/\s+/ / ; + if ($tmp=~/^(\d+)\.(\d+)\.(\d+)\s+(\d+)\:(\d+)$/) { + $y=$3;if ($3>=0 && $3<100) {;$y=$3+2000;} + return sprintf("%04d-%02d-%02d %02d:%02d",$y,$2,$1,$4,$5); + } + if ($tmp=~/^(\d+)\.(\d+)\.(\d+)\s+(\d+)\:(\d+)\:(\d+)$/) { + $y=$3;if ($3>=0 && $3<100) {;$y=$3+2000;} + return sprintf("%04d-%02d-%02d %02d:%02d:%02d",$y,$2,$1,$4,$5,$6); + } + elsif ($tmp=~/^(\d+)\.(\d+)\.(\d+)$/) { + $y=$3;if ($3>=0 && $3<100) {;$y=$3+2000;} + return sprintf("%04d-%02d-%02d",$y,$2,$1); + } + elsif ($tmp=~/^(\d+)\:(\d+)$/) { + return sprintf("%02d:%02d",$1,$2); + } + else {;return("");} +} + +sub fsd { ########################### format MySQL date/time to date/time ##### + my($tmp,$mode)=@_;if (!defined($mode)) {;$mode="";} + $tmp=~s/^\s*//;$tmp=~s/\s*$//;$tmp=~s/\s+/ / ; + if ($tmp=~/(\d+)\-(\d+)\-(\d+)\s+(\d+)\:(\d+)\:(\d+)/) { + if ($tmp eq '0000-00-00 00:00:00') {;return("");} + if ($mode eq 'date') { + return sprintf("%d\.%d\.%04d",$3,$2,$1); + } + elsif ($mode eq 'time') { + return sprintf("%d\:%02d",$4,$5); + } + else { + return sprintf("%d\.%d\.%04d %d\:%02d",$3,$2,$1,$4,$5); + } + } + elsif ($tmp=~/(\d+)\-(\d+)\-(\d+)/) { + if ($tmp eq '0000-00-00' || $mode eq 'time') {;return("");} + return sprintf("%d\.%d\.%04d",$3,$2,$1); + } + if ($tmp=~/(\d+)\:(\d+)\:(\d+)/) { + if ($mode eq 'date') {;return("");} + return sprintf("%d\:%02d",$1,$2); + } + else {;return("");} +} + +sub mkdatequery { ###################### make query string for date range ##### + my($datestr,$field)=@_; + my(@list)=split(",",$datestr); + my($tmp)="";my($da,$db); + for (@list) { + if (/^\s*([^\s]+)\s*\-\s*([^\s]+)\s*$/) { + $da=$1;$db=$2; + $da=~s/(\d+)\.(\d+)\.(\d+)/$3\-$2\-$1/; + $db=~s/(\d+)\.(\d+)\.(\d+)/$3\-$2\-$1/; + $tmp.=" $field BETWEEN '$da' AND '$db' OR "; + } + elsif (/^\s*([\>\<])\s*(.*)/) { + $da=$1;$db=$2;$db=~s/(\d+)\.(\d+)\.(\d+)/$3\-$2\-$1/; + $tmp.=" $field $da '$db' OR "; + } + elsif (/^\s*\-(\d+)$/) { + $tmp.=" UNIX_TIMESTAMP($field)>UNIX_TIMESTAMP(now())-(86400*$1) OR "; + } + elsif (/^\s*([^\s]+)\s*$/) { + $da=$1;$da=~s/(\d+)\.(\d+)\.(\d+)/$3\-$2\-$1/; + $tmp.=" $field='$da' OR "; + } + } + $tmp=~s/\s*or\s*$//i;$tmp=~s/^\s//i;$tmp=~s/\s+/ /g; + if ($tmp=~/^\s*$/) {;return "";} + return "($tmp)"; +} + +sub mknumquery { ##################### make query string for number range ##### + my($numstr,$field)=@_; + my($tmp)=""; + my(@list)=split(",",$numstr); + for (@list) { + if (/^\s*(\d+)\s*\-\s*(\d+)\s*$/) { + $tmp.=" $field BETWEEN $1 AND $2 OR "; + } + elsif (/^\s*([\>\<])\s*(\d+)/) { + $tmp.=" $field $1 $2 OR "; + } + elsif (/^\s*(\d+)\s*$/) { + $tmp.=" $field=$1 OR "; + } + } + $tmp=~s/\s*or\s*$//i;$tmp=~s/^\s//i;$tmp=~s/\s+/ /g; + return "($tmp)"; +} + +sub mkquery { ############################### make query string for field ##### + my($query,$mode,@fields)=@_;if (!defined($query)) {;$query="";} + my(@list,$tmp,$field,@field); + use Text::ParseWords; + + $query=~s/\s*\(\s*/ \( /g;$query=~s/\s*\)\s*/ \) /g; + @list="ewords(' ',0,$query); + $query=""; + my($notflag)=0; + for (@list) { + if (!/^\s*and\s*$/i && !/^\s*or\s*$/i && + !/^\s*andnot\s*$/i && !/^\s*ornot\s*$/i && + !/^\s*\(\s*$/ && !/^\s*\)\s*$/ && !/^\s*$/) { + s/^\s*\'//;s/\'\s*$//; + + if ($query=~/\)\s*$/) {;$query.=" AND (";} + else {;$query.="(";} + for $field (@fields) { + $tmp=$_;if($mode==1) {;$tmp=" $_ ";} + if ($notflag) {;$query.=" NOT($field LIKE '%$tmp%') ";$notflag=0;} + else {;$query.=" $field LIKE '%$tmp%' ";} + $query.="OR "; + } + $query=~s/\s*or\s*$/\)/i; + } + else { + if ($_=~/^\s*andnot\s*$/i) {;$query.=" AND ";$notflag=1;} + elsif ($_=~/^\s*andnot\s*$/i) {;$query.=" OR ";$notflag=1;} + else {;$query.=" $_ ";} + } + + } + return $query; +} + + +sub base62() { ################################################### Base62 ##### + my($s)=@_; + my(@c)=('0'..'9','a'..'z','A'..'Z'); + my(@p,$u,$v,$i,$n); + my($m)=20; + $p[0]=1; + for $i (1..$m) { + $p[$i]=Math::BigInt->new($p[$i-1]); + $p[$i]=$p[$i]->bmul(62); + } + + $v=Math::BigInt->new($s); + for ($i=$m;$i>=0;$i--) { + $v=Math::BigInt->new($v); + ($n,$v)=$v->bdiv($p[$i]); + $u.=$c[$n]; + } + $u=~s/^0+//; + + return($u); +} + +sub uniqid { ############################################## get unique id ##### + use Math::BigInt; + use Sys::Hostname; + use Time::HiRes qw( gettimeofday usleep ); + my($s,$us)=gettimeofday(); + my($ia,$ib,$ic,$id)=unpack("C4", (gethostbyname(hostname()))[4]); + my($v)=sprintf("%06d%10d%06d%03d%03d%03d%03d",$us,$s,$$,$ia,$ib,$ic,$id); + return(&base62($v)); +} + +sub shortstr() { ########################### make short string with '...' ##### + my($str,$len)=@_; + if (length($str)>$len) { + my($tmp)=substr($str,0,$len-3) . "..."; + return $tmp; + } else {;return ($str);} +} + +##################################################################### END ##### +1; +__END__ + +=head1 NAME + +mwx - mikes perl tools + +=head1 SYNOPSIS + + use mwx; + + sendmail($from,$to,$subject,$message,$server); + + $md5 = md5($file); + + $name = gnfip($ip); + + $str = tosql($str); + $sqldate = tsd($date); + $date = fsd($date); + + $subsql = mkdatequery($datestr,$columnname); + $subsql = mknumquery($numstr,$columnname); + $subsql = mkquery($querystr,$mode,@columnnames); + + $id = uniqid(); + +=head1 AUTHOR + +Mike Wesemann, Emwx@gmx.deE + +=cut diff --git a/perlmodules/mwx-1.21/test.pl b/perlmodules/mwx-1.21/test.pl new file mode 100644 index 0000000..0d39eb8 --- /dev/null +++ b/perlmodules/mwx-1.21/test.pl @@ -0,0 +1,45 @@ +use Test; +BEGIN { plan tests => 25 }; +use mwx; +use strict; +#&sendmail('mike@fhi-berlin.mpg.de','mike@fhi-berlin.mpg.de','test','MSG','mail'); + +ok(&md5('Makefile.PL'),'a37560d14c32201defbecaa17f23628c'); + +ok(&fsd('2000-10-18 09:54:01'),'18.10.2000 9:54'); +ok(&fsd('0000-00-00 00:00:00'),''); +ok(&fsd('1999-09-19'),'19.9.1999'); +ok(&fsd('0000-00-00'),''); +ok(&fsd('08:53:02'),'8:53'); +ok(&fsd('00:00:00'),'0:00'); +ok(&fsd('2000-10-18 09:54:01','date'),'18.10.2000'); +ok(&fsd('2000-10-18 09:54:01','time'),'9:54'); +ok(&tsd('23.12.2002'),'2002-12-23'); +ok(&tsd('24.11.2001 14:12'),'2001-11-24 14:12'); +ok(&tsd('24.11.2001 14:12:23'),'2001-11-24 14:12:23'); +ok(&tsd('0:1'),'00:01'); + +ok(&gnfip('141.14.141.141'),'root.RZ-Berlin.MPG.DE'); + +ok(&mkdatequery("1.1.2002 , 2.2.2003","date"), + "(date='2002-1-1' OR date='2003-2-2')"); +ok(&mkdatequery("1.11.2002 - 7.11.2002","date"), + "(date BETWEEN '2002-11-1' AND '2002-11-7')"); +ok(&mkdatequery("> 1.11.2002","date"),"(date > '2002-11-1')"); + +ok(&mknumquery(" 2 - 5 ","number"),"(number BETWEEN 2 AND 5)"); +ok(&mknumquery("11,22 ,33","number"),"(number=11 OR number=22 OR number=33)"); + +ok(&mkquery("tee or cafe",0,'string'), + "( string LIKE '%tee%') or ( string LIKE '%cafe%')"); +ok(&mkquery("'tee or cafe'",0,'string'),"( string LIKE '%tee or cafe%')"); + +ok(&tosql(' test '),'test'); +ok(&tosql("a'b"),"a''b"); + +ok(&shortstr('0123456789',10),'0123456789'); +ok(&shortstr('0123456789',8),'01234...'); + +print &uniqid() . " " . &uniqid() . " " . &uniqid() . "\n"; + + diff --git a/restic.config.enc b/restic.config.enc new file mode 100644 index 0000000..aabe94f --- /dev/null +++ b/restic.config.enc @@ -0,0 +1,6 @@ +U2FsdGVkX1/vb68X/pAIz5XudakFRxh3wBUxNJqWFNOcltEXfbxxegN6PXyHIii+ +yGlQS5zfmPNuZNds7WIE+5E8ah2qemwTLBIidMjxI7Iq0GfJkX5SS6QOAt3Bhxa6 +bsqVjf7keGXKWIc7kIu3AnwQlz+qgkW99WFLJ5MYrd60ePYQ9uAf7foIVdNs/fmz +a47jbHeDDteilzQBSJgiYhhY7Tdc/vOzuAzOXImEX3OG4FyGj90+SMgLnkrIJUOv +4wFpNz4NPXq9rIiav6z/gOblLze+4O7CkkTHqjMSJTeQUSKyXZ0bvZ1mUfzpV7ld +GYUf4zGNcVYSkVWPgS0iJnlcY+psYvk2rPDDxsBCuwk= diff --git a/restic.setup b/restic.setup new file mode 100755 index 0000000..dbbfa2e --- /dev/null +++ b/restic.setup @@ -0,0 +1,117 @@ +#!/usr/bin/perl +####################################################################################### restic setup (mwx'2023) +use Config; +die if (!-f "./files/rt"); + + +#myuname: linux localhost 4.19.0 #1 smp debian 4.19.0 armv7l gnulinux +#archname: arm-linux-gnueabihf-thread-multi-64int + +if ($Config{archname}=~/^darwin/) { # --------------------------------------------------------------- mac setup + + $XRT = $ENV{"HOME"}.'/bin/rt'; + $XRTLOG = $ENV{"HOME"}.'/.rt.log'; + $XRESTIC = $ENV{"HOME"}.'/bin/restic'; + $XLOG = $ENV{"HOME"}.'/.restic.log'; + $XPWFILE = $ENV{"HOME"}.'/.restic.pw'; + + $XSRC = $ENV{"HOME"}.'/Sync /Volumes/Pictures'; + $XEXCLUDE = '-e .Spotlight-V100 -e .Trashes -e .fseventsd -e .bzvol -e .DS_Store ' . + '-e .TemporaryItems -e .DocumentRevisions-V100'; + $config=$ENV{"HOME"}.'/.rt.conf'; + + system('./upd https://github.com/restic/restic -i '.$ENV{"HOME"}.'/bin'); + + system("cp ./files/rt $XRT"); + system("chmod 755 $XRT"); + +} elsif ($Config{archname}=~/-linux-/) { # ------------------------------------------------ ubuntu/debian setup + + $XRT = '/db/bin/rt'; + $XRTLOG = '/var/log/rt.log'; + $XRESTIC = '/db/bin/restic'; + $XLOG = '/var/log/restic.log'; + $XLOG = '/var/log/restic.log'; + $XPWFILE = '/db/etc/restic.pw'; + + $XSRC = '/etc /db /var /root /home /usr/local /opt'; + $XEXCLUDE = '-e /var/lib/lxcfs -e /var/log/journal'; + + $config='/db/etc/rt.conf'; + + system('./upd https://github.com/restic/restic -i /db/bin'); + + system("cp ./files/rt $XRT"); + system("chmod 755 $XRT"); + system("mkdir -p /db/etc /db/tmp"); + +} else {die "architecture not found";} # ---------------------------------------------------------------------- + +chomp($host=`hostname`);$host=~s/^([^\.]+).*/$1/; +$host=&readline("Hostname: ",$host); + + +if (!-f $config) { # write config file +open(OUT,"> $config"); +print OUT <<"ENDOFCONF"; + +\$NAME = '$host'; +\$ID = '0'; +\$TAG = 'ppb'; + +\$PASSWORD = ""; +\$TARGET = ""; +\$ENV{'AWS_ACCESS_KEY_ID'} = ''; +\$ENV{'AWS_SECRET_ACCESS_KEY'} = ''; + +\$SRC = '$XSRC'; + +\$EXCLUDE = '$XEXCLUDE'; + +\$RESTIC = '$XRESTIC'; +\$LOG = '$XLOG'; +\$PWFILE = '$XPWFILE'; + +\$HTTP_LOG = 'log.fhi.berlin'; + +ENDOFCONF +} + + +system("vi $config"); + +system("$XRT init"); + +&setupcron(); + + +####################################################################################################### SUPPORT + + +sub setupcron() { + open(CRON,"crontab -l |"); + while() { + chomp(); + push(@CRON,$_) if (!/rt\s+selfupdate/ && !/rt delaybackup/); + } + + push(@CRON,"0 2 * * * $XRT delaybackup >> $XRTLOG 2>&1"); + + open(OUT,"> /tmp/cron.$$"); + for (@CRON) { + print OUT "$_\n"; + } + close(OUT); + system("/usr/bin/crontab /tmp/cron.$$"); + system("rm -f /tmp/cron.$$"); +} + +sub readline() { + my($prompt,$input)=@_; use Term::ReadLine; + BEGIN{ $ENV{PERL_RL} = 'Perl o=0' } + if (!$term) {;$term = new Term::ReadLine 'term';} + my($txt)=$term->readline($prompt,$input); + return $txt; +} + +########################################################################################################### END diff --git a/setup.debian1x b/setup.debian1x new file mode 100755 index 0000000..ee89c45 --- /dev/null +++ b/setup.debian1x @@ -0,0 +1,114 @@ +#!/usr/bin/perl +use Getopt::Std;getopts('z'); + +system("userdel ppb; rm -rf /home/ppb") if (-d "/home/ppb"); +system("userdel mike; rm -rf /home/mike") if (-d "/home/mike"); + +&ai('dnsutils','net-tools','zsh','joe','rsync','curl','fuse','libwww-perl', + 'libterm-readline-perl-perl','libterm-readpassword-perl','libdbd-mysql-perl','ntp', + 'libjson-perl','jq','unzip','7zip'); + +if ($opt_z) { + if (-x "/usr/bin/zsh") { + system("chsh root -s /usr/bin/zsh"); + } +} + + +system("locale-gen C.UTF-8"); + +system("mkdir /db"); +system("mkdir /db/bin"); +system("mkdir /db/backup"); +system("mkdir /db/backup/mysql"); +system("mkdir /db/tmp"); +system("mkdir /db/log"); +system("mkdir /db/lib"); +system("mkdir /db/data"); +system("mkdir /db/etc"); +system("mkdir /db/src"); +system("mkdir /db/upload"); +system("chmod 777 /db/tmp"); +system("chmod 777 /db/log"); +system("chmod 777 /db/upload"); + +system("mkdir -p ~/.joe/colors/"); +system("cp ./files/default.jcf ~/.joe/colors/default.jcf"); +system("cp ./files/joerc4 /root/.joerc"); +system("cp ./files/csh.cshrc /etc"); +system("cp ./files/rc.local.debian /etc/rc.local"); +system("chmod 755 /etc/rc.local"); +system("cp ./files/myuser /db/bin"); +system("cp ./files/mybackup /db/bin"); +system("cp ./files/dx /db/bin"); +system("cp ./files/gx /db/bin"); +system("cp ./files/gy /db/bin"); +system("cp ./files/telemetry /db/bin"); +system("cp ./files/rt /db/bin"); +system("cp ./files/mgsh /db/bin"); +system("cp ./files/locale /etc/default/locale"); + +system("cp ./files/zshrc /etc/zsh/zshrc"); + +system("rm /etc/motd; touch /etc/motd"); + +system("mkdir /root/.ssh") if (!-d "/root/.ssh"); + + +&readak("/root/.ssh/authorized_keys"); +&readak("./files/authorized_keys"); + +open(OUT,"> /root/.ssh/authorized_keys"); +for (sort(keys(%K))) {print OUT "$_\n" if (!/^\s*$/);} +close(OUT); + +sub readak() { + my($file)=@_; + if (-f $file) {open(IN,$file);while() {chomp();$K{$_}=$_;}close(IN);} +} + + +system("chmod 700 /root/.ssh"); +system("chmod 600 /root/.ssh/authorized_keys"); + +if (!$opt_x) { + system("/usr/bin/apt-get update"); + system("/usr/bin/apt-get upgrade"); + + if (is_debian_13_or_later()) { + system("cp ./files/timesyncd.conf /etc/systemd/"); + + } else { + system("service ntp stop"); + system("/usr/sbin/ntpd -gq"); + system("service ntp start"); + } +} + +sub ai { + my @pkgs=@_; + for (@pkgs) { + system("/usr/bin/apt-get -y install $_"); + } +} + + +sub is_debian_13_or_later { + return 0 unless -r '/etc/os-release'; + + my %os_release; + open(my $fh, '<', '/etc/os-release') or return 0; + while (my $line = <$fh>) { + chomp $line; + if ($line =~ /^([A-Z_]+)=(.*)$/) { + my ($key, $val) = ($1, $2); + $val =~ s/^"|"$//g; + $os_release{$key} = $val; + } + } + close($fh); + + return 0 unless ($os_release{ID} // '') eq 'debian'; + return 0 unless ($os_release{VERSION_ID} // '') =~ /^(\d+)/; + return $1 >= 13 ? 1 : 0; +} diff --git a/setup.phpini b/setup.phpini new file mode 100755 index 0000000..201ed6b --- /dev/null +++ b/setup.phpini @@ -0,0 +1,60 @@ +#!/usr/bin/perl + +for $v ('7.2','7.3','7.4','8.1') { + if (-f "/etc/php/$v/apache2/php.ini") { + $FILE = "/etc/php/$v/apache2/php.ini"; + $OFILE = "/etc/php/$v/apache2/php.ini.org"; + } +} + +die "$FILE not found" if (!-f $FILE); +die "$FILE skipped" if (-f $OFILE); + +$epre = "\"
\""; +$epost = "\"
\""; + +$P{'html_errors'} = 'On'; +$P{'display_errors'} = 'On'; +$P{'error_prepend_string'} = $epre; + +$P{'error_append_string'} = $epost; +$P{'error_reporting'} = 'E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED'; +$P{'short_open_tag'} = 'On'; +$P{'upload_tmp_dir'} = '/db/upload'; +$P{'upload_max_filesize'} = '10000M'; +$P{'post_max_size'} = '10000M'; +$P{'max_execution_time'} = '300'; +$P{'max_input_time'} = '600'; +$P{'memory_limit'} = '512M'; + +if (!-f $OFILE) { + system("cp $FILE $OFILE"); +} + +open(IN,$OFILE); +open(OUT,"> $FILE"); +while() { + + if (!/^;/ && !/^\s*$/) { + print OUT "\n" if (/^\[/); + $match=0; + for $key (keys(%P)) { + $match++ if (/^$key/); + } + if ($match>0) { + print OUT ";$_"; + } else { + print OUT "$_"; + } + } + + if (/^\[PHP\]/) { + for $key (sort(keys(%P))) { + print OUT "$key = $P{$key}\n"; + } + print OUT "\n"; + } + +} +close(IN); +close(OUT); diff --git a/setup.rpi b/setup.rpi new file mode 100755 index 0000000..48453a6 --- /dev/null +++ b/setup.rpi @@ -0,0 +1,34 @@ +#!/usr/bin/perl + +&ai('tcsh','joe','libterm-readpassword-perl','libterm-readline-perl-perl','resolvconf'); + +system("/usr/bin/chsh -s /usr/bin/tcsh root"); + +system("mkdir /db"); +system("mkdir /db/bin"); +system("mkdir /db/tmp"); +system("chmod 777 /db/tmp"); + +system("cp ./files/joerc4 /etc/joe/joerc"); +system("cp ./files/csh.cshrc /etc"); +system("cp ./files/dx /db/bin"); +system("cp ./files/gx /db/bin"); +system("cp ./files/gy /db/bin"); +system("cp ./restic/restic_0.9.5_linux_arm /db/bin/restic"); + +system("rm /etc/motd"); + +system("mkdir /root/.ssh"); +system("cp ./files/authorized_keys /root/.ssh"); +system("chmod 700 /root/.ssh"); +system("chmod 600 /root/.ssh/authorized_keys"); + +system("/usr/bin/apt-get update"); +system("/usr/bin/apt-get upgrade"); + +sub ai { + my @pkgs=@_; + for (@pkgs) { + system("/usr/bin/apt-get -y install $_"); + } +} diff --git a/setup.ssh b/setup.ssh new file mode 100755 index 0000000..1054d5b --- /dev/null +++ b/setup.ssh @@ -0,0 +1,24 @@ +#!/usr/bin/perl + +$SSHCONF='/etc/ssh/sshd_config'; + +$out=""; +open(IN,$SSHCONF); +while() { + + if (/^\s*\#*\s*PermitRootLogin/) { + $out.="PermitRootLogin yes\n" ; + } elsif (/(^\s*AcceptEnv.*$)/) { + $out.="#$1"; + } else { + $out.=$_; + } +} +close(IN); + +open(OUT,"> $SSHCONF"); +print OUT $out; +close(OUT); + +system("service ssh restart"); + diff --git a/setup.ubuntu2x b/setup.ubuntu2x new file mode 100755 index 0000000..da59c1b --- /dev/null +++ b/setup.ubuntu2x @@ -0,0 +1,58 @@ +#!/usr/bin/perl + +system("userdel ppb; rm -rf /home/ppb") if (-d "/home/ppb"); +system("userdel mike; rm -rf /home/mike") if (-d "/home/mike"); + +&ai('net-tools','zsh','joe','fuse','libwww-perl','bzip2','jq', + 'libterm-readline-perl-perl','libterm-readpassword-perl','libdbd-mysql-perl','ntp'); + +system("chsh root -s /usr/bin/zsh"); + +system("mkdir /db"); +system("mkdir /db/bin"); +system("mkdir /db/backup"); +system("mkdir /db/backup/mysql"); +system("mkdir /db/tmp"); +system("mkdir /db/log"); +system("mkdir /db/lib"); +system("mkdir /db/data"); +system("mkdir /db/etc"); +system("mkdir /db/src"); +system("mkdir /db/upload"); +system("chmod 777 /db/tmp"); +system("chmod 777 /db/log"); +system("chmod 777 /db/upload"); + +system("cp ./files/joerc4 /root/.joerc"); +system("cp ./files/csh.cshrc /etc"); +system("cp ./files/rc.local.ubuntu /etc/rc.local"); +system("chmod 755 /etc/rc.local"); +system("cp ./files/myuser /db/bin"); +system("cp ./files/mybackup /db/bin"); +system("cp ./files/dx /db/bin"); +system("cp ./files/gx /db/bin"); +system("cp ./files/gy /db/bin"); +system("cp ./files/telemetry /db/bin"); +system("cp ./files/rt /db/bin"); +system("cp ./files/mgsh /db/bin"); + +system("cp ./files/zshrc /etc/zsh/zshrc"); + +system("mkdir /root/.ssh") if (!-d "/root/.ssh"); +system("cp ./files/authorized_keys /root/.ssh"); +system("chmod 700 /root/.ssh"); +system("chmod 600 /root/.ssh/authorized_keys"); + +system("/usr/bin/apt update"); +system("/usr/bin/apt upgrade"); + +system("service ntp stop"); +system("/usr/sbin/ntpd -gq"); +system("service ntp start"); + +sub ai { + my @pkgs=@_; + for (@pkgs) { + system("/usr/bin/apt -qq -y install $_"); + } +} diff --git a/telemetry.setup b/telemetry.setup new file mode 100755 index 0000000..8682c87 --- /dev/null +++ b/telemetry.setup @@ -0,0 +1,28 @@ +#!/usr/bin/perl +#################################################################################### telemetry setup (mwx'2020) + +&setupcron(); + + +####################################################################################################### SUPPORT + +sub setupcron() { + open(CRON,"crontab -l |"); + while() { + chomp(); + push(@CRON,$_) if (!/\/db\/bin\/telemetry/); + } + + push(@CRON,"*/5 * * * * /db/bin/telemetry > /dev/null 2>&1"); + + open(OUT,"> /tmp/cron.$$"); + for (@CRON) { + print OUT "$_\n"; + } + close(OUT); + system("/usr/bin/crontab /tmp/cron.$$"); + system("rm -f /tmp/cron.$$"); +} + + +########################################################################################################### END diff --git a/upd b/upd new file mode 100755 index 0000000..adfc513 --- /dev/null +++ b/upd @@ -0,0 +1,1227 @@ +#!/usr/bin/env perl +# +# upd - download the matching binary from the latest Gitea/GitHub release. +# +# ./upd https://git.fhi.mpg.de/mike/mgsh +# ./upd https://github.com/sxyazi/yazi --install ~/bin --name yazi,ya +# ./upd --all # everything listed in the config file +# ./upd --all --check # exit 10 if any update is available +# +# Needs only Perl core modules plus curl (or wget) for HTTPS. + +use strict; +use warnings; +use Getopt::Long qw(GetOptions); +use File::Basename qw(basename dirname); +use File::Spec; +use File::Temp qw(tempdir); +use POSIX qw(uname strftime); +use Digest::SHA qw(sha256_hex); +use JSON::PP (); + +my $UA = 'upd/2.0 (perl)'; + +# Exit codes: 0 ok, 1 usage, 2 error, 10 update available (--check only). +use constant { EX_OK => 0, EX_USAGE => 1, EX_ERROR => 2, EX_OUTDATED => 10 }; + +# Options that belong to a single repository. Anything else is global and +# applies to every entry of an --all run. +my @SPEC_KEYS = qw(install name tag asset pattern os arch forge token version-flag pre); + +my %opt = ('version-flag' => '--version', timeout => 30); + +# Leftovers from an interrupted install must not linger next to the binary. +my @TMPFILES; +END { unlink @TMPFILES if @TMPFILES } + +# Run only when executed directly, so the subs below can be require'd and +# exercised on their own. +main() unless caller; + +sub main { + GetOptions( + \%opt, + 'repo=s', 'tag=s', 'install|dest|i=s', 'name=s', 'asset=s', 'pattern=s', + 'os=s', 'arch=s', 'token=s', 'forge=s', 'version-flag=s', 'timeout=i', + 'config=s', 'all', 'check', 'pre', 'force', 'list', 'dry-run', + 'quiet', 'verbose', 'help', + ) or usage(EX_USAGE); + usage(EX_OK) if $opt{help}; + $| = 1; + + for my $sig (qw(INT TERM HUP)) { + $SIG{$sig} = sub { unlink @TMPFILES; @TMPFILES = (); exit 130 }; + } + + my @specs; + eval { @specs = build_specs(); 1 } or do { + warn trim($@) . "\n"; + exit EX_ERROR; + }; + + my @results; + for my $spec (@specs) { + my $res = eval { update_one($spec) }; + $res = { status => 'error', label => label_of($spec), msg => trim($@ || 'failed') } + unless defined $res; + push @results, $res; + warn "$res->{label}: $res->{msg}\n" if $res->{status} eq 'error'; + } + + summary(\@results) if @specs > 1 && !$opt{list}; + exit worst_code(\@results); +} + +sub build_specs { + if ($opt{all}) { + my $path = $opt{config} // config_path(); + my @s = read_config($path); + die "No entries in $path.\n" unless @s; + return @s; + } + my $url = $opt{repo} // shift(@ARGV) // $ENV{UPD_REPO}; + unless (defined $url && length $url) { + warn "Error: missing repository URL.\n\n"; + usage(EX_USAGE); + } + my %s = (repo => $url); + $s{$_} = $opt{$_} for grep { defined $opt{$_} } @SPEC_KEYS; + return (\%s); +} + +# ============================================================================== +# One repository, end to end +# ============================================================================== + +sub update_one { + my $spec = shift; + + my ($base, $owner, $repo) = parse_repo($spec->{repo}); + my $forge = detect_forge($base, $spec->{forge}); + my %ctx = ( + base => $base, + owner => $owner, + repo => $repo, + forge => $forge, + token => resolve_token($forge, $spec->{token}), + api => api_base($base, $forge) . '/repos/' . uri_esc($owner) . '/' . uri_esc($repo), + ); + + my @names = parse_names($spec->{name} // $repo, $repo); + my ($os, $arch) = detect_platform($spec); + + info("Repo: $base/$owner/$repo [$forge]"); + info("Platform: $os/$arch"); + + my $rel = fetch_release(\%ctx, $spec); + my $tag = $rel->{tag_name}; + + if ($opt{list}) { + list_releases($rel->{_list} || [$rel]); + return { status => 'listed', label => $names[0]{out}, msg => '' }; + } + + info("Release: $tag ($rel->{published_at})" . ($rel->{prerelease} ? ' [prerelease]' : '')); + + my @assets = @{ $rel->{assets} || [] }; + die "Release $tag has no assets.\n" unless @assets; + + my $asset = pick_asset(\@assets, $names[0]{src}, $os, $arch, $spec); + unless ($asset) { + my $have = join "\n ", map { $_->{name} } @assets; + die "No asset for $os/$arch in release $tag.\nAvailable:\n $have\n" + . "Select one explicitly with --asset or --pattern .\n"; + } + info("Asset: $asset->{name} (" . human_size($asset->{size}) . ")"); + + my @targets = resolve_targets($spec, \@names, $os); + info("Target: " . join(', ', map { $_->{dest} } @targets)); + + my @stale = grep { !target_current($_, $tag, $asset, $spec) } @targets; + unless (@stale || $opt{force}) { + info("Already up to date ($tag) - nothing to do."); + return { status => 'current', label => $names[0]{out}, msg => $tag }; + } + @stale = @targets if $opt{force}; + + if ($opt{check}) { + my $have = join ', ', map { installed_tag($_) } @stale; + info("Update available: $tag (installed: $have)"); + return { status => 'outdated', label => $names[0]{out}, msg => "$tag (have: $have)" }; + } + + my ($dl_url) = asset_url(\%ctx, $asset); + if ($opt{'dry-run'}) { + print "[dry-run] would download: $dl_url\n"; + print "[dry-run] would install to: $_->{dest}\n" for @stale; + return { status => 'dry', label => $names[0]{out}, msg => $tag }; + } + + # --- download ------------------------------------------------------------- + + my $tmpdir = tempdir(CLEANUP => 1); + my $dl = File::Spec->catfile($tmpdir, $asset->{name}); + + info("Downloading $dl_url ..."); + my (undef, $dl_hdr) = asset_url(\%ctx, $asset); + my $res = http_request(url => $dl_url, headers => { %{ auth_headers(\%ctx) }, %$dl_hdr }, + file => $dl, progress => 1); + die "Download failed (HTTP $res->{status}): $dl_url\n" unless $res->{status} == 200; + + my $got = -s $dl // 0; + die "Incomplete download: $got of $asset->{size} bytes.\n" + if $asset->{size} && $got < $asset->{size}; + + verify_download(\%ctx, $dl, $asset, \@assets, $tmpdir); + + # --- extract and install -------------------------------------------------- + + my $root = extract_if_archive($dl, $tmpdir); + for my $t (@stale) { + my $src = defined $root ? find_in_tree($root, $t->{name}) + : $dl; + die "Binary '$t->{name}' not found inside $asset->{name}.\n" unless defined $src; + warn "Warning: $t->{name} does not look like an executable.\n" + unless looks_executable($src); + + install_atomic($src, $t->{dest}); + strip_quarantine($t->{dest}) if $os eq 'darwin'; + write_state($t, \%ctx, $spec, $tag, $asset); + info("Installed: $t->{dest} ($tag)"); + my $v = installed_version($t->{dest}, $spec); + info("Version: $v") if length $v; + } + + my %dirs = map { dirname($_->{dest}) => 1 } @stale; + warn "Note: $_ is not in \$PATH.\n" for grep { !in_path($_) } sort keys %dirs; + + return { status => 'updated', label => $names[0]{out}, msg => $tag }; +} + +# ============================================================================== +# Release selection +# ============================================================================== + +sub fetch_release { + my ($ctx, $spec) = @_; + + # A specific tag: both forges have a direct endpoint. Fall back to the list + # so "26.5.6" also finds a tag named "v26.5.6". + if (defined $spec->{tag}) { + my $t = $spec->{tag}; + my $hit = api_get($ctx, "$ctx->{api}/releases/tags/" . uri_esc($t), soft => 1); + return $hit if $hit && $hit->{tag_name}; + my $list = api_get($ctx, releases_url($ctx)); + ($hit) = grep { $_->{tag_name} eq $t } @$list; + ($hit) = grep { norm_ver($_->{tag_name}) eq norm_ver($t) } @$list unless $hit; + die "Release '$t' not found (--list shows all).\n" unless $hit; + return $hit; + } + + # The plain case is one request: the forge already knows its latest + # non-draft, non-prerelease release. + unless ($spec->{pre} || $opt{list}) { + my $latest = api_get($ctx, "$ctx->{api}/releases/latest", soft => 1); + return $latest if $latest && $latest->{tag_name}; + verbose('no /releases/latest, falling back to the release list'); + } + + my $list = api_get($ctx, releases_url($ctx)); + die "No releases found in $ctx->{owner}/$ctx->{repo}.\n" + unless ref $list eq 'ARRAY' && @$list; + + if ($opt{list}) { + return { tag_name => '', published_at => '', assets => [], _list => $list }; + } + my ($rel) = grep { !$_->{draft} && ($spec->{pre} || !$_->{prerelease}) } @$list; + die "No suitable release found (try --pre).\n" unless $rel; + return $rel; +} + +sub releases_url { + my $ctx = shift; + return $ctx->{forge} eq 'github' ? "$ctx->{api}/releases?per_page=50" + : "$ctx->{api}/releases?limit=50&draft=false"; +} + +# ============================================================================== +# Asset selection +# ============================================================================== + +# Aliases commonly used in release asset names, including Rust target triples. +sub os_alias { + my $o = shift; + return $o eq 'darwin' ? [qw(darwin macos osx mac apple)] + : $o eq 'windows' ? [qw(windows win)] + : [$o]; +} + +# --- Asset name matching ------------------------------------------------------ + +# Can this machine turn the asset into a binary? Bare names and tarballs +# always qualify; single-file compression needs its decompressor present. +sub unpackable { + my $n = lc shift; + return 1 if $n =~ /\.(tar\.gz|tgz|tar\.bz2|tbz|tar\.xz|txz|tar\.zst|tzst|tar)$/; + return which('unzip') ? 1 : 0 if $n =~ /\.zip$/; + return (which('7zz') || which('7z') || which('7za')) ? 1 : 0 if $n =~ /\.7z$/; + return decompressor($1) ? 1 : 0 if $n =~ /\.(gz|bz2|xz|zst|lz4|lzma)$/; + return 0 if $n =~ /\.(rar|dmg|pkg|msi|deb|rpm)$/; + return 1; # bare binary or an unversioned name +} + +# Compound tokens that name OS and architecture in one word. Rewritten before +# matching so the normal token rules apply. "win32" is Node-speak for Windows +# in general (pnpm-win32-x64.zip), so it contributes no architecture. +sub normalize_tokens { + my $n = shift; + $n =~ s/(?{asset}) { + my ($hit) = grep { $_->{name} eq $spec->{asset} } @$assets; + die "Asset '$spec->{asset}' is not part of the release.\n" unless $hit; + return $hit; + } + if (defined $spec->{pattern}) { + my $re = qr/$spec->{pattern}/; + my ($hit) = grep { $_->{name} =~ $re } @$assets; + return $hit; + } + + my $os_re = join '|', @{ os_alias($want_os) }; + my @arches = @{ arch_alias($want_arch) }; + # Universal macOS builds serve both architectures. + push @arches, qw(universal universal2) if $want_os eq 'darwin'; + my $arch_re = join '|', @arches; + + my (@cand, @rejected); + for my $as (@$assets) { + my $n = lc $as->{name}; + my $m = normalize_tokens($n); + + # Checksums, signatures and OS packages are not plain binaries. + if ($n =~ /\.(sha\d*|sha256sum|md5|asc|sig|pem|sbom|json|txt|deb|rpm|apk|dmg|pkg|msi|snap|flatpak|appimage)$/) { + push @rejected, "$n (not a binary)"; + next; + } + # Cross-compile targets whose triples contain a host OS token: + # aarch64-linux-android is Android, not Linux. + if ($m =~ /(?:^|[^a-z0-9])(?:android\w*|ios|wasi|wasm\w*|emscripten)(?:[^a-z0-9]|$)/) { + push @rejected, "$n (foreign target)"; + next; + } + unless ($m =~ /(?:^|[^a-z0-9])(?:$os_re)(?:[^a-z0-9]|$)/) { + push @rejected, "$n (os)"; + next; + } + unless ($m =~ /(?:^|[^a-z0-9])(?:$arch_re)(?:[^a-z0-9]|$)/) { + push @rejected, "$n (arch)"; + next; + } + # Keep 32-bit "arm" off "arm64" and "386" off "x86_64". + if ( ($want_arch eq 'arm' && $m =~ /arm64|aarch64/) + || ($want_arch eq '386' && $m =~ /x86[_-]?64|amd64/) + || ($want_arch eq 'amd64' && $m =~ /arm64|aarch64/)) { + push @rejected, "$n (wider arch)"; + next; + } + + my $score = 0; + $score += 10 if index($n, lc $bin) == 0; # named after the binary + $score += 3 if $n =~ /\.(tar\.gz|tgz|zip|tar\.xz|tar\.bz2|tar\.zst|tzst)$/ || $n !~ /\./; + $score -= 5 if $n =~ /debug|symbols|static-pie|profile/; + # Only avoid formats this machine has no tool for - restic, for one, + # ships nothing but .bz2, and bunzip2 handles that fine. + $score -= 8 if !unpackable($n); + + # Toolchain preference is a tie-break, not a penalty: a project that + # ships musl only (or mingw only) must not be downranked for it. + my $pref = 0; + if ($want_os eq 'linux' && $n =~ /musl|gnu/) { + my $libc = prefers_musl() ? 'musl' : 'gnu'; + $pref = $n =~ /\Q$libc\E/ ? 0 : 1; + } + elsif ($want_os eq 'windows' && $n =~ /msvc|gnu/) { + $pref = $n =~ /msvc/ ? 0 : 1; # msvc is the normal Windows build + } + push @cand, [ $score, $pref, length($n), $as ]; + } + + # Best score, then preferred toolchain, then the shortest name (which + # avoids special variants like -baseline or -static). + @cand = sort { $b->[0] <=> $a->[0] || $a->[1] <=> $b->[1] || $a->[2] <=> $b->[2] } @cand; + if ($opt{verbose}) { + verbose(sprintf 'candidate score=%-3d pref=%d %s', @{$_}[0, 1], $_->[3]{name}) for @cand; + verbose("rejected: $_") for @rejected; + } + return @cand ? $cand[0][3] : undef; +} + +# ============================================================================== +# Install targets and state +# ============================================================================== + +sub resolve_targets { + my ($spec, $names, $os) = @_; + my $want = $spec->{install} // $ENV{UPD_INSTALL}; + $want =~ s{^~(?=/|$)}{$ENV{HOME} // '~'}e if defined $want; + my $ext = $os eq 'windows' ? '.exe' : ''; + + # --install is a directory unless it clearly points at a single binary: + # an existing file, or a last segment that is one of the binary names. + # Everything else is a directory (and gets created) - otherwise a config + # line like "install=~/bin" would create a *file* called bin. + my ($dir, $single); + if (defined $want && length $want) { + my $leaf = basename($want); + my $is_bin = grep { $leaf eq $_->{out} || $leaf eq $_->{out} . $ext } @$names; + if (!-d $want && ($is_bin || -f $want)) { + die "--install points at the file '$want' but " . scalar(@$names) + . " binaries were requested; give a directory instead.\n" if @$names > 1; + $single = $want; + $dir = dirname($want); + } + else { + ($dir = $want) =~ s{(?<=.)/+$}{}; + } + } + else { + $dir = default_dir($names->[0]{out}); + } + make_dir($dir); + + my @t; + for my $n (@$names) { + my $dest = $single // File::Spec->catfile($dir, $n->{out} . $ext); + # Replacing a symlink would silently break the link, so follow it. + if (-l $dest) { + require Cwd; + if (my $real = Cwd::abs_path($dest)) { + info("Note: $dest is a symlink, installing to $real"); + $dest = $real; + } + } + push @t, { name => $n->{src}, out => $n->{out}, dest => $dest }; + } + return @t; +} + +# Without --install: replace the binary already on PATH, else ~/.local/bin. +sub default_dir { + my $bin = shift; + for my $dir (split /:/, ($ENV{PATH} // '')) { + next unless length $dir; + my $p = File::Spec->catfile($dir, $bin); + return $dir if -x $p && -w $dir; + } + return File::Spec->catdir($ENV{HOME} // '.', '.local', 'bin'); +} + +sub make_dir { + my $dir = shift; + return if -d $dir || $opt{'dry-run'} || $opt{list} || $opt{check}; + require File::Path; + File::Path::make_path($dir) + or die "Cannot create target directory $dir: $!\n"; +} + +sub state_dir { + my $base = $ENV{XDG_STATE_HOME} + || File::Spec->catdir($ENV{HOME} // '.', '.local', 'state'); + return File::Spec->catdir($base, 'upd'); +} + +sub cache_dir { + my $base = $ENV{XDG_CACHE_HOME} || File::Spec->catdir($ENV{HOME} // '.', '.cache'); + return File::Spec->catdir($base, 'upd'); +} + +# One state file per installed path; readable name plus a hash for uniqueness. +sub state_file { + my $dest = shift; + (my $key = $dest) =~ s{[^A-Za-z0-9._-]+}{_}g; + $key =~ s{^_+|_+$}{}g; + $key = substr($key, -70) if length $key > 70; + return File::Spec->catfile(state_dir(), $key . '.' . substr(sha256_hex($dest), 0, 8) . '.json'); +} + +# Identity of a release asset: the digest if the forge publishes one (GitHub +# does), otherwise its upload time - this is what makes rolling tags such as +# "nightly" detectable. +sub asset_stamp { + my $a = shift; + return $a->{digest} if $a->{digest}; + return "t:$a->{updated_at}" if $a->{updated_at}; + return "t:$a->{created_at}" if $a->{created_at}; + return 's:' . ($a->{size} // 0); +} + +sub target_current { + my ($t, $tag, $asset, $spec) = @_; + return 0 unless -f $t->{dest}; + + my $st = read_json(state_file($t->{dest})); + if ($st && defined $st->{tag}) { + return 0 unless $st->{tag} eq $tag; + return 0 unless ($st->{asset} // '') eq $asset->{name}; + return 0 unless ($st->{stamp} // '') eq asset_stamp($asset); + # A locally replaced binary counts as out of date. + my $same = ($st->{binary_sha256} // '') eq file_sha256($t->{dest}); + verbose("$t->{dest}: state matches but binary differs") unless $same; + return $same; + } + + # No state yet (first run after an install by other means): ask the binary. + my $v = installed_version($t->{dest}, $spec); + verbose("$t->{dest}: no state file, binary reports '" . ($v // '') . "'"); + return length($v) && $v eq norm_ver($tag) ? 1 : 0; +} + +sub installed_tag { + my $t = shift; + my $st = read_json(state_file($t->{dest})); + return $st->{tag} if $st && defined $st->{tag}; + return '-' unless -f $t->{dest}; + my $v = installed_version($t->{dest}, {}); + return length($v) ? $v : 'unknown'; +} + +sub write_state { + my ($t, $ctx, $spec, $tag, $asset) = @_; + make_dir_always(state_dir()); + write_json(state_file($t->{dest}), { + dest => $t->{dest}, + binary => $t->{out}, + repo => "$ctx->{base}/$ctx->{owner}/$ctx->{repo}", + forge => $ctx->{forge}, + tag => $tag, + asset => $asset->{name}, + asset_size => $asset->{size}, + stamp => asset_stamp($asset), + binary_sha256 => file_sha256($t->{dest}), + installed_at => strftime('%Y-%m-%dT%H:%M:%SZ', gmtime), + }); +} + +sub make_dir_always { + my $dir = shift; + return if -d $dir; + require File::Path; + File::Path::make_path($dir) or die "Cannot create $dir: $!\n"; +} + +# ============================================================================== +# Config file (--all) +# ============================================================================== + +sub config_path { + my $base = $ENV{XDG_CONFIG_HOME} || File::Spec->catdir($ENV{HOME} // '.', '.config'); + return File::Spec->catfile($base, 'upd', 'tools'); +} + +# One entry per line: [key=value ...] [pre] +sub read_config { + my $path = shift; + open my $fh, '<', $path + or die "Cannot read config $path: $!\n" + . "Format: one line per tool, e.g.\n" + . " https://github.com/sxyazi/yazi install=~/bin name=yazi,ya\n"; + + my (@out, $ln); + while (my $line = <$fh>) { + $ln++; + $line =~ s/^\s+|\s+$//g; + next if !length $line || $line =~ /^#/; + + my @tok = map { unquote($_) } $line =~ /("(?:\\.|[^"])*"|\S+)/g; + my %s = (repo => shift @tok); + for my $t (@tok) { + my ($k, $v) = split /=/, $t, 2; + $k = lc $k; + die "$path:$ln: unknown key '$k' (allowed: " . join(', ', @SPEC_KEYS) . ")\n" + unless grep { $_ eq $k } @SPEC_KEYS; + $s{$k} = defined $v ? $v : 1; + } + # Global flags still win, so --force/--pre on the command line apply. + $s{$_} = $opt{$_} for grep { defined $opt{$_} } @SPEC_KEYS; + push @out, \%s; + } + close $fh; + return @out; +} + +sub unquote { + my $s = shift; + if ($s =~ s/^"(.*)"$/$1/s) { $s =~ s/\\(.)/$1/g } + return $s; +} + +# "yazi,ya" -> two binaries; "yazi:yazi-nightly" -> install yazi under a +# different file name. src is what to look for, out is what to write. +sub parse_names { + my ($list, $fallback) = @_; + my @n; + for my $part (split /\s*,\s*/, $list) { + next unless length $part; + my ($src, $out) = split /:/, $part, 2; + push @n, { src => $src, out => (defined $out && length $out) ? $out : $src }; + } + return @n ? @n : ({ src => $fallback, out => $fallback }); +} + +sub label_of { + my $spec = shift; + return (parse_names($spec->{name}, '?'))[0]{out} if defined $spec->{name}; + my $r = $spec->{repo} // '?'; + $r =~ s{/+$}{}; + return basename($r); +} + +sub summary { + my $res = shift; + # --quiet is meant for cron: report only what needs attention. + my @rows = $opt{quiet} + ? grep { $_->{status} =~ /^(error|outdated|updated)$/ } @$res + : @$res; + return unless @rows; + my $w = 0; + for (@rows) { $w = length $_->{label} if length $_->{label} > $w } + print "\nSummary:\n"; + printf " %-9s %-*s %s\n", $_->{status}, $w, $_->{label}, $_->{msg} // '' for @rows; +} + +sub worst_code { + my $res = shift; + return EX_ERROR if grep { $_->{status} eq 'error' } @$res; + return EX_OUTDATED if grep { $_->{status} eq 'outdated' } @$res; + return EX_OK; +} + +# ============================================================================== +# HTTP +# ============================================================================== + +# Use HTTP::Tiny only if it can really do TLS - otherwise curl/wget. +my $HTTP; +sub http_tiny { + return $HTTP if defined $HTTP; + $HTTP = eval { + require HTTP::Tiny; + HTTP::Tiny->can_ssl or die "no ssl\n"; + HTTP::Tiny->new(agent => $UA, timeout => $opt{timeout}, verify_SSL => 1); + } || 0; + return $HTTP; +} + +sub transport { + return 'tiny' if http_tiny(); + return 'curl' if which('curl'); + return 'wget' if which('wget'); + die "Found neither a TLS-capable HTTP::Tiny nor curl/wget.\n"; +} + +# wget cannot report response headers usefully, so no conditional requests. +sub conditional_ok { return transport() ne 'wget' } + +sub auth_headers { + my $ctx = shift; + return {} unless $ctx->{token}; + # GitHub wants "Bearer", Gitea wants "token". + return { Authorization => $ctx->{forge} eq 'github' ? "Bearer $ctx->{token}" + : "token $ctx->{token}" }; +} + +# Returns { status, headers => {lc => value}, content } - content only when no +# 'file' was given. Never dies on HTTP status; callers decide. +sub http_request { + my %a = @_; + my $hdr = $a{headers} || {}; + + if (my $h = http_tiny()) { + my %o = (headers => $hdr); + my $out; + if ($a{file}) { + open $out, '>', $a{file} or die "Cannot write $a{file}: $!\n"; + binmode $out; + $o{data_callback} = sub { print {$out} $_[0] }; + } + my $r = $h->get($a{url}, \%o); + close $out if $out; + return { status => $r->{status}, headers => $r->{headers} || {}, + content => $a{file} ? '' : $r->{content} }; + } + + my $tmp = tempdir(CLEANUP => 1); + my $body = $a{file} // File::Spec->catfile($tmp, 'body'); + my $hf = File::Spec->catfile($tmp, 'head'); + + if (transport() eq 'wget') { + my @cmd = ('wget', '-q', '-O', $body, '--timeout', $opt{timeout}, "--user-agent=$UA", + map { "--header=$_: $hdr->{$_}" } sort keys %$hdr); + my $rc = system(@cmd, $a{url}); + return { status => $rc == 0 ? 200 : 599, headers => {}, + content => $a{file} ? '' : slurp($body) }; + } + + my @prog = ($a{progress} && !$opt{quiet} && -t STDOUT) ? ('--progress-bar') : ('-sS'); + my @cmd = ('curl', @prog, '-L', '--retry', '2', '--connect-timeout', $opt{timeout}, + '-A', $UA, '-D', $hf, '-o', $body, '-w', '%{http_code}', + map { ('-H', "$_: $hdr->{$_}") } sort keys %$hdr); + + my $code = ''; + if (open my $ph, '-|', @cmd, $a{url}) { + local $/; + $code = <$ph> // ''; + close $ph; + } + my $rc = $? >> 8; + $code =~ s/\D//g; + die "curl failed (exit $rc): $a{url}\n" if $rc != 0 && !length $code; + die "curl failed (exit $rc, HTTP $code): $a{url}\n" if $rc != 0 && $code =~ /^[45]/; + + return { status => $code || 599, headers => parse_headers($hf), + content => $a{file} ? '' : slurp($body) }; +} + +# Keep only the last response block; -L may have walked through redirects. +sub parse_headers { + my $path = shift; + open my $fh, '<', $path or return {}; + my %h; + while (my $l = <$fh>) { + $l =~ s/\r?\n$//; + %h = () , next if $l =~ m{^HTTP/}; + $h{lc $1} = $2 if $l =~ /^([^:]+):\s*(.*)$/; + } + close $fh; + return \%h; +} + +sub slurp { + my $path = shift; + open my $fh, '<', $path or return ''; + binmode $fh; + local $/; + return <$fh> // ''; +} + +# GET a JSON API endpoint, revalidating a cached copy via ETag where supported. +# soft => 1 returns undef instead of dying on 404. +sub api_get { + my ($ctx, $url, %o) = @_; + my $accept = $ctx->{forge} eq 'github' ? 'application/vnd.github+json' : 'application/json'; + my %hdr = (%{ auth_headers($ctx) }, Accept => $accept); + $hdr{'X-GitHub-Api-Version'} = '2022-11-28' if $ctx->{forge} eq 'github'; + + my $cf = cache_file($url); + my $cached = read_json($cf); + $hdr{'If-None-Match'} = $cached->{etag} + if $cached && $cached->{etag} && conditional_ok(); + + my $r = http_request(url => $url, headers => \%hdr); + + if ($r->{status} == 304 && $cached) { + verbose("304 not modified, using cached $url"); + return decode_json_or_die($cached->{body}, $url, $ctx); + } + return undef if $o{soft} && $r->{status} == 404; + if ($r->{status} == 403 || $r->{status} == 429) { + my $left = $r->{headers}{'x-ratelimit-remaining'}; + die "$ctx->{forge} rate limit reached" + . (defined $left ? " (remaining: $left)" : '') + . ". Set a token via --token or \$GITHUB_TOKEN.\n" + if defined $left && $left eq '0'; + } + die "HTTP $r->{status}: $url\n" unless $r->{status} == 200; + + my $data = decode_json_or_die($r->{content}, $url, $ctx); + if (my $etag = $r->{headers}{etag}) { + make_dir_always(cache_dir()); + write_json($cf, { url => $url, etag => $etag, body => $r->{content} }); + } + return $data; +} + +sub decode_json_or_die { + my ($body, $url, $ctx) = @_; + my $data = eval { JSON::PP->new->utf8->decode($body) }; + die "Response from $url is not JSON (is this really a $ctx->{forge} instance?).\n" + unless defined $data; + die ucfirst($ctx->{forge}) . " error: $data->{message}\n" + if ref $data eq 'HASH' && $data->{message}; + return $data; +} + +sub cache_file { + my $url = shift; + return File::Spec->catfile(cache_dir(), substr(sha256_hex($url), 0, 16) . '.json'); +} + +# Private GitHub assets are only reachable through the API URL; curl/HTTP::Tiny +# drop the Authorization header on the cross-host redirect to storage. +sub asset_url { + my ($ctx, $a) = @_; + return ("$ctx->{api}/releases/assets/$a->{id}", { Accept => 'application/octet-stream' }) + if $ctx->{forge} eq 'github' && $ctx->{token} && $a->{id}; + return ($a->{browser_download_url}, {}); +} + +# ============================================================================== +# Verification, extraction, installation +# ============================================================================== + +sub verify_download { + my ($ctx, $file, $asset, $assets, $tmpdir) = @_; + + my ($want, $src); + if (($asset->{digest} // '') =~ /^sha256:([0-9a-f]{64})$/i) { + ($want, $src) = (lc $1, 'asset digest'); + } + else { + my ($sum) = grep { $_->{name} eq "$asset->{name}.sha256" } @$assets; + ($sum) = grep { $_->{name} =~ /^(sha256sums?(\.txt)?|checksums?\.txt)$/i } @$assets + unless $sum; + return unless $sum; + + my $sf = File::Spec->catfile($tmpdir, 'sums'); + my ($u, $h) = asset_url($ctx, $sum); + my $r = eval { + http_request(url => $u, headers => { %{ auth_headers($ctx) }, %$h }, file => $sf); + }; + unless ($r && $r->{status} == 200) { + warn "Checksum file could not be downloaded, skipping verification.\n"; + return; + } + open my $fh, '<', $sf or return; + while (my $l = <$fh>) { + # " ", or just "" in a single-file .sha256 + next unless my ($hash, $fn) = $l =~ /^([0-9a-fA-F]{64})(?:\s+\*?(\S+))?/; + next if defined $fn && basename($fn) ne $asset->{name}; + ($want, $src) = (lc $hash, $sum->{name}); + last; + } + close $fh; + return unless $want; + } + + my $got = file_sha256($file); + die "SHA256 mismatch ($src)!\n expected: $want\n got: $got\n" if $got ne $want; + info("SHA256: ok ($src)"); +} + +sub file_sha256 { + my $path = shift; + open my $fh, '<', $path or die "Cannot read $path: $!\n"; + binmode $fh; + my $d = Digest::SHA->new(256)->addfile($fh)->hexdigest; + close $fh; + return $d; +} + +# Single-file compression: the asset is the binary, just squeezed. Each entry +# lists the tools that can expand it, in order of preference; the first one +# found wins. All of them write to stdout with the flags given. +sub DECOMP { + return { + gz => { tools => [qw(gzip gunzip)], args => ['-dc'] }, + bz2 => { tools => [qw(bzip2 bunzip2)], args => ['-dc'] }, + xz => { tools => [qw(xz unxz)], args => ['-dc'] }, + lzma => { tools => [qw(xz unxz lzma)], args => ['-dc'] }, + zst => { tools => [qw(zstd unzstd)], args => ['-dcq'] }, + lz4 => { tools => [qw(lz4 unlz4)], args => ['-dcq'] }, + }; +} + +sub decompressor { + my $ext = shift; + my $e = DECOMP()->{$ext} or return; + for my $t (@{ $e->{tools} }) { + my $p = which($t) or next; + return { prog => $p, args => $e->{args} }; + } + return; +} + +sub decompress_to { + my ($dec, $src, $dst) = @_; + open my $out, '>', $dst or die "Cannot write $dst: $!\n"; + binmode $out; + my $pid = open my $in, '-|'; + die "fork failed: $!\n" unless defined $pid; + unless ($pid) { + open STDIN, '<', File::Spec->devnull; + exec $dec->{prog}, @{ $dec->{args} }, $src; + exit 127; + } + binmode $in; + my $buf; + print {$out} $buf while read $in, $buf, 1 << 20; + close $in; + my $rc = $?; + close $out or die "Error writing $dst: $!\n"; + die "Failed to decompress $src (" . basename($dec->{prog}) . " exit " + . ($rc >> 8) . ").\n" if $rc != 0; +} + +# Returns the root of the extracted tree, or undef if the asset is a bare +# binary (then the download itself is the binary). +sub extract_if_archive { + my ($file, $tmpdir) = @_; + my $lc = lc basename($file); + + my $out = File::Spec->catdir($tmpdir, 'x'); + + if ($lc =~ /\.(tar\.gz|tgz|tar\.bz2|tbz|tar\.xz|txz|tar\.zst|tzst|tar)$/) { + mkdir $out or die "mkdir $out: $!\n"; + system('tar', '-xf', $file, '-C', $out) == 0 or die "Failed to extract $file.\n"; + } + elsif ($lc =~ /\.zip$/) { + which('unzip') or die "unzip not found, but needed for $lc.\n"; + mkdir $out or die "mkdir $out: $!\n"; + system('unzip', '-q', $file, '-d', $out) == 0 or die "Failed to extract $file.\n"; + } + elsif ($lc =~ /\.7z$/) { + my $z = which('7zz') || which('7z') || which('7za') + or die "7z not found, but needed for $lc.\n"; + mkdir $out or die "mkdir $out: $!\n"; + system($z, 'x', '-y', "-o$out", $file) == 0 or die "Failed to extract $file.\n"; + } + elsif (my ($ext) = $lc =~ /\.(gz|bz2|xz|zst|lz4|lzma)$/) { + # A single compressed file, e.g. restic_0.19.1_darwin_arm64.bz2 - + # the binary itself, just squeezed. + my $dec = decompressor($ext) + or die "Cannot unpack .$ext - install " . join('/', @{ DECOMP()->{$ext}{tools} }) + . " or pick another asset with --asset/--pattern.\n"; + mkdir $out or die "mkdir $out: $!\n"; + (my $stem = basename($file)) =~ s/\.\Q$ext\E$//i; + my $plain = File::Spec->catfile($out, $stem); + decompress_to($dec, $file, $plain); + } + else { + return undef; # bare binary + } + return $out; +} + +# Look for a file called $name; fall back to the single executable in the tree. +sub find_in_tree { + my ($root, $name) = @_; + + my @found; + my @stack = ($root); + while (my $dir = pop @stack) { + opendir my $dh, $dir or next; + for my $e (readdir $dh) { + next if $e eq '.' || $e eq '..'; + my $p = File::Spec->catfile($dir, $e); + if (-d $p) { push @stack, $p; next } + push @found, $p; + } + closedir $dh; + } + + my ($exact) = grep { basename($_) eq $name || basename($_) eq "$name.exe" } @found; + return $exact if $exact; + + my @exec = grep { looks_executable($_) } @found; + return $exec[0] if @exec == 1; + verbose("archive contains " . scalar(@found) . " files, " + . scalar(@exec) . " of them executable"); + return undef; +} + +# Magic bytes beat guessing by file size: ELF, Mach-O (incl. fat), PE, script. +sub looks_executable { + my $path = shift; + open my $fh, '<', $path or return 0; + binmode $fh; + read $fh, my $m, 4; + close $fh; + return 0 unless defined $m && length $m >= 2; + return 1 if $m =~ /^\x7fELF/; + return 1 if $m =~ /^(?:\xcf\xfa\xed\xfe|\xce\xfa\xed\xfe|\xca\xfe\xba\xbe|\xbe\xba\xfe\xca)/; + return 1 if $m =~ /^MZ/; + return 1 if $m =~ /^#!/; + return 0; +} + +sub install_atomic { + my ($src, $dest) = @_; + my $dir = dirname($dest); + -d $dir or die "Target directory $dir does not exist.\n"; + -w $dir or die "No write permission in $dir (use sudo, or pick another --install path).\n"; + + my $tmp = "$dest.new.$$"; + push @TMPFILES, $tmp; + open my $in, '<', $src or die "Cannot read $src: $!\n"; + open my $out, '>', $tmp or die "Cannot write $tmp: $!\n"; + binmode $in; + binmode $out; + my $buf; + print {$out} $buf while read $in, $buf, 1 << 20; + close $in; + close $out or die "Error writing $tmp: $!\n"; + chmod 0755, $tmp; + + # rename is atomic and works even while $dest is currently running. + rename $tmp, $dest or do { + my $err = $!; + unlink $tmp; + die "Cannot replace $dest: $err\n"; + }; + @TMPFILES = grep { $_ ne $tmp } @TMPFILES; +} + +sub strip_quarantine { + my $dest = shift; + return unless -x '/usr/bin/xattr'; + system(qq{/usr/bin/xattr -d com.apple.quarantine \Q$dest\E >/dev/null 2>&1}); +} + +# ============================================================================== +# Helpers +# ============================================================================== + +sub info { print "$_[0]\n" unless $opt{quiet} } +sub verbose { print " $_[0]\n" if $opt{verbose} } +sub trim { my $s = shift // ''; $s =~ s/^\s+|\s+$//g; return $s } + +sub parse_repo { + my $url = shift; + $url =~ s{/+$}{}; + $url =~ s{\.git$}{}; + $url = "https://$url" unless $url =~ m{^https?://}; + my ($scheme_host, $path) = $url =~ m{^(https?://[^/]+)(/.*)?$} + or die "Cannot parse repository URL: $url\n"; + $path //= ''; + $path =~ s{^/}{}; + # Anything before / is a base path (Gitea under a sub-path). + my @seg = split m{/}, $path; + die "Repository URL needs /: $url\n" if @seg < 2; + my ($o, $r) = splice @seg, -2; + return ($scheme_host . (@seg ? '/' . join('/', @seg) : ''), $o, $r); +} + +sub uri_esc { + my $s = shift; + $s =~ s{([^A-Za-z0-9._~-])}{sprintf '%%%02X', ord $1}ge; + return $s; +} + +sub host_of { my ($h) = ($_[0] // '') =~ m{^https?://([^/:]+)}i; return lc($h // '') } + +# Gitea and GitHub expose the same release JSON, only under different API +# roots and with different auth headers. +sub detect_forge { + my ($b, $override) = @_; + if (defined $override) { + my $f = lc $override; + die "Unknown forge '$override' (use github or gitea).\n" + unless $f eq 'github' || $f eq 'gitea'; + return $f; + } + return host_of($b) =~ /(^|\.)github\.com$/ ? 'github' : 'gitea'; +} + +sub api_base { + my ($b, $f) = @_; + return "$b/api/v1" unless $f eq 'github'; + return 'https://api.github.com' if host_of($b) =~ /(^|\.)github\.com$/; + return "$b/api/v3"; # GitHub Enterprise +} + +sub resolve_token { + my ($forge, $explicit) = @_; + return $explicit if defined $explicit; + my @env = $forge eq 'github' ? qw(UPD_TOKEN GITHUB_TOKEN GH_TOKEN) + : qw(UPD_TOKEN GITEA_TOKEN); + for my $k (@env) { + return $ENV{$k} if defined $ENV{$k} && length $ENV{$k}; + } + return ''; +} + +sub detect_platform { + my $spec = shift || {}; + my ($sysname, undef, undef, undef, $machine) = uname(); + my $o = lc $sysname; + $o = 'windows' if $o =~ /mingw|msys|cygwin|windows/; + $o = 'darwin' if $o =~ /darwin/; + $o = 'linux' if $o =~ /linux/; + + my $m = lc $machine; + my $a = $m =~ /^(x86_64|amd64)$/ ? 'amd64' + : $m =~ /^(aarch64|arm64)$/ ? 'arm64' + : $m =~ /^(i[3-6]86|x86)$/ ? '386' + : $m =~ /^armv?[5-8]/ ? 'arm' + : $m =~ /^(ppc64le|riscv64|s390x)$/ ? $m + : $m; + + return ($spec->{os} // $o, $spec->{arch} // $a); +} + +sub in_path { + my $dir = shift; + return grep { $_ eq $dir } split /:/, ($ENV{PATH} // ''); +} + +sub norm_ver { my $v = shift // ''; $v =~ s/^v//i; $v =~ s/^\s+|\s+$//g; return $v } + +# Run a program and capture stdout+stderr, with a timeout and no stdin. +sub capture { + my ($timeout, $prog, @args) = @_; + my $pid = open my $fh, '-|'; + return '' unless defined $pid; + unless ($pid) { + open STDIN, '<', File::Spec->devnull; + open STDERR, '>&', \*STDOUT; + exec $prog, @args; + exit 127; + } + my $out = ''; + local $SIG{ALRM} = sub { kill 'TERM', $pid }; + alarm $timeout; + { local $/; $out = <$fh> // '' } + alarm 0; + close $fh; + return $out; +} + +# Legacy fallback: ask the binary for its version (used when no state exists). +sub installed_version { + my ($path, $spec) = @_; + return '' unless -x $path; + my $flag = $spec->{'version-flag'} // $opt{'version-flag'}; + my $out = capture(10, $path, $flag); + my ($v) = $out =~ /(\d+\.\d+(?:\.\d+)*(?:[-+][\w.]+)?)/; + return norm_ver($v); +} + +sub list_releases { + my $rels = shift; + for my $r (@$rels) { + printf "%-12s %s%s\n", $r->{tag_name}, substr($r->{published_at} // '', 0, 10), + $r->{prerelease} ? ' [prerelease]' : ''; + printf " %-32s %s\n", $_->{name}, human_size($_->{size}) + for @{ $r->{assets} || [] }; + } +} + +sub human_size { + my $n = shift // 0; + return sprintf '%.1f MB', $n / 1024 / 1024 if $n >= 1024 * 1024; + return sprintf '%.1f kB', $n / 1024 if $n >= 1024; + return "$n B"; +} + +sub which { + my $cmd = shift; + for my $dir (split /:/, ($ENV{PATH} // '')) { + my $p = File::Spec->catfile($dir, $cmd); + return $p if -x $p && !-d $p; + } + return; +} + +sub read_json { + my $path = shift; + return undef unless -f $path; + my $body = slurp($path); + return eval { JSON::PP->new->utf8->decode($body) }; +} + +sub write_json { + my ($path, $data) = @_; + my $tmp = "$path.$$"; + push @TMPFILES, $tmp; + open my $fh, '>', $tmp or die "Cannot write $tmp: $!\n"; + print {$fh} JSON::PP->new->utf8->canonical->pretty->encode($data); + close $fh or die "Cannot write $tmp: $!\n"; + rename $tmp, $path or die "Cannot update $path: $!\n"; + @TMPFILES = grep { $_ ne $tmp } @TMPFILES; +} + +sub usage { + my $rc = shift; + print <<"USAGE"; +upd - download the matching binary from the latest Gitea/GitHub release + + upd [OPTIONS] REPO-URL + upd --all [OPTIONS] + + REPO-URL e.g. https://git.fhi.mpg.de/mike/mgsh + https://github.com/sxyazi/yazi + (or use --repo / \$UPD_REPO) + +Options: + --install PATH, -i target directory (created if missing), e.g. ~/bin. + A path whose last segment is one of the binary names, + or an existing file, means that exact file. + Also \$UPD_INSTALL. Default: the directory of a + same-named binary in \$PATH, else ~/.local/bin + --name A[,B...] binary name(s) to take out of one asset, e.g. + "yazi,ya" installs both. Use "SRC:DST" to install + under a different name (default: repository name) + --all update every entry of the config file + --config PATH config file (default: ~/.config/upd/tools) + --check only report whether an update is available + --tag VERSION install a specific release ("v1.2.3" or "1.2.3") + --pre consider prereleases as well + --asset NAME exact asset name instead of auto-detection + --pattern REGEX select the asset by regex + --os OS darwin|linux|windows|freebsd (default: detected) + --arch ARCH amd64|arm64|386|arm (default: detected) + --forge NAME github|gitea (default: github for github.com hosts, + gitea otherwise; needed for GitHub Enterprise) + --token TOKEN API token for private repositories. Also read from + \$UPD_TOKEN, then \$GITHUB_TOKEN/\$GH_TOKEN (GitHub) + or \$GITEA_TOKEN (Gitea) + --version-flag F flag to query the version of a binary installed + without upd (default: --version) + --force install even if it is already up to date + --list show releases and their assets + --dry-run show what would happen, write nothing + --verbose show asset scoring and cache decisions + --quiet print errors only + --timeout SEC network timeout (default: 30) + --help this help + +Config file (one line per tool, "#" comments): + https://git.fhi.mpg.de/mike/mgsh install=~/bin + https://github.com/sxyazi/yazi install=~/bin name=yazi,ya + Keys: @{[ join ', ', @SPEC_KEYS ]} + +State is kept in @{[ state_dir() ]} +Exit codes: 0 ok, 1 usage, 2 error, 10 update available (--check) +USAGE + exit $rc; +} + +1;