diff --git a/sh/.shellcheckrc b/sh/.shellcheckrc new file mode 100644 index 0000000..8e71c00 --- /dev/null +++ b/sh/.shellcheckrc @@ -0,0 +1,4 @@ +disable=3043 +enable=all +external-sources=true +shell=sh diff --git a/sh/alias/apt.sh b/sh/alias/apt.sh new file mode 100644 index 0000000..0f3294e --- /dev/null +++ b/sh/alias/apt.sh @@ -0,0 +1,95 @@ +# show package information +acl() { a__apt_cache_list "${@}"; } +a__apt_cache_list() { + apt-cache \ + show \ + "${@}" +} + +# package versions policy +acp() { a__apt_cache_policy "${@}"; } +a__apt_cache_policy() { + apt-cache \ + policy \ + "${@}" +} + +# search package +acs() { a__apt_cache_search "${@}"; } +a__apt_cache_search() { + apt-cache \ + search \ + "${@}" +} + +# +agap() { a__apt_get_auto_purge "${@}"; } +a__apt_get_auto_purge() { + apt-get \ + autopurge \ + "${@}" +} + +# +agar() { a__apt_get_auto_remove "${@}"; } +a__apt_get_auto_remove() { + apt-get \ + autoremove \ + "${@}" +} + +# clean packages cache +agc() { a__apt_get_clean "${@}"; } +a__apt_get_clean() { + apt-get \ + clean \ + "${@}" +} + +# upgrade allowing package installation or removal +agfu() { a__apt_get_full_upgrade "${@}"; } +a__apt_get_full_upgrade() { + apt-get \ + full-upgrade \ + "${@}" +} + +# install packages +agi() { a__apt_get_install "${@}"; } +a__apt_get_install() { + apt-get \ + install \ + "${@}" +} + +# +agp() { a__apt_get_purge "${@}"; } +a__apt_get_purge() { + apt-get \ + purge \ + "${@}" +} + +# +agr() { a__apt_get_remove "${@}"; } +a__apt_get_remove() { + apt-get \ + remove \ + "${@}" +} + +# update packages catalog +agud() { a__apt_get_up_date "${@}"; } +a__apt_get_up_date() { + apt-get \ + update \ + "${@}" +} + +# upgrade forbidding package installation or removal +agug() { a__apt_get_up_grade "${@}"; } +a__apt_get_up_grade() { + apt-get \ + upgrade \ + "${@}" +} diff --git a/sh/alias/batcat.sh b/sh/alias/batcat.sh new file mode 100644 index 0000000..99d8373 --- /dev/null +++ b/sh/alias/batcat.sh @@ -0,0 +1,5 @@ +b() { a__bat "${@}"; } +a__bat() { + batcat \ + "${@}" +} diff --git a/sh/alias/btrfs.sh b/sh/alias/btrfs.sh new file mode 100644 index 0000000..0e4ba62 --- /dev/null +++ b/sh/alias/btrfs.sh @@ -0,0 +1,73 @@ +bfdf() { a__btrfs_filesystem_d_f "${@}"; } +a__btrfs_filesystem_d_f() { + btrfs \ + filesystem \ + df \ + "${@}" +} + +bfdu() { a__btrfs_filesystem_d_u "${@}"; } +a__btrfs_filesystem_d_u() { + btrfs \ + filesystem \ + du \ + --summarize \ + "${@}" +} + +bfu() { a__btrfs_filesystem_usage "${@}"; } +a__btrfs_filesystem_usage() { + btrfs \ + filesystem \ + usage \ + "${@}" +} + +bpg() { a__btrfs_property_get "${@}"; } +a__btrfs_property_get() { + btrfs \ + property \ + get \ + "${@}" +} + +bsc() { a__btrfs_subvolume_create "${@}"; } +a__btrfs_subvolume_create() { + btrfs \ + subvolume \ + create \ + "${@}" +} + +bsd() { a__btrfs_subvolume_delete "${@}"; } +a__btrfs_subvolume_delete() { + btrfs \ + subvolume \ + delete \ + "${@}" +} + +bsl() { a__btrfs_subvolume_list "${@}"; } +a__btrfs_subvolume_list() { + if [ -n "${1}" ]; then + btrfs subvolume list "${1}" | + cut --delimiter " " --fields 9 | + sort + fi +} + +bss() { a__btrfs_subvolume_snapshot "${@}"; } +a__btrfs_subvolume_snapshot() { + btrfs \ + subvolume \ + snapshot \ + "${@}" +} + +bssr() { a__btrfs_subvolume_snapshot_r "${@}"; } +a__btrfs_subvolume_snapshot_r() { + btrfs \ + subvolume \ + snapshot -r \ + "${@}" +} diff --git a/sh/alias/byobu.sh b/sh/alias/byobu.sh new file mode 100644 index 0000000..0f5336e --- /dev/null +++ b/sh/alias/byobu.sh @@ -0,0 +1,27 @@ +bb() { a__byo_bu "${@}"; } +a__byo_bu() { + byobu \ + "${@}" +} + +bba() { a__byo_bu_attach "${@}"; } +a__byo_bu_attach() { + byobu \ + attach-session \ + "${@}" +} + +bbl() { a__byo_bu_ls "${@}"; } +a__byo_bu_ls() { + byobu \ + ls \ + "${@}" +} + +bbnd() { a__byo_bu_new_detach "${@}"; } +a__byo_bu_new_detach() { + byobu \ + new-session \ + -d \ + "${@}" +} diff --git a/sh/alias/chmod.sh b/sh/alias/chmod.sh new file mode 100644 index 0000000..57ec74e --- /dev/null +++ b/sh/alias/chmod.sh @@ -0,0 +1,15 @@ +# change mode to directory +cmd() { a__change_mode_directory "${@}"; } +a__change_mode_directory() { + chmod \ + "755" \ + "${@}" +} + +# change mode to file +cmf() { a__change_mode_file "${@}"; } +a__change_mode_file() { + chmod \ + "644" \ + "${@}" +} diff --git a/sh/alias/chown.sh b/sh/alias/chown.sh new file mode 100644 index 0000000..f4fa865 --- /dev/null +++ b/sh/alias/chown.sh @@ -0,0 +1,15 @@ +# change owner to root +cor() { a__change_owner_root "${@}"; } +a__change_owner_root() { + chown \ + "0:0" \ + "${@}" +} + +# change owner to user +cou() { a__change_owner_user "${@}"; } +a__change_owner_user() { + chown \ + "1000:1000" \ + "${@}" +} diff --git a/sh/alias/clear.sh b/sh/alias/clear.sh new file mode 100644 index 0000000..ae32b30 --- /dev/null +++ b/sh/alias/clear.sh @@ -0,0 +1,6 @@ +# clear terminal +c() { a__clear "${@}"; } +a__clear() { + clear \ + "${@}" +} diff --git a/sh/alias/cp.sh b/sh/alias/cp.sh new file mode 100644 index 0000000..c9e7d6b --- /dev/null +++ b/sh/alias/cp.sh @@ -0,0 +1,7 @@ +# copy interactively +cpi() { a__co_py_interactive "${@}"; } +a__co_py_interactive() { + cp \ + --interactive \ + "${@}" +} diff --git a/sh/alias/emacs.sh b/sh/alias/emacs.sh new file mode 100644 index 0000000..8e26878 --- /dev/null +++ b/sh/alias/emacs.sh @@ -0,0 +1,5 @@ +em() { a__e_macs "${@}"; } +a__e_macs() { + emacs \ + "${@}" +} diff --git a/sh/alias/evince.sh b/sh/alias/evince.sh new file mode 100644 index 0000000..25ac069 --- /dev/null +++ b/sh/alias/evince.sh @@ -0,0 +1,5 @@ +ev() { a__e_vince "${@}"; } +a__e_vince() { + evince \ + "${@}" +} diff --git a/sh/alias/git.sh b/sh/alias/git.sh new file mode 100644 index 0000000..6400092 --- /dev/null +++ b/sh/alias/git.sh @@ -0,0 +1,535 @@ +SH_GIT_LOG_FORMAT="\ +%C(auto)%h%d +S %C(red)%GS +A %C(green)%an %ae + %C(green)%ai +C %C(blue)%cn %ce + %C(blue)%ci +%B" + +# add to index +ga() { a__git_add "${@}"; } +a__git_add() { + git \ + add \ + "${@}" +} + +# add all to index +gaa() { a__git_add_all "${@}"; } +a__git_add_all() { + git \ + add \ + --all \ + "${@}" +} + +# add parts of all to index +gaap() { a__git_add_all_patch "${@}"; } +a__git_add_all_patch() { + git \ + add \ + --all \ + --patch \ + "${@}" +} + +# add parts to index +gap() { a__git_add_patch "${@}"; } +a__git_add_patch() { + git \ + add \ + --patch \ + "${@}" +} + +# create a branch +gb() { a__git_branch "${@}"; } +a__git_branch() { + git \ + branch \ + "${@}" +} + +# delete a branch +gbd() { a__git_branch_delete "${@}"; } +a__git_branch_delete() { + git \ + branch \ + --delete \ + "${@}" +} + +# force a branch deletion +gbdf() { a__git_branch_delete_force "${@}"; } +a__git_branch_delete_force() { + git \ + branch \ + --delete \ + --force \ + "${@}" +} + +# list branches +gbl() { a__git_branch_list "${@}"; } +a__git_branch_list() { + git \ + branch \ + --all \ + --list \ + --verbose \ + --verbose \ + "${@}" +} + +# set the link to a remote branch from a local branch +gbsu() { a__git_branch_set_upstream "${@}"; } +a__git_branch_set_upstream() { + git \ + branch \ + --set-upstream-to \ + "${@}" +} + +# switch to a branch or checkout file(s) from a commit +gc() { a__git_checkout "${@}"; } +a__git_checkout() { + git \ + checkout \ + "${@}" +} + +# checkout an orphan branch +gco() { a__git_checkout_orphan "${@}"; } +a__git_checkout_orphan() { + git \ + checkout \ + --orphan \ + "${@}" +} + +# pick a commit +gcp() { a__git_cherry_pick "${@}"; } +a__git_cherry_pick() { + git \ + cherry-pick \ + "${@}" +} + +# abort the commit pick +gcpa() { a__git_cherry_pick_abort "${@}"; } +a__git_cherry_pick_abort() { + git \ + cherry-pick \ + --abort \ + "${@}" +} + +# continue the commit pick +gcpc() { a__git_cherry_pick_continue "${@}"; } +a__git_cherry_pick_continue() { + git \ + cherry-pick \ + --continue \ + "${@}" +} + +# clean untracked files +gcf() { a__git_clean_force "${@}"; } +a__git_clean_force() { + git \ + clean \ + -d \ + --force \ + "${@}" +} + +# redo the last commit with a different message +gcam() { a__git_commit_amend_message "${@}"; } +a__git_commit_amend_message() { + git \ + commit \ + --amend \ + --message \ + "${@}" +} + +# make a root commit +gcem() { a__git_commit_empty_message "${@}"; } +a__git_commit_empty_message() { + git \ + commit \ + --allow-empty \ + --allow-empty-message \ + --message \ + "${@}" +} + +# commit the index +gcm() { a__git_commit_message "${@}"; } +a__git_commit_message() { + git \ + commit \ + --message \ + "${@}" +} + +# configure the user email +gcue() { a__git_config_user_email "${@}"; } +a__git_config_user_email() { + git \ + config \ + "user.email" \ + "${@}" +} + +# configure the user name +gcun() { a__git_config_user_name "${@}"; } +a__git_config_user_name() { + git \ + config \ + "user.name" \ + "${@}" +} + +# differences from last or between commits +gd() { a__git_diff "${@}"; } +a__git_diff() { + git \ + diff \ + "${@}" +} + +# display what is indexed in cache +gdc() { a__git_diff_cached "${@}"; } +a__git_diff_cached() { + git \ + diff \ + --cached \ + "${@}" +} + +# indexed character-level differences +gdcw() { a__git_diff_cached_word "${@}"; } +a__git_diff_cached_word() { + git \ + diff \ + --cached \ + --word-diff-regex "." \ + "${@}" +} + +# differences via external tool +gdt() { a__git_diff_tool "${@}"; } +a__git_diff_tool() { + git \ + difftool \ + --dir-diff \ + "${@}" +} + +# character-level differences +gdw() { a__git_diff_word "${@}"; } +a__git_diff_word() { + git \ + diff \ + --word-diff-regex "." \ + "${@}" +} + +# fetch from the remote repository +gf() { a__git_fetch "${@}"; } +a__git_fetch() { + git \ + fetch \ + --tags \ + --verbose \ + "${@}" +} + +# fetch from remote repository and prune local orphan branches +gfp() { a__git_fetch_prune "${@}"; } +a__git_fetch_prune() { + a__git_fetch \ + --prune \ + "${@}" +} + +# garbage collect all orphan commits +ggc() { a__git_garbage_collect "${@}"; } +a__git_garbage_collect() { + git \ + reflog \ + expire \ + --all \ + --expire "all" && + git \ + gc \ + --aggressive \ + --prune="now" +} + +# initialize a new repository +gi() { a__git_init "${@}"; } +a__git_init() { + git \ + init \ + "${@}" +} + +# initialize a new bare repository +gib() { a__git_init_bare "${@}"; } +a__git_init_bare() { + git \ + init \ + --bare \ + "${@}" +} + +# log history +gl() { a__git_log "${@}"; } +a__git_log() { + git \ + log \ + --abbrev=8 \ + --abbrev-commit \ + --format="${SH_GIT_LOG_FORMAT}" \ + --graph \ + "${@}" +} + +# log all history +gla() { a__git_log_all "${@}"; } +a__git_log_all() { + a__git_log \ + --all \ + "${@}" +} + +# log all history with patches +glap() { a__git_log_all_patch "${@}"; } +a__git_log_all_patch() { + a__git_log \ + --all \ + --patch \ + "${@}" +} + +# log history with patches +glp() { a__git_log_patch "${@}"; } +a__git_log_patch() { + a__git_log \ + --patch \ + "${@}" +} + +# fast-forward merge to remote branch +gm() { a__git_merge "${@}"; } +a__git_merge() { + git \ + merge \ + --ff-only \ + "${@}" +} + +# abort the current merge commit +gma() { a__git_merge_abort "${@}"; } +a__git_merge_abort() { + git \ + merge \ + --abort \ + "${@}" +} + +# do a merge commit +gmc() { a__git_merge_commit "${@}"; } +a__git_merge_commit() { + git \ + merge \ + --no-ff \ + --message \ + "${@}" +} + +# squash a branch and index its modifications +gms() { a__git_merge_squash "${@}"; } +a__git_merge_squash() { + git \ + merge \ + --squash \ + "${@}" +} + +# merge via external tool +gmt() { a__git_merge_tool "${@}"; } +a__git_merge_tool() { + git \ + mergetool \ + "${@}" +} + +# push to the remote repository +gp() { a__git_push "${@}"; } +a__git_push() { + git \ + push \ + --tags \ + --verbose \ + "${@}" +} + +# delete from the remote repository +gpd() { a__git_push_delete "${@}"; } +a__git_push_delete() { + git \ + push \ + --delete \ + "${@}" +} + +# force the push to the remote repository +gpf() { a__git_push_force "${@}"; } +a__git_push_force() { + a__git_push \ + --force \ + "${@}" +} + +# rebase current branch onto another +grb() { a__git_re_base "${@}"; } +a__git_re_base() { + git \ + rebase \ + "${@}" +} + +# abort current rebase +grba() { a__git_re_base_abort "${@}"; } +a__git_re_base_abort() { + git \ + rebase \ + --abort \ + "${@}" +} + +# continue current rebase +grbc() { a__git_re_base_continue "${@}"; } +a__git_re_base_continue() { + git \ + rebase \ + --continue \ + "${@}" +} + +# force rebase without fast-forward +grbf() { a__git_re_base_force "${@}"; } +a__git_re_base_force() { + git \ + rebase \ + --force-rebase \ + "${@}" +} + +# rebase interactively +grbi() { a__git_re_base_interactive "${@}"; } +a__git_re_base_interactive() { + git \ + rebase \ + --interactive \ + "${@}" +} + +# add a new remote repository +grma() { a__git_re_mote_add "${@}"; } +a__git_re_mote_add() { + git \ + remote \ + add \ + "${@}" +} + +# list remote repositories +grml() { a__git_re_mote_list "${@}"; } +a__git_re_mote_list() { + git \ + remote \ + --verbose \ + "${@}" +} + +# set the location of a remote repository +grmsu() { a__git_re_mote_set_upstream "${@}"; } +a__git_re_mote_set_upstream() { + git \ + remote \ + set-url \ + "${@}" +} + +# show connection to a remote repository +grms() { a__git_re_mote_show "${@}"; } +a__git_re_mote_show() { + git \ + remote \ + show \ + "${@}" +} + +# remove and add removal to index +grm() { a__git_re_move "${@}"; } +a__git_re_move() { + git \ + rm \ + "${@}" +} + +# remove file(s) from index or move current branch pointer +grs() { a__git_re_set "${@}"; } +a__git_re_set() { + git \ + reset \ + "${@}" +} + +# wipe modifications or reset current branch to another commit +grsh() { a__git_re_set_hard "${@}"; } +a__git_re_set_hard() { + git \ + reset \ + --hard \ + "${@}" +} + +# show a commit +gsc() { a__git_show_commit "${@}"; } +a__git_show_commit() { + git \ + show \ + "${@}" +} + +# current state of repository +gs() { a__git_status "${@}"; } +a__git_status() { + git \ + status \ + --untracked-files="all" \ + "${@}" +} + +# tag a commit +gt() { a__git_tag "${@}"; } +a__git_tag() { + git \ + tag \ + "${@}" +} + +# delete a tag +gtd() { a__git_tag_delete "${@}"; } +a__git_tag_delete() { + git \ + tag \ + --delete \ + "${@}" +} diff --git a/sh/alias/gpg.sh b/sh/alias/gpg.sh new file mode 100644 index 0000000..496b05e --- /dev/null +++ b/sh/alias/gpg.sh @@ -0,0 +1,14 @@ +# turn gpg agent off +gak() { a__gpg_agent_kill "${@}"; } +a__gpg_agent_kill() { + gpgconf \ + --kill "gpg-agent" +} + +# bind gpg agent to current tty +gau() { a__gpg_agent_update "${@}"; } +a__gpg_agent_update() { + gpg-connect-agent \ + updatestartuptty \ + /bye +} diff --git a/sh/alias/grep.sh b/sh/alias/grep.sh new file mode 100644 index 0000000..5b00ed7 --- /dev/null +++ b/sh/alias/grep.sh @@ -0,0 +1,9 @@ +# grep from current directory with regex +g() { a__grep "${@}"; } +a__grep() { + grep \ + --directories "recurse" \ + --line-number \ + --regexp \ + "${@}" +} diff --git a/sh/alias/kill.sh b/sh/alias/kill.sh new file mode 100644 index 0000000..718a307 --- /dev/null +++ b/sh/alias/kill.sh @@ -0,0 +1,14 @@ +# kill a process by id +k() { a__kill "${@}"; } +a__kill() { + kill \ + "${@}" +} + +# force kill a process by id +kf() { a__kill_force "${@}"; } +a__kill_force() { + kill \ + -9 \ + "${@}" +} diff --git a/sh/alias/killall.sh b/sh/alias/killall.sh new file mode 100644 index 0000000..6658065 --- /dev/null +++ b/sh/alias/killall.sh @@ -0,0 +1,14 @@ +# kill all instances of a process by name +ka() { a__kill_all "${@}"; } +a__kill_all() { + killall \ + "${@}" +} + +# force kill all instances of a process by name +kaf() { a__kill_all_force "${@}"; } +a__kill_all_force() { + killall \ + -9 \ + "${@}" +} diff --git a/sh/alias/ls.sh b/sh/alias/ls.sh new file mode 100644 index 0000000..ad5a809 --- /dev/null +++ b/sh/alias/ls.sh @@ -0,0 +1,32 @@ +export LS_COLORS="\ +di=0;94\ +" + +# list current directory’s entries +l() { a__ls "${@}"; } +a__ls() { + ls \ + --all \ + --color \ + -l \ + -p \ + --time-style "+" \ + "${@}" +} + +# list timestamps +lt() { a__ls_time "${@}"; } +a__ls_time() { + a__ls \ + --time-style "+%Y%m%d-%H%M%S%-:::z" \ + "${@}" +} + +# list timestamps recent last +ltr() { a__ls_time_reverse "${@}"; } +a__ls_time_reverse() { + a__ls_time \ + --reverse \ + -t \ + "${@}" +} diff --git a/sh/alias/lsblk.sh b/sh/alias/lsblk.sh new file mode 100644 index 0000000..43dffc6 --- /dev/null +++ b/sh/alias/lsblk.sh @@ -0,0 +1,31 @@ +# list block devices +lb() { a__list_block "${@}"; } +a__list_block() { + a__list_block_output \ + "SIZE" \ + "TYPE" \ + "FSTYPE" \ + "LABEL" \ + "MOUNTPOINTS" \ + "${@}" +} + +# base arguments +lbne() { a__list_block_no_empty "${@}"; } +a__list_block_no_empty() { + lsblk \ + --noempty \ + "${@}" +} + +# output arguments +lbo() { a__list_block_output "${@}"; } +a__list_block_output() { + local argument + local arguments="NAME" + for argument in "${@}"; do + arguments="${arguments},${argument}" + done + a__list_block_no_empty \ + --output "${arguments}" +} diff --git a/sh/alias/mkdir.sh b/sh/alias/mkdir.sh new file mode 100644 index 0000000..bebc665 --- /dev/null +++ b/sh/alias/mkdir.sh @@ -0,0 +1,14 @@ +# make a directory +md() { a__make_directory "${@}"; } +a__make_directory() { + mkdir \ + "${@}" +} + +# make a directory after making its parents +mdp() { a__make_directory_parents "${@}"; } +a__make_directory_parents() { + mkdir \ + --parents \ + "${@}" +} diff --git a/sh/alias/mount.sh b/sh/alias/mount.sh new file mode 100644 index 0000000..535910e --- /dev/null +++ b/sh/alias/mount.sh @@ -0,0 +1,5 @@ +m() { a__mount "${@}"; } +a__mount() { + mount \ + "${@}" +} diff --git a/sh/alias/mv.sh b/sh/alias/mv.sh new file mode 100644 index 0000000..0630042 --- /dev/null +++ b/sh/alias/mv.sh @@ -0,0 +1,7 @@ +# move interactively +mvi() { a__mo_ve_interactive "${@}"; } +a__mo_ve_interactive() { + mv \ + --interactive \ + "${@}" +} diff --git a/sh/alias/nano.sh b/sh/alias/nano.sh new file mode 100644 index 0000000..7570cda --- /dev/null +++ b/sh/alias/nano.sh @@ -0,0 +1,5 @@ +nn() { a__na_no "${@}"; } +a__na_no() { + nano \ + "${@}" +} diff --git a/sh/alias/newsboat.sh b/sh/alias/newsboat.sh new file mode 100644 index 0000000..6c08c90 --- /dev/null +++ b/sh/alias/newsboat.sh @@ -0,0 +1,5 @@ +nb() { a__news_boat "${@}"; } +a__news_boat() { + newsboat \ + "${@}" +} diff --git a/sh/alias/overlay.sh b/sh/alias/overlay.sh new file mode 100644 index 0000000..6357655 --- /dev/null +++ b/sh/alias/overlay.sh @@ -0,0 +1,140 @@ +obm() { a__overlay_bind_mount "${@}"; } +a__overlay_bind_mount() { + local directory + for directory in "dev" "dev/pts" "proc" "sys"; do + if ! mount --bind "/${directory}" "overlay/mount/${directory}"; then + rwx_log_error "Unable to bind mount directory: ${directory}" + return 1 + fi + done +} + +obu() { a__overlay_bind_unmount "${@}"; } +a__overlay_bind_unmount() { + local directory + for directory in "sys" "proc" "dev/pts" "dev"; do + if ! umount --lazy "overlay/mount/${directory}"; then + rwx_log_error "Unable to bind unmount directory: ${directory}" + return 1 + fi + done +} + +ocr() { a__overlay_command_root "${@}"; } +a__overlay_command_root() { + chroot \ + "overlay/mount" "${@}" +} + +ocu() { a__overlay_command_user "${@}"; } +a__overlay_command_user() { + chroot \ + --userspec "1000:1000" \ + "overlay/mount" "${@}" +} + +omm() { a__overlay_mirror_mount "${@}"; } +a__overlay_mirror_mount() { + mount --make-rslave --rbind "/deb" "overlay/mount/deb" +} + +omu() { a__overlay_mirror_unmount "${@}"; } +a__overlay_mirror_unmount() { + umount --recursive "overlay/mount/deb" +} + +orm() { a__overlay_root_mount "${@}"; } +a__overlay_root_mount() { + local root="${1}" + if [ -z "${root}" ]; then + rwx_log_error "No root target directory" + return 1 + fi + root="$(realpath "${root}")" + if ! mkdir "overlay"; then + rwx_log_error "Unable to make overlay directory" + return 2 + fi + ( + if ! cd "overlay"; then + rwx_log_error "Unable to move into overlay directory" + return 3 + fi + local directory + for directory in "lower" "upper" "work" "mount"; do + if ! mkdir --parents "${directory}"; then + rwx_log_error "Unable to make directory: ${directory}" + return 4 + fi + done + local file="${root}/filesystem.squashfs" + if ! mount "${file}" "lower"; then + rwx_log_error "Unable to lower mount: ${file}" + return 5 + fi + if ! mount \ + -o "lowerdir=lower,upperdir=upper,workdir=work" \ + -t "overlay" \ + "overlay" "mount"; then + rwx_log_error "Unable to overlay mount" + return 6 + fi + ) +} + +ors() { a__overlay_root_squash "${@}"; } +a__overlay_root_squash() { + local directory="${1}" + local file + local level="${2}" + if [ -n "${directory}" ]; then + if mkdir "${directory}"; then + [ -n "${level}" ] || level="18" + for file in "vmlinuz" "initrd.img"; do + cp "overlay/mount/${file}" "${directory}" + done + mksquashfs \ + "overlay/mount" "${directory}/filesystem.squashfs" \ + -noappend \ + -comp "zstd" -Xcompression-level "${level}" + chown --recursive 1000:1000 "${directory}" + fi + fi +} + +oru() { a__overlay_root_unmount "${@}"; } +a__overlay_root_unmount() { + ( + if ! cd "overlay"; then + rwx_log_error "Unable to move into overlay directory" + return 1 + fi + if ! umount "mount"; then + rwx_log_error "Unable to unmount mount directory" + return 2 + fi + if ! rmdir "mount"; then + rwx_log_error "Unable to remove mount directory" + return 3 + fi + local directory + for directory in "upper" "work"; do + if ! rm --force --recursive "${directory}"; then + rwx_log_error "Unable to remove directory: ${directory}" + return 4 + fi + done + if ! umount "lower"; then + rwx_log_error "Unable to unmount lower directory" + return 5 + fi + if ! rmdir "lower"; then + rwx_log_error "Unable to remove lower directory" + return 6 + fi + ) + if ! rmdir "overlay"; then + rwx_log_error "Unable to remove overlay directory" + return 7 + fi +} diff --git a/sh/alias/pass.sh b/sh/alias/pass.sh new file mode 100644 index 0000000..66cad55 --- /dev/null +++ b/sh/alias/pass.sh @@ -0,0 +1,14 @@ +# display pass entry’s content +p() { a__pass "${@}"; } +a__pass() { + pass \ + "${@}" +} + +# copy passphrase into clipboard +pc() { a__pass_clip "${@}"; } +a__pass_clip() { + pass \ + --clip \ + "${@}" +} diff --git a/sh/alias/pgrep.sh b/sh/alias/pgrep.sh new file mode 100644 index 0000000..72de025 --- /dev/null +++ b/sh/alias/pgrep.sh @@ -0,0 +1,7 @@ +# look for a string in processes names +pg() { a__proc_grep "${@}"; } +a__proc_grep() { + pgrep \ + --list-full \ + "${@}" +} diff --git a/sh/alias/pwgen.sh b/sh/alias/pwgen.sh new file mode 100644 index 0000000..3b3dc83 --- /dev/null +++ b/sh/alias/pwgen.sh @@ -0,0 +1,17 @@ +# generate passwords +pwg() { a__pass_word_gen "${@}"; } +a__pass_word_gen() { + pwgen \ + -1 \ + --num-passwords 1048576 \ + --secure \ + "${@}" +} + +# generate passwords with symbols +pwgs() { a__pass_word_gen_symbols "${@}"; } +a__pass_word_gen_symbols() { + a__pass_word_gen \ + --symbols \ + "${@}" +} diff --git a/sh/alias/rm.sh b/sh/alias/rm.sh new file mode 100644 index 0000000..9634c1b --- /dev/null +++ b/sh/alias/rm.sh @@ -0,0 +1,7 @@ +# remove interactively +rmi() { a__re_move_interactive "${@}"; } +a__re_move_interactive() { + rm \ + --interactive \ + "${@}" +} diff --git a/sh/alias/rsync.sh b/sh/alias/rsync.sh new file mode 100644 index 0000000..bdbe4ed --- /dev/null +++ b/sh/alias/rsync.sh @@ -0,0 +1,27 @@ +# synchronize +rs() { a__r_sync "${@}"; } +a__r_sync() { + rsync \ + --archive \ + --no-inc-recursive \ + --partial \ + --progress \ + --verbose \ + "${@}" +} + +# synchronize and delete after +rsda() { a__r_sync_delete_after "${@}"; } +a__r_sync_delete_after() { + a__r_sync \ + --delete-after \ + "${@}" +} + +# synchronize and delete before +rsdb() { a__r_sync_delete_before "${@}"; } +a__r_sync_delete_before() { + a__r_sync \ + --delete-before \ + "${@}" +} diff --git a/sh/alias/shell.sh b/sh/alias/shell.sh new file mode 100644 index 0000000..daadbce --- /dev/null +++ b/sh/alias/shell.sh @@ -0,0 +1,29 @@ +# shorten alias +a() { + alias \ + "${@}" +} + +# swap directory (current ↔ previous) +sd() { + cd \ + - || + return +} + +# exit terminal +x() { + exit \ + "${@}" +} + +[ "${SH_SHELL}" = "bash" ] || return + +# shellcheck disable=SC3033 +..() { + cd .. +} +# shellcheck disable=SC3033 +...() { + cd ../.. +} diff --git a/sh/alias/tar.sh b/sh/alias/tar.sh new file mode 100644 index 0000000..92b8fbf --- /dev/null +++ b/sh/alias/tar.sh @@ -0,0 +1,31 @@ +tc() { a__tar_create "${@}"; } +a__tar_create() { + a__tar_verbose \ + --create \ + --auto-compress \ + --file \ + "${@}" +} + +tl() { a__tar_list "${@}"; } +a__tar_list() { + a__tar_verbose \ + --list \ + --file \ + "${@}" +} + +tv() { a__tar_verbose "${@}"; } +a__tar_verbose() { + tar \ + --verbose \ + "${@}" +} + +tx() { a__tar_xtract "${@}"; } +a__tar_xtract() { + a__tar_verbose \ + --extract \ + --file \ + "${@}" +} diff --git a/sh/alias/tmux.sh b/sh/alias/tmux.sh new file mode 100644 index 0000000..b30dc79 --- /dev/null +++ b/sh/alias/tmux.sh @@ -0,0 +1,5 @@ +tm() { a__t_mux "${@}"; } +a__t_mux() { + tmux \ + "${@}" +} diff --git a/sh/alias/tree.sh b/sh/alias/tree.sh new file mode 100644 index 0000000..03be3de --- /dev/null +++ b/sh/alias/tree.sh @@ -0,0 +1,12 @@ +t() { a__tree "${@}"; } +a__tree() { + tree \ + "${@}" +} + +ta() { a__tree_all "${@}"; } +a__tree_all() { + tree \ + -a \ + "${@}" +} diff --git a/sh/debian.sh b/sh/debian.sh new file mode 100644 index 0000000..88e8b01 --- /dev/null +++ b/sh/debian.sh @@ -0,0 +1,76 @@ +RWX_DEBIAN_CODENAME="$( + grep "VERSION_CODENAME" "/etc/os-release" | + cut --delimiter "=" --fields "2" +)" + +rwx_apt_clean() { + apt-get \ + clean +} + +rwx_apt_conf_write() { + printf "\ +Acquire::AllowInsecureRepositories False; +Acquire::AllowWeakRepositories False; +Acquire::AllowDowngradeToInsecureRepositories False; +Acquire::Check-Valid-Until True; +APT::Install-Recommends False; +APT::Install-Suggests False; +APT::Get::Show-Versions True; +Dir::Etc::SourceParts \"\"; +Dpkg::Progress True; +" >"/etc/apt/apt.conf.d/apt.conf" +} + +rwx_apt_install_backports() { + rwx_apt_install_target "${RWX_DEBIAN_CODENAME}-backports" "${@}" +} + +rwx_apt_install_release() { + rwx_apt_install_target "${RWX_DEBIAN_CODENAME}" "${@}" +} + +rwx_apt_install_target() { + local target="${1}" + shift + local package + for package in "${@}"; do + rwx_log "" \ + "${package} ← ${target}" + apt-get \ + install \ + --assume-yes \ + --target-release "${target}" \ + "${package}" + rwx_apt_clean + done +} + +rwx_apt_sources_write() { + printf "%s" "\ +deb https://deb.debian.org/debian \ +${RWX_DEBIAN_CODENAME} main non-free-firmware contrib non-free +deb https://deb.debian.org/debian \ +${RWX_DEBIAN_CODENAME}-backports main non-free-firmware contrib non-free +deb https://deb.debian.org/debian \ +${RWX_DEBIAN_CODENAME}-updates main non-free-firmware contrib non-free +deb https://deb.debian.org/debian-security \ +${RWX_DEBIAN_CODENAME}-security main non-free-firmware contrib non-free +" >"/etc/apt/sources.list" +} + +rwx_apt_update() { + apt-get \ + update +} + +rwx_apt_upgrade() { + apt-get \ + upgrade \ + --assume-yes + rwx_apt_clean +} + +rwx_debian_frontend_disable() { + export DEBIAN_FRONTEND="noninteractive" +} diff --git a/sh/fs.sh b/sh/fs.sh new file mode 100644 index 0000000..ac46f6d --- /dev/null +++ b/sh/fs.sh @@ -0,0 +1,121 @@ +rwx_fs_make_btrfs() { + local device="${1}" + local label="${2}" + local uuid="${3}" + if [ -b "${device}" ]; then + set -- \ + --force \ + --checksum "sha256" + if [ -n "${label}" ]; then + set -- "${@}" \ + --label "${label}" + fi + if [ -n "${uuid}" ]; then + set -- "${@}" \ + --uuid "${uuid}" + fi + mkfs.btrfs "${@}" "${device}" + fi +} + +rwx_fs_make_btrfs_swap() { + local path="${1}" + local size="${2}" + local uuid="${3}" + if [ -n "${path}" ]; then + set -- filesystem mkswapfile + if [ -n "${size}" ]; then + set -- "${@}" \ + --size "${size}" + fi + if [ -n "${uuid}" ]; then + set -- "${@}" \ + --uuid "${uuid}" + fi + btrfs "${@}" "${path}" + fi +} + +rwx_fs_make_fat() { + local device="${1}" + local name="${2}" + local volid="${3}" + if [ -b "${device}" ]; then + set -- \ + -F 32 \ + -S 4096 + if [ -n "${name}" ]; then + set -- "${@}" \ + -n "${name}" + fi + if [ -n "${volid}" ]; then + set -- "${@}" \ + -i "${volid}" + fi + mkfs.fat "${@}" "${device}" + fi +} + +rwx_fs_raid_create() { + if [ -n "${4}" ]; then + local name="${1}" + local uuid="${2}" + shift 2 + mdadm \ + --create "/dev/md/${name}" \ + --level 0 \ + --metadata 1 \ + --name "md:${name}" \ + --raid-devices ${#} \ + --uuid "${uuid}" \ + "${@}" + fi +} + +rwx_fs_wipe() { + local device="${1}" + local buffer="${2}" + local count="${3}" + if [ -b "${device}" ]; then + set -- \ + status="progress" \ + if="/dev/zero" \ + of="${device}" + if [ -n "${buffer}" ]; then + set -- "${@}" \ + bs="${buffer}" + fi + if [ -n "${count}" ]; then + set -- "${@}" \ + count="${count}" + fi + dd "${@}" + fi +} + +rwx_fs_luks_format() { + local passphrase="${1}" + local device="${2}" + local label="${3}" + local uuid="${4}" + if [ -b "${device}" ]; then + set -- \ + --batch-mode \ + --cipher "aes-xts-plain64" \ + --hash "sha512" \ + --iter-time 4096 \ + --key-size 512 \ + --pbkdf "argon2id" \ + --type "luks2" \ + --use-random \ + --verbose + if [ -n "${label}" ]; then + set -- "${@}" --label "${label}" + fi + if [ -n "${uuid}" ]; then + set -- "${@}" --uuid "${uuid}" + fi + echo "${passphrase}" | + cryptsetup "${@}" luksFormat "${device}" + fi +} diff --git a/sh/gnome.sh b/sh/gnome.sh new file mode 100644 index 0000000..11831fb --- /dev/null +++ b/sh/gnome.sh @@ -0,0 +1,24 @@ +rwx_gnome_proxy() { + local value + case "${1}" in + "on") value="manual" ;; + *) value="none" ;; + esac + gsettings set "org.gnome.system.proxy" "mode" "${value}" +} + +rwx_gnome_workspaces_primary() { + local bool + local group="org.gnome.mutter" + local name="workspaces-only-on-primary" + local var="${group}/${name}" + # get + bool="$(gsettings get "${group}" "${name}")" + rwx_log_debug "${var}: ${bool}" + # not + bool="$(rwx_not "${bool}")" + rwx_log_debug "bool: ${bool}" + # set + gsettings set "${group}" "${name}" "${bool}" + rwx_log_info "${var}: ${bool}" +} diff --git a/sh/gpg.sh b/sh/gpg.sh new file mode 100644 index 0000000..a2b7f50 --- /dev/null +++ b/sh/gpg.sh @@ -0,0 +1,12 @@ +rwx_gpg_ssh_auth_sock() { + local user_id + user_id=$(id --user) + if [ "${user_id}" -ne 0 ]; then + if [ -f "${HOME}/.gnupg/gpg-agent.conf" ]; then + SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)" + export SSH_AUTH_SOCK + fi + fi +} + +rwx_gpg_ssh_auth_sock diff --git a/sh/lint/shellcheck.sh b/sh/lint/shellcheck.sh new file mode 100644 index 0000000..11b5b0d --- /dev/null +++ b/sh/lint/shellcheck.sh @@ -0,0 +1,20 @@ +rwx_shellcheck_check() { + local root="${1}" + local file module modules path + file="$(mktemp)" + modules="$(rwx_find_sh "${root}")" + rwx_ifs_set + for module in ${modules}; do + path="${root}/${module}" + echo ". \"${path}\"" >>"${file}" + done + rwx_ifs_unset + shellcheck \ + --check-sourced \ + --enable "all" \ + --exclude "3043" \ + --external-sources \ + --shell "dash" \ + "${file}" + rm "${file}" +} diff --git a/sh/lint/shfmt.sh b/sh/lint/shfmt.sh new file mode 100644 index 0000000..107170b --- /dev/null +++ b/sh/lint/shfmt.sh @@ -0,0 +1,4 @@ +rwx_shfmt_check() { + local root="${1}" + shfmt --diff "${root}" +} diff --git a/sh/live.sh b/sh/live.sh new file mode 100644 index 0000000..7d82bfc --- /dev/null +++ b/sh/live.sh @@ -0,0 +1,6 @@ +# remount read-only medium in read-write +rwx_live_medium_remount() { + mount \ + -o "remount,rw" \ + "/usr/lib/live/mount/medium" +} diff --git a/sh/log.sh b/sh/log.sh new file mode 100644 index 0000000..9b2ffc4 --- /dev/null +++ b/sh/log.sh @@ -0,0 +1,68 @@ +RWX_LOG_LEVEL_FATAL=0 +RWX_LOG_LEVEL_ERROR=1 +RWX_LOG_LEVEL_WARN=2 +RWX_LOG_LEVEL_INFO=3 +RWX_LOG_LEVEL_DEBUG=4 +RWX_LOG_LEVEL_TRACE=5 + +RWX_LOG_LEVEL=${RWX_LOG_LEVEL_INFO} + +rwx_log() { rwx_log_info "${@}"; } + +rwx_log_debug() { + if [ "${RWX_LOG_LEVEL}" -ge "${RWX_LOG_LEVEL_DEBUG}" ]; then + _rwx_log "[DEBUG]" "${@}" + fi +} + +rwx_log_error() { + local code="${1}" + shift + [ -n "${code}" ] || rwx_log_fatal 1 "No error code" + if [ "${RWX_LOG_LEVEL}" -ge "${RWX_LOG_LEVEL_ERROR}" ]; then + _rwx_log "[ERROR]" "${@}" >&2 + return "${code}" + fi +} + +rwx_log_fatal() { + local code="${1}" + shift + [ -n "${code}" ] || rwx_log_fatal 1 "No error code" + if [ "${RWX_LOG_LEVEL}" -ge "${RWX_LOG_LEVEL_FATAL}" ]; then + _rwx_log "[FATAL]" "${@}" >&2 + exit "${code}" + fi +} + +rwx_log_info() { + if [ "${RWX_LOG_LEVEL}" -ge "${RWX_LOG_LEVEL_INFO}" ]; then + _rwx_log "" "${@}" + fi +} + +rwx_log_trace() { + if [ "${RWX_LOG_LEVEL}" -ge "${RWX_LOG_LEVEL_TRACE}" ]; then + _rwx_log "[TRACE]" "${@}" + fi +} + +rwx_log_warn() { + if [ "${RWX_LOG_LEVEL}" -ge "${RWX_LOG_LEVEL_WARN}" ]; then + _rwx_log "[ WARN]" "${@}" + fi +} + +_rwx_log() { + local prefix="${1}" + shift + [ ${#} -gt 0 ] || set -- "" + local line + for line in "${@}"; do + if [ -n "${prefix}" ]; then + _rwx_main_log "${prefix} ${line}" + else + _rwx_main_log "${line}" + fi + done +} diff --git a/sh/main.sh b/sh/main.sh new file mode 100644 index 0000000..b2dd223 --- /dev/null +++ b/sh/main.sh @@ -0,0 +1,154 @@ +# ╭───────────╮ +# │ constants │ +# ╰───────────╯ + +RWX_MAIN_FILE_NAME="main.sh" +RWX_NAME="sh" + +RWX_ROOT_SYSTEM="/etc/${RWX_NAME}" + +RWX_MAIN="${RWX_ROOT_SYSTEM}/${RWX_MAIN_FILE_NAME}" + +# ╭───────────╮ +# │ variables │ +# ╰───────────╯ + +RWX_SHELL="$(cat "/proc/${$}/comm")" +RWX_ROOT_USER="${HOME}/${RWX_NAME}" + +# ╭──────────╮ +# │ internal │ +# ╰──────────╯ + +# _RWX_IFS + +# ╭─────────╮ +# │ private │ +# ╰─────────╯ + +rwx_ifs_set() { + _RWX_IFS="${IFS}" + IFS=" +" +} + +rwx_ifs_unset() { + IFS="${_RWX_IFS}" + unset RWX_IFS +} + +_rwx_main_log() { + if rwx_shell_interactive; then + [ ${#} -gt 0 ] || set -- "" + local line + for line in "${@}"; do + echo "${line}" + done + fi +} + +# ╭────────╮ +# │ public │ +# ╰────────╯ + +# find directory’s files by extension +rwx_find_extension() { + local extension="${1}" + local root="${2}" + local file="${3}" + set -- \ + "${root}" \ + -name "*.${extension}" \ + -type "f" + [ -n "${file}" ] && + set -- "${@}" \ + -not \ + -name "${file}" + find "${@}" \ + -printf "%P\n" | + sort +} + +# find directory’s sh files +rwx_find_sh() { + rwx_find_extension "sh" "${@}" +} + +# get functions from file +rwx_grep_functions() { + local file="${1}" + grep "()" "${file}" | + cut --delimiter "(" --fields 1 +} + +# output help message +rwx_help() { + rwx_log \ + "rwx_… = functions" \ + " a__… = aliases" \ + " u__… = user" +} + +# test if active shell is in interactive mode +rwx_shell_interactive() { + case "${-}" in + *i*) ;; + *) return 1 ;; + esac +} + +rwx_main_source() { + local path="${1}" + [ -d "${path}" ] || + return 1 + local cmd count module modules + modules="$(rwx_find_sh "${path}" "${RWX_MAIN_FILE_NAME}")" + rwx_ifs_set + count=0 + _rwx_main_log "" \ + ". ${path}" + for module in ${modules}; do + count=$((count + 1)) + _rwx_main_log "$(printf "%02d" "${count}") ${module%.sh}" + module="${path}/${module}" + # shellcheck disable=SC1090 + . "${module}" + cmd="$(rwx_grep_functions "${module}")" + if [ -n "${cmd}" ]; then + [ -n "${CMD}" ] && CMD="${CMD} +" + CMD="${CMD}${cmd}" + fi + done + rwx_ifs_unset +} + +# ╭──────╮ +# │ main │ +# ╰──────╯ + +# run initial steps +rwx_main() { + # system root + if ! rwx_main_source "${RWX_ROOT_SYSTEM}"; then + _rwx_main_log "Not a directory: ${RWX_ROOT_SYSTEM}" + return 1 + fi + # user root + rwx_main_source "${RWX_ROOT_USER}" + # run interactive extras + if rwx_shell_interactive; then + # check format + rwx_log + rwx_shfmt_check "${RWX_ROOT_SYSTEM}" + # check syntax + rwx_log + rwx_shellcheck_check "${RWX_ROOT_SYSTEM}" + # help + rwx_log + rwx_help + fi +} + +# run main function +rwx_main diff --git a/sh/rescue/common.sh b/sh/rescue/common.sh new file mode 100644 index 0000000..4e2684a --- /dev/null +++ b/sh/rescue/common.sh @@ -0,0 +1,94 @@ +rwx_rescue_configure() { + local hostname="${1}" + # apt / conf + rwx_apt_conf_write + # apt / sources + rwx_apt_sources_write + # bash / rc + main_link_bashrc + mv "${HOME}/.bashrc" "${HOME}/.bashrc.old" + # host name + hostname "${hostname}" + # locales + printf "\ +en_US.UTF-8 UTF-8 +fr_FR.UTF-8 UTF-8 +" >"/etc/locale.gen" + # generate locales + locale-gen + # update catalog + rwx_apt_update + # disable frontend + rwx_debian_frontend_disable + # install backports + rwx_apt_install_backports "tmux" + # install packages + rwx_apt_install_release "apt-file" "mosh" "screen" "byobu" + # update catalog + rwx_apt_update +} + +rwx_rescue_install() { + # update catalog + rwx_apt_update + # disable frontend + rwx_debian_frontend_disable + # upgrade packages + rwx_apt_upgrade + # install packages + rwx_apt_install_release \ + "man-db" \ + "dmidecode" "efibootmgr" "lshw" "pciutils" "usbutils" \ + "parted" "mdadm" "cryptsetup-bin" "lvm2" \ + "btrfs-progs" "dosfstools" "duperemove" "squashfs-tools" \ + "git" "micro" "nano" "python3" "rsync" "vim" \ + "exa" "lf" "ncdu" "nnn" "ranger" "tree" \ + "file" "htop" "iotop" "ipcalc" "libdigest-sha3-perl" "lsof" + # install backports + rwx_apt_install_backports \ + "grub-pc-bin" \ + \ + "grub-efi-amd64-bin" +} + +rwx_rescue_upload() { + local host="${1}" + local hostname="${2}" + if [ -n "${hostname}" ]; then + local user="root" + # + local user_host="${user}@${host}" + # remove fingerprints + ssh-keygen -R "${host}" + # copy ssh id + ssh-copy-id \ + -o "StrictHostKeyChecking=accept-new" \ + "${user_host}" + # upload root + rsync --delete --recursive \ + "$(dirname "${ENV}")" "${user_host}:/etc" + # call setup + # TODO variable + ssh "${user_host}" -- \ + ". \"${ENV}\" ; rwx_rescue_configure \"${hostname}\"" + # create session + ssh "${user_host}" -- byobu new-session -d + # send keys + ssh "${user_host}" -- byobu send-keys "rwx_rescue_install" "C-m" + # attach session + mosh "${user_host}" -- byobu attach-session + else + echo "host & hostname" + return 1 + fi +} + +rwx_rescue_wipe_1_zero() { + rwx_fs_wipe "/dev/mapper/crypt" "512M" +} + +rwx_rescue_wipe_3_close() { + umount "/media/boot" + umount "/media/crypt" && + cryptsetup luksClose "crypt" +} diff --git a/sh/rescue/hetzner.sh b/sh/rescue/hetzner.sh new file mode 100644 index 0000000..9d22847 --- /dev/null +++ b/sh/rescue/hetzner.sh @@ -0,0 +1,125 @@ +rwx_rescue_wipe_0_init_hetzner_8_8() { + local device + set \ + "/dev/sda" \ + "/dev/sdb" + local members + local number + local passphrase + # read passphrase + passphrase="$(rwx_read_passphrase)" + # warn + rwx_warn_wipe "${@}" + # + number=0 + for device in "${@}"; do + number=$((number + 1)) + echo + echo "#${number}: ${device}" + # + parted --script "${device}" \ + mktable gpt \ + unit "mib" \ + mkpart "crypt-${number}" 33282 7630885 \ + mkpart "boot-${number}" 514 33282 \ + mkpart "esp-${number}" 2 514 \ + set 3 esp on \ + mkpart "bios-${number}" 1 2 \ + set 4 bios_grub on + done + # + number=0 + for device in "${@}"; do + number=$((number + 1)) + echo + echo "#${number}: ${device}4" + # wipe bios + rwx_fs_wipe "${device}4" + done + # + number=0 + for device in "${@}"; do + number=$((number + 1)) + echo + echo "#${number}: ${device}3" + # format esp + rwx_fs_wipe "${device}3" "1M" + rwx_fs_make_fat "${device}3" "esp-${number}" "0000000${number}" + # mount esp + mkdir --parents "/media/esp/${number}" + mount "${device}3" "/media/esp/${number}" + done + # + number=0 + for device in "${@}"; do + number=$((number + 1)) + echo + echo "#${number}: ${device}2" + # wipe boot + rwx_fs_wipe "${device}2" "1G" 1 + done + # + members="" + for device in "${@}"; do + members="${members} ${device}2" + done + rwx_fs_raid_create \ + "boot" "00000000:00000000:00000000:00000002" ${members} + # + rwx_fs_make_btrfs "/dev/md/boot" "boot" \ + "00000000-0000-0000-0000-00000000000b" + # mount boot + mkdir --parents "/media/boot" + mount \ + --options "autodefrag,compress-force=zstd" \ + "/dev/md/boot" "/media/boot" + # + number=0 + for device in "${@}"; do + number=$((number + 1)) + echo + echo "#${number}: ${device}1" + # wipe crypt head + rwx_fs_wipe "${device}1" "1G" 1 + done + # + members="" + for device in "${@}"; do + members="${members} ${device}1" + done + rwx_fs_raid_create \ + "crypt" "00000000:00000000:00000000:00000001" ${members} + # encrypt + rwx_fs_luks_format "${passphrase}" "/dev/md/crypt" + # open + echo "${passphrase}" | + cryptsetup luksOpen "/dev/md/crypt" "crypt" + # passphrase + unset passphrase +} + +rwx_rescue_wipe_2_make_hetzner_8_8() { + local passphrase + # close + cryptsetup luksClose "crypt" + # read passphrase + passphrase="$(rwx_read_passphrase)" + # encrypt + rwx_fs_luks_format "${passphrase}" "/dev/md/crypt" + # open + echo "${passphrase}" | + cryptsetup luksOpen "/dev/md/crypt" "crypt" + # passphrase + unset passphrase + # format crypt + rwx_fs_make_btrfs "/dev/mapper/crypt" "crypt" \ + "00000000-0000-0000-0000-00000000000c" + # mount crypt + mkdir --parents "/media/crypt" + mount \ + --options "autodefrag,compress-force=zstd" \ + "/dev/mapper/crypt" "/media/crypt" + # make swap file + rwx_fs_make_btrfs_swap "/media/crypt/swap" "64g" \ + "00000000-0000-0000-0000-000000000005" +} diff --git a/sh/rescue/ovh.sh b/sh/rescue/ovh.sh new file mode 100644 index 0000000..b4120e2 --- /dev/null +++ b/sh/rescue/ovh.sh @@ -0,0 +1,71 @@ +rwx_rescue_wipe_0_init_ovh_vle2() { + local device="/dev/sdb" + local passphrase + # read passphrase + passphrase="$(rwx_read_passphrase)" + # warn + rwx_warn_wipe "${device}" + # + parted --script "${device}" \ + mktable gpt \ + unit "mib" \ + mkpart "crypt" 4610 40959 \ + mkpart "boot" 514 4610 \ + mkpart "esp" 2 514 \ + set 3 esp on \ + mkpart bios 1 2 \ + set 4 bios_grub on + # bios / wipe + rwx_fs_wipe "${device}4" + # esp / wipe + rwx_fs_wipe "${device}3" "1M" + # esp / format + rwx_fs_make_fat "${device}3" "esp" "00000001" + # esp / mount + mkdir --parents "/media/esp" + mount "${device}3" "/media/esp" + # boot / wipe + rwx_fs_wipe "${device}2" "1G" 1 + # boot / format + rwx_fs_make_btrfs "${device}2" "boot" \ + "00000000-0000-0000-0000-00000000000b" + # boot / mount + mkdir --parents "/media/boot" + mount --options "autodefrag,compress-force=zstd" \ + "${device}2" "/media/boot" + # crypt / wipe + rwx_fs_wipe "${device}1" "1G" 1 + # crypt / encrypt + rwx_fs_luks_format "${passphrase}" "${device}1" + # crypt / open + echo "${passphrase}" | + cryptsetup luksOpen "${device}1" "crypt" + # passphrase + unset passphrase +} + +rwx_rescue_wipe_2_make_ovh_vle2() { + local device="/dev/sdb" + local passphrase + # crypt / close + cryptsetup luksClose "crypt" + # read passphrase + passphrase="$(rwx_read_passphrase)" + # crypt / encrypt + rwx_fs_luks_format "${passphrase}" "${device}1" + # crypt / open + echo "${passphrase}" | + cryptsetup luksOpen "${device}1" "crypt" + # passphrase + unset passphrase + # crypt / format + rwx_fs_make_btrfs "/dev/mapper/crypt" "crypt" \ + "00000000-0000-0000-0000-00000000000c" + # crypt / mount + mkdir --parents "/media/crypt" + mount --options "autodefrag,compress-force=zstd" \ + "/dev/mapper/crypt" "/media/crypt" + # crypt / swap + rwx_fs_make_btrfs_swap "/media/crypt/swap" "4g" \ + "00000000-0000-0000-0000-000000000005" +} diff --git a/sh/shell.sh b/sh/shell.sh new file mode 100644 index 0000000..a5f1b99 --- /dev/null +++ b/sh/shell.sh @@ -0,0 +1,125 @@ +_rwx_shell_color() { + local code="${1}" + case "${SH_SHELL}" in + "bash") + printf "\x01\e[0" + if [ -n "${code}" ]; then + printf "%s" ";${code}" + fi + printf "m\x02" + ;; + *) + printf "\033[" + if [ -n "${code}" ]; then + printf "%s" "${code}" + else + printf "0" + fi + printf "m" + ;; + esac +} +RWX_COLOR_BROWN="$(_rwx_shell_color 33)" +RWX_COLOR_CYAN="$(_rwx_shell_color 36)" +RWX_COLOR_DEFAULT="$(_rwx_shell_color)" +RWX_COLOR_GREEN="$(_rwx_shell_color 31)" +RWX_COLOR_MAGENTA="$(_rwx_shell_color 35)" +RWX_COLOR_RED="$(_rwx_shell_color 32)" + +rwx_shell_configure() { + [ -n "${ENV}" ] || ENV="${SH_MAIN}" + export ENV + # prompt + PS1="\$(rwx_shell_prompt \${?})" + PS2="├ " + # specific + case "${SH_SHELL}" in + "bash") + # completion + local root="/usr/share/bash-completion" + local file="bash_completion" + local path="${root}/${file}" + # shellcheck disable=SC1090 + [ -f "${path}" ] && . "${path}" + root="${root}/completions" + if [ -d "${root}" ]; then + set \ + "git" \ + "tar" + for file in "${@}"; do + path="${root}/${file}" + # shellcheck disable=SC1090 + [ -f "${path}" ] && . "${path}" + done + fi + # history + HISTCONTROL="ignorespace" + HISTSIZE=-1 + HISTTIMEFORMAT="%Y%m%d %H%M%S " + ;; + *) ;; + esac +} +rwx_shell_configure + +rwx_shell_prompt() { + local date host id + local code="${1}" + date="$(date +%H:%M:%S)" + local git + host="$(hostname)" + id="$(id --user)" + local path="${PWD}" + local user="${USER}" + local view="└ " + # code + if [ "${code}" -ne 0 ]; then + view="${view}${RWX_COLOR_GREEN}" + else + view="${view}${RWX_COLOR_RED}" + fi + view="${view}${code}" + # date + view="${view}${RWX_COLOR_DEFAULT} @ " + view="${view}${RWX_COLOR_BROWN}${date}" + # git + if command -v "__git_ps1" >"/dev/null"; then + git="$(__git_ps1)" + if [ -n "${git}" ]; then + view="${view}${RWX_COLOR_DEFAULT} –${RWX_COLOR_MAGENTA}${git}" + fi + fi + # new + view="${view}\\n" + # path + view="${view}${RWX_COLOR_CYAN}${path}" + # new + view="${view}\\n" + # frame + view="${view}${RWX_COLOR_DEFAULT}┌ " + # user + if [ "${id}" -eq 0 ]; then + view="${view}${RWX_COLOR_GREEN}" + else + view="${view}${RWX_COLOR_RED}" + fi + view="${view}${user}" + # host + view="${view}${RWX_COLOR_DEFAULT} @ " + view="${view}${RWX_COLOR_BROWN}${host}" + # new + view="${view}\\n" + # prompt + view="${view}${RWX_COLOR_DEFAULT}${PS2}" + # print + printf "%b" "${view}" +} + +rwx_shell_setup() { + # shell + echo "export ENV=\"${ENV}\"" >"/etc/profile.d/${SH_NAME}.sh" + # bash + local file="/etc/bash.bashrc" + rm --force --recursive "${file}" + ln --symbolic "${ENV}" "${file}" +} diff --git a/sh/util.sh b/sh/util.sh new file mode 100644 index 0000000..7d9cc3f --- /dev/null +++ b/sh/util.sh @@ -0,0 +1,37 @@ +rwx_list_block_devices() { + lsblk \ + --noempty \ + --output "NAME,SIZE,TYPE,FSTYPE,LABEL,MOUNTPOINTS" +} + +rwx_not() { + case "${1}" in + "false") echo "true" ;; + "true") echo "false" ;; + *) ;; + esac +} + +rwx_read_passphrase() { + rwx_read_secret "PassPhrase: " +} + +rwx_read_secret() { + local prompt="${1}" + local secret + printf "%s" "${prompt}" 1>&2 + stty -echo + read -r secret + stty echo + echo >&2 + echo "${secret}" + unset secret +} + +rwx_warn_wipe() { + local tmp + rwx_list_block_devices + printf "%s" "WIPE ${*} /?\\ OR CANCEL /!\\" + read -r tmp + rwx_log_trace "${tmp}" +}