[Android Software/Hacking General [Developers Only]] Beakhole:
[MENTION=4544860]osm0sis[/MENTION], I have a question for you that I can't seem to find a relevant thread to ask in. This is the closest I could find. I've spent a long time trying to Google this and searched XDA. So please forgive me if this is a stupid question:

Attached is a flashable zip I created a while ago but I haven't been able to get to work after rebooting. I used your flashable zip shell script update-binary. All I'm doing is flashing a script file to /su/su.d and giving it 755 perms.

Below is the update-binary:

#!/sbin/sh
# ROM Patcher: Recovery Flashable Zip
# osm0sis @ xda-developers

OUTFD=/proc/self/fd/$2;
ZIP="$3";
DIR=$(dirname "$ZIP");

# ui_print "<message>" ["<message 2>" ...]
ui_print() {
until [ ! "$1" ]; do
echo -e "ui_print $1nui_print" > $OUTFD;
shift;
done;
}
# show_progress <amount> <time>
show_progress() { echo "progress $1 $2" > $OUTFD; }
# set_progress <amount>
set_progress() { echo "set_progress $1" > $OUTFD; }

# sleep <seconds> exists in shell

# is_substring <substring> <string>
is_substring() {
case "$2" in
*$1*) echo 1;;
*) echo 0;;
esac;
}
# less_than_int <x> <y>
less_than_int() { test $1 -lt $2 && echo 1 || echo 0; }
# greater_than_int <x> <y>
greater_than_int() { test $1 -gt $2 && echo 1 || echo 0; }

# format(fs_type, partition_type, device, fs_size, mountpoint) {} is unneeded since specific format/wipe commands may be run directly
# mount <partition> exists in shell
# unmount <partition>
unmount() { umount $1; }
# is_mounted <partition>
is_mounted() {
case `mount` in
*$1*) echo 1;;
*) echo 0;;
esac;
}
# tune2fs(device[, arg, …]) {} should be done directly with the tune2fs command

# write_raw_image <file> <block>
write_raw_image() { dd if=$1 of=$2; }
# write_firmware_image() {} is a manufacturer command to apply further OEM update zips with hboot/uboot functions, so can't be duplicated
# wipe_block_device(block_dev, len) {} should be done directly with dd or nanderase
# wipe_cache() {} should be done directly with format or rm -rf

# package_extract_file <file> <destination_file>
package_extract_file() { unzip -o "$ZIP" "$1" -p > "$2"; }
# package_extract_dir <dir>
package_extract_dir() { unzip -o "$ZIP" "$1/*" -d /; }

# rename <file> <destination_file>
rename() { mv -f $1 $2; }

# delete <file> [<file2> ...]
delete() { rm -f $*; }
# delete_recursive <dir> [<dir2> ...]
delete_recursive() { rm -rf $*; }

# symlink <file/dir> <link> [<link2> ...]
symlink() {
links=$(echo $* | awk '{ print substr($0, index($0,$2)) }');
ln -s $1 $links;
}

# set_metadata <file> <uid|gid|mode|capabilities|selabel> <value> [<uid|gid|mode|capabilities|selabel_2> <value2> ...]
set_metadata() {
file="$1";
shift;
until [ ! "$2" ]; do
case $1 in
uid) chown $2 $file;;
gid) chown :$2 $file;;
mode) chmod $2 $file;;
capabilities) ;;
selabel)
for i in /system/bin/toybox /system/toolbox /system/bin/toolbox; do
LD_LIBRARY_PATH=/system/lib $i chcon -h $2 $file;
LD_LIBRARY_PATH=/system/lib $i chcon $2 $file;
done;
chcon -h $2 $file;
chcon $2 $file;
;;
*) ;;
esac;
shift 2;
done;
}
# set_metadata_recursive <dir> <uid|gid|dmode|fmode|capabilities|selabel> <value> [<uid|gid|dmode|fmode|capabilities|selabel_2> <value2> ...]
set_metadata_recursive() {
dir="$1";
shift;
until [ ! "$2" ]; do
case $1 in
uid) chown -R $2 $dir;;
gid) chown -R :$2 $dir;;
dmode) find "$dir" -type d -exec chmod $2 {} +;;
fmode) find "$dir" -type f -exec chmod $2 {} +;;
capabilities) ;;
selabel)
for i in /system/bin/toybox /system/toolbox /system/bin/toolbox; do
find "$dir" -exec LD_LIBRARY_PATH=/system/lib $i chcon -h $2 {} +;
find "$dir" -exec LD_LIBRARY_PATH=/system/lib $i chcon $2 {} +;
done;
find "$dir" -exec chcon -h $2 '{}' +;
find "$dir" -exec chcon $2 '{}' +;
;;
*) ;;
esac;
shift 2;
done;
}

# set_perm <owner> <group> <mode> <file> [<file2> ...]
set_perm() {
files=$(echo $* | awk '{ print substr($0, index($0,$4)) }');
for i in $files; do
chown $1.$2 $i; chown $1:$2 $i;
chmod $3 $i;
done;
}
# set_perm_recursive <owner> <group> <dir_mode> <file_mode> <dir> [<dir2> ...]
set_perm_recursive() {
dirs=$(echo $* | awk '{ print substr($0, index($0,$5)) }');
for i in $dirs; do
chown -R $1.$2 $i; chown -R $1:$2 $i;
find "$i" -type d -exec chmod $3 {} +;
find "$i" -type f -exec chmod $4 {} +;
done;
}

# ch_con <context> <file> [<file2> ...]
ch_con() {
files=$(echo $* | awk '{ print substr($0, index($0,$2)) }');
for i in /system/bin/toybox /system/toolbox /system/bin/toolbox; do
LD_LIBRARY_PATH=/system/lib $i chcon -h u:object_r:$1:s0 $files;
LD_LIBRARY_PATH=/system/lib $i chcon u:object_r:$1:s0 $files;
done;
chcon -h u:object_r:$1:s0 $files;
chcon u:object_r:$1:s0 $files;
}
# ch_con_recursive <dir_context> <file_context> <dir> [<dir2> ...]
ch_con_recursive() {
dirs=$(echo $* | awk '{ print substr($0, index($0,$3)) }');
for i in $dirs; do
for j in /system/bin/toybox /system/toolbox /system/bin/toolbox; do
find "$i" -type d -exec LD_LIBRARY_PATH=/system/lib $j chcon -h u:object_r:$1:s0 {} +;
find "$i" -type f -exec LD_LIBRARY_PATH=/system/lib $j chcon -h u:object_r:$2:s0 {} +;
find "$i" -type d -exec LD_LIBRARY_PATH=/system/lib $j chcon u:object_r:$1:s0 {} +;
find "$i" -type f -exec LD_LIBRARY_PATH=/system/lib $j chcon u:object_r:$2:s0 {} +;
done;
find "$i" -type d -exec chcon -h u:object_r:$1:s0 '{}' +;
find "$i" -type f -exec chcon -h u:object_r:$2:s0 '{}' +;
find "$i" -type d -exec chcon u:object_r:$1:s0 '{}' +;
find "$i" -type f -exec chcon u:object_r:$2:s0 '{}' +;
done;
}
# restore_con <file/dir> [<file2/dir2> ...]
restore_con() {
for i in /system/bin/toybox /system/toolbox /system/bin/toolbox; do
LD_LIBRARY_PATH=/system/lib $i restorecon -R $*;
done;
restorecon -R $*;
}

# read_file(filename) {} is unneeded since file contents can be read directly with the cat command
# concat(expr[, expr, ...]) {} is unneeded since string operations can be done directly
# stdout(expr[, expr, ...]) {} is unneeded since all output goes to stdout by default

# file_getprop <file> <property>
file_getprop() { grep "^$2" "$1" | cut -d= -f2; }
# getprop <property>
getprop() { test -e /sbin/getprop && /sbin/getprop $1 || grep "^$1" /default.prop; }

# sha1_check <file> [<sha1_hex> [<sha1_hex2> ...]]
sha1_check() {
sum=$(sha1sum $1 | awk '{ print $1 }');
if [ ! "$2" -o $(is_substring $sum "$*") == 1 ]; then
echo $sum;
fi;
}

# apply_patch <src_file> <tgt_file> <tgt_sha1> <tgt_size> [<src_sha1_1>:<patch1> [<src_sha1_2>:<patch2> ...]]
apply_patch() {
LD_LIBRARY_PATH=/system/lib applypatch $*;
}
# apply_patch_check <file> [<sha1_hex> [<sha1_hex2> ...]]
apply_patch_check() {
LD_LIBRARY_PATH=/system/lib applypatch -c $*;
}
# apply_patch_space <bytes>
apply_patch_space() {
LIBRARY_PATH=/system/lib applypatch -s $1;
}

# run_program(program) {} is unneeded since programs may be run directly

# abort [<message>]
abort() { ui_print "$*"; exit 1; }
# assert "<command>" ["<command2>"]
assert() {
until [ ! "$1" ]; do
$1;
test $? == 1 && abort "assert failed($1)";
shift;
done;
}

# backup_files <file> [<file2> ...]
backup_files() {
until [ ! "$1" ]; do
test ! -e "$1.bak" && cp -pf "$1" "$1.bak";
shift;
done;
}
# restore_files <file> [<file2> ...]
restore_files() {
until [ ! "$1" ]; do
mv -f "${1}.bak" "$1";
shift;
done;
}

ui_print " Flashing kernel gestures... ";
mount /su;
package_extract_dir su;
set_perm 0 0 0755 /su/su.d/ZZZ-Kernel-Gestures;
umount /su;
ui_print " --- DONE!!! --- ";

So when I flash it in TWRP, it says success. If I then immediately go into the TWRP file manager and navigate to /su/su.d I can see the flashed file there. But once I reboot into Android and navigate to /su/su.d it has disappeared.

Do you have any idea what I'm doing wrong that's causing that flashed file to disappear?

(edit: spelling)