Recursion with for loops BASH - linux

I have yet another question. This code is for the rcS script in a Linux distro I'm making and for some reason occasionally it segfaults. About 85% of the time it works just fine and all is dandy. But then there is that 15% of the time when it segfaults on either creating a directory or doing the mount.
# Find and mount all detected drives sda-sdm and partitions 0-10, you can change these by changing the values but odds are you won't have more than 26 USB drives plugged in or 10 partitions ;)
echo " ${YELLOW}[ ${BLUE}*${YELLOW} ] Finding and mounting the program drive"
for DRIVE in a b c d e f g h i j k l m n o p q r s t u v w x y z; do
mkdir "/mnt/sd${DRIVE}/"
mount "/dev/sd${DRIVE}" "/mnt/sd${DRIVE}/" 2> /dev/null
if [ ! "${?}" = '0' ]; then
rmdir "/mnt/sd${DRIVE}/"
fi
for PARTITION in 1 2 3 4 5 6 7 8 9 10; do
mkdir "/mnt/sd${DRIVE}${PARTITION}"
mount "/dev/sd${DRIVE}${PARTITION}" "/mnt/sd${DRIVE}${PARTITION}/" 2> /dev/null
if [ ! "${?}" = '0' ]; then
rmdir "/mnt/sd${DRIVE}${PARTITION}/"
fi
if [ -d /mnt/sd${DRIVE}${PARTITION}/*/program-drive-${ARCH} ]; then
if [ ! "${PROGRAM_DRIVE_FOUND}" = 'YES' ]; then
PROGRAM_DRIVE_FOUND='YES'
echo "${MESG} Found program drive on device sd${DRIVE}${PARTITION} mounted at /mnt/sd${DRIVE}${PARTITION}"
source /mnt/sd${DRIVE}${PARTITION}/*/program-drive-${ARCH}/os_info
rm "/etc/init.d/os_info"
cp /mnt/sd${DRIVE}${PARTITION}/*/program-drive-${ARCH}/os_info "/etc/init.d/os_info"
echo "${MESG} Adding user ${USER}"
/bin/adduser -s /bin/bash -G root -D "$USER"
echo "${USER}:password" | /usr/sbin/chpasswd -m > /dev/null
echo -e "${USER}\tALL=NOPASSWD: ALL" >> /etc/sudoers
mount -o loop /mnt/sd${DRIVE}${PARTITION}/*/program-drive-${ARCH}/home "/home/${USER}/" 2> /dev/null
rmdir "/home/${USER}/lost+found/" 2> /dev/null
chmod 770 "/home/${USER}/"
if [ ! "${?}" = '0' ]; then
echo "${MESG} Error mounting home on program drive! 'home' file gone or corrupt."
echo "${RED}SYSTEM BROKEN, PRESS ANY KEY TO SHUTDOWN:"
read -sn 1
poweroff
fi
fi
fi
done
done

Related

can not create RISC-V Linux root filesystem image that targets the virt machine in riscv-qemu

I am trying to create a RISC-V Linux root filesystem image. I ran the following code:
#!/bin/bash
set -e
. conf/riscv64.config
#
# locate compiler
#
GCC_DIR=$(dirname $(which ${CROSS_COMPILE}gcc))/..
if [ ! -d ${GCC_DIR} ]; then
echo "Cannot locate ${CROSS_COMPILE}gcc"
exit 1
fi
#
# create root filesystem
#
rm -f ${IMAGE_FILE}
dd if=/dev/zero of=${IMAGE_FILE} bs=1M count=${IMAGE_SIZE}
chown ${UID}:${GID} ${IMAGE_FILE}
echo '
o
n
p
1
+200M
n
p
2
t
2
c
p
w
' | fdisk ${IMAGE_FILE} && sudo losetup -P /dev/loop30 ${IMAGE_FILE} && sudo fdisk -l /dev/loop30
sudo mkfs.ext4 -j -F /dev/loop30p1
# /sbin/mkfs.ext4 -j -F ${IMAGE_FILE}
sudo mkfs.vfat -F 32 /dev/loop30p2
test -d mnt || mkdir mnt
# mount -o loop ${IMAGE_FILE} mnt
sudo mount /dev/loop30p1 mnt
set +e
#
# copy libraries, flattening symlink directory structure
#
copy_libs() {
for lib in $1/*.so*; do
if [[ ${lib} =~ (^libgomp.*|^libgfortran.*|.*\.py$) ]]; then
: # continue
elif [[ -e "$2/$(basename $lib)" ]]; then
: # continue
elif [[ -h "$lib" ]]; then
ln -s $(basename $(readlink $lib)) $2/$(basename $lib)
else
cp -a $lib $2/$(basename $lib)
fi
done
}
#
# configure root filesystem
#
(
set -e
# create directories
for dir in root bin dev etc lib lib/modules proc sbin sys mnt tmp \
usr usr/bin usr/sbin var var/run var/log var/tmp \
etc/dropbear \
etc/network/if-pre-up.d \
etc/network/if-up.d \
etc/network/if-down.d \
etc/network/if-post-down.d
do
mkdir -p mnt/${dir}
done
touch mnt/mnt/please_mount_vda2
# copy busybox and dropbear
cp build/busybox-${BUSYBOX_VERSION}/busybox mnt/bin/
cp build/dropbear-${DROPBEAR_VERSION}/scp mnt/bin/
cp build/dropbear-${DROPBEAR_VERSION}/dbclient mnt/usr/bin/
cp build/dropbear-${DROPBEAR_VERSION}/dropbear mnt/sbin/
# copy libraries
if [ -d ${GCC_DIR}/sysroot/usr/lib${ARCH/riscv/}/${ABI}/ ]; then
ABI_DIR=lib${ARCH/riscv/}/${ABI}
else
ABI_DIR=lib
fi
LDSO_NAME=ld-linux-${ARCH}-${ABI}.so.1
LDSO_TARGET=$(readlink ${GCC_DIR}/sysroot/lib/${LDSO_NAME})
mkdir -p mnt/${ABI_DIR}/
copy_libs $(dirname ${GCC_DIR}/sysroot/lib/${LDSO_TARGET})/ mnt/${ABI_DIR}/
copy_libs ${GCC_DIR}/sysroot/usr/${ABI_DIR}/ mnt/${ABI_DIR}/
if [ ! -e mnt/lib/${LDSO_NAME} ]; then
ln -s /${ABI_DIR}/$(basename ${LDSO_TARGET}) mnt/lib/${LDSO_NAME}
fi
# final configuration
rsync -a etc/ mnt/etc/
hash=$(openssl passwd -1 -salt xyzzy ${ROOT_PASSWORD})
sed -i'' "s:\*:${hash}:" mnt/etc/shadow
chmod 600 mnt/etc/shadow
touch mnt/var/log/lastlog
touch mnt/var/log/wtmp
ln -s ../bin/busybox mnt/sbin/init
ln -s busybox mnt/bin/sh
cp bin/ldd mnt/bin/ldd
mknod mnt/dev/console c 5 1
mknod mnt/dev/ttyS0 c 4 64
mknod mnt/dev/null c 1 3
)
#
# remove if configure failed
#
if [[ $? -ne 0 ]]; then
echo "*** failed to create ${IMAGE_FILE}"
rm -f ${IMAGE_FILE}
else
echo "+++ successfully created ${IMAGE_FILE}"
ls -l ${IMAGE_FILE}
fi
#
# finish
#
sudo sync
sudo umount mnt
sudo losetup -d /dev/loop30
rmdir mnt
The code stuck at
LDSO_TARGET=$(readlink ${GCC_DIR}/sysroot/lib/${LDSO_NAME}).
There is nothing print out when I ran this command in my terminal.
The LDSO_NAME is ld-linux-riscv64-lp64d.so.1 .
Is there anyone know how to fix it? How to make the following code run and successfully create a IMAGE_FILE = riscv64-rootfs.bin
And what is LDSO_NAME and LDSO_TARGET, what are they used for?

xinitrc.d content are not applied when running startx

I have a script which allows me to restart my running Xserver. However, whenever the Xserver run back again, all the contents of xinitrc.d folder aren't applied.
rm /tmp/startx.logs
LOOPTC=0
while [ $LOOPTC -eq 0 ]
do
pidof TerminalConfig 1>/dev/null 2>/dev/null
LOOPTC=$?
sleep 1
echo Tc not closed >> /tmp/startx.logs
done
killall gdm 2>/dev/null &
pkill x
if grep ^AUTOLOGIN /etc/sysconfig/autologin | egrep "NO|no|No|nO" ; then
echo autologin off >> /tmp/startx.logs
LOOPX=0
while [ $LOOPX -eq 0 ]
do
pidof X 1>/dev/null 2>/dev/null
LOOPX=$?
sleep 1
echo X not closed >> /tmp/startx.logs
done
fi
clear >> /dev/tty1
for (( i=0; i<4; i++ )) ; do
sleep 1
echo Please wait while restarting X11 Windows... >> /dev/tty1
done
clear >> /dev/tty1
ps ax | grep startx > /tmp/startx.result
sed -e s/.*grep.*//g -e /^$/d /tmp/startx.result -i
echo $(date) :startx: >> /tmp/startx.logs
cat /tmp/startx.result >> /tmp/startx.logs
if [ -s /tmp/startx.result ] ; then
echo Thu Feb 1 22:50:08 UTC 2018 :startx already running, no need to execute startx >> /tmp/startx.logs
else
killall gdm 2>/dev/null &
startx
echo $(date) :startx not running, executing startx >> /tmp/startx.logs
fi
if grep --quiet if [ ! /etc/X11/xinit/xinitrc; then
cp -f /etc/X11/xinit/xinitrc.old /etc/X11/xinit/xinitrc
rm -f /tmp/startx.result
#rm -f /tmp/restart-x.sh
Note that this script is always run on the Xserver. All the xinitrc.d contents are always applied whenever I run startx from the console (without Xserver running).
I'm wondering, why aren't the xinitrc.d files applied even if I have already ensured that the contents of the xinitrc.d folder should be applied using a for-loop and placed it in the xinitrc file?

Mount multiple folders linked together

I have three folders, /ftp/A, /ftp/B, /ftp/C but logically C is a subdirectory of B and B is a subdirectory of A.
I try to resolv this using a script at system startup that binds the folders.
I have a text file in /ftp/dirFolder where there are the relationships between the folders. Like
B C
A B C
A B
The first column is the father, the second one is the son and the third one is the nephew.
The script is this:
case "$1" in
start) while IFS=' ' read -r x y z
do
if [ -z "$z" ]; then
mkdir -p /ftp/$x/$y
mount -t none --bind /ftp/$y /ftp/$x/$y > /dev/null 2>&1
else
mkdir -p /ftp/$x/$y/$z
mount -t none --bind /ftp/$z /ftp/$x/$y/$z > /dev/null 2>&1
fi
done < /ftp/dirFolder
;;
stop) while IFS=' ' read -r x y z
do
if [ -z "$z" ]; then
umount /ftp/$x/$y > /dev/null 2>&1
else
umount /ftp/$x/$y/$z > /dev/null 2>&1
fi
done < /ftp/dirFolder
;;
The problem is: when I start the script, the folders are created and mounted correctly, but if inside C there is a folder or a file, it won't be visible inside /ftp/A/B/C but they will inside /ftp/B/C.
mount command gives me this:
/ftp/C on /ftp/B/C type none (rw,bind)
/ftp/C on /ftp/A/B/C type none (rw,bind)
Is there a way to make the folder C available from both folder A and B?
Solved, it was an error on the dirFolder file.
First you need to mount the nephew folder in the son's folder, then mount the son's folder in the father's one.
I was:
B C
A B C
A B
It should be:
B C
A B
A B C
Hope it helps someone!

Bash script: if any argument is "N" then function has extra options

(I'll reuse this as it's about the same thing).
I have managed to make a usable script that does everything what's explained below the code block, except the order of the arguments, i.e.:
./test.sh B N A
will delete B.zip, create a new archive, but stops there, A will not be processed. It's fine, I can keep N as the last argument, no problem. Also, the echo "no backup needed, removing" does not work for some reason, but that's rather optional.
My question is: can what I have done be improved/altered somehow so that if there are other folders to be added in time the only changes to the script to be the DIRx entries? The biggest problem I see is modifying the block between <start> and <stop>. Here is the script:
#!/bin/bash
DIR1=A
DIR2=B
DIR3=C
bak()
{
if [[ "$*" == N ]]
then
if [ $1 == N ]
then
:
else
echo "no backup needed, removing"
rm -v $1.zip
fi
else
if
[ -f $1.zip ]
then
/bin/mv -vi $1.zip BKP/$1.zip_`/bin/date +"%H-%M"`
else
echo "no "$1".zip"
fi
fi
}
archive()
{
if [ $* == N ]
then
:
else
if [ $1 == C ]
then
7z a -mx=9 $1.zip ../path/$1 -r -x\!$1/nope
else
7z a -mx=9 $1.zip $1 -r -x\!$1/bogus
fi
fi
}
########### <start> ####################
if [ -z "$*" ] || [[ "$#" -eq 1 && "$1" == N ]]
then
bak "$DIR1"
bak "$DIR2"
bak "$DIR3"
archive "$DIR1"
archive "$DIR2"
archive "$DIR3"
fi
############## <stop> #####################
#if [[ "$#" -eq 1 && "$1" == N ]]
#then
# rm -v "$DIR1".zip
# rm -v "$DIR2".zip
# rm -v "$DIR3".zip
# archive "$DIR1"
# archive "$DIR2"
# archive "$DIR3"
#fi
if [[ "$#" -gt 1 && "$*" == *N* ]]
then
while [ "$#" -gt 1 ]
do
if [ "$1" == N ]
then
:
else
rm -v "$1".zip
fi
archive "$1"
shift
done
else
while [ "$#" -ge 1 ]
do
bak "$1"
archive "$1"
shift
done
fi
exit 0
Now, here's what I have and want it to do. The current directory holds the script, test.sh, and the folders A and B. ls -AR produces this:
A B test.sh
./A:
1.txt 2.txt bogus
./B:
3.txt 4.txt bogus
There is another folder, C, in ../path/. The same ls -AR ../path gives this:
../path:
C
../path/C:
5.txt 6.txt nope
../path/C/nope:
q.doc w.rtf
What I want the script to do. When run with no arguments:
./test.sh
1) checks for existing zip archives in the current directory
1.a) if they exist, a backup is made for each with additional date suffix into BKP/.
2.a) if not, it lets you know
2) the three folders, A, B and C are archived, folders A and B without A/bogus and B/bogus and folder C without ../path/C/nope/* and ../path/C/nope/ .
If run with arguments, these can be any of A, B or C, with an optional N. If run with N, only:
./test.sh N
then no archive check/backup will be performed, any archives already existent will be deleted and all 3 folders get archived. If run with any combination of A, B or C, for example:
./test.sh A C
then only archives A.zip and C.zip have a check and backup and only folders A and C are archived, A without A/bogus and C without ../path/C/nope/* and ../path/C/nope/ . If run with any combination of A, B or C, but with additional N, i.e.:
./test.sh B N C
Then no check/backup is performed for B.zip and C.zip, the archives (if existent) get deleted and the folders B and C are archived.
The archives will have (inside) the folder as the root directory (i.e. open up the archive and you'll see A, B or C first) and all three of them have exceptions to the list of files to be processed: A and B don't need bogus, while C doesn't need subfolder none and anything inside it. I use 7z instead of zip because I can write:
7z a x.zip ../path/./C/bla/bla
and have C as the root directory; I couldn't do it with zip (most likely I don't know how to, it doesn't matter as long as it works).
So far, the checking and the backup work. The archiving, if no exceptions are added and I remove the $PATH thing, work. The whole script doesn't. I would have posted every combination I have done so far, but 99% of them would have probably been impossible and the rest childish. I couldn't care less how it looks as long as it does the job.
Very optional: can an alias (or some sort) like "SCF" be made to "Supercalifragilistic"? The C folder has a rather long name (I could just make a symlink, I know). I have no idea about this one.
I managed to do it. It's probably very childish and the worst possible script but I don't care right now, it works. Of course, if somebody has a better alternative to share, it's welcome, until then here's the whole script:
#!/bin/bash
# ./test.sh = 1. searches for existing archives
# 1.a. if they exist, it backups them into BKP/.
# 1.b. if not, displays a message
# 2. archives all the directories in the array list
# ./test.sh N = 1. deletes all the folder's archives existent and
# specified in the array list
# 2. archives all the directories in the array list
# ./test.sh {A..F} = 1. searches for existing archives from arguments
# 1.a. if they exist, it backups them into BKP/.
# 1.b. if not, displays a message
# 2. archives all the directories passed as arguments
# ./test.sh {A..F} N = 1. deletes all the archives matching $argument.zip
# 2. archives all the directories passed as arguments
# The directories to be backed-up/archived, all in the current (script's) path
# except "C", on a different path
DIR=(A B C D E F)
# The back-up function, if any argument is "N", processing it is omitted
bak()
{
if [[ "$*" == N ]]
then
:
else
if
[ -f $1.zip ]
then
mv -vi $1.zip BKP/$1.zip_`date +"%H-%M"`
else
echo "$(tput setaf 1) no "$1".zip$(tput sgr0)"
fi
fi
}
# The archive function, if any argument is "N", processing it is omitted. Folder
# "C" has special treatment
archive()
{
if [ $* == N ]
then
:
else
if [ $1 == C ]
then
7z a -mx=9 $1.zip ../path/$1 -r -x\!$1/nope
else
7z a -mx=9 $1.zip $1 -r -x\!$1/bogus
fi
fi
}
# case #1: no arguments
if [ -z "$*" ]
then
for i in $(seq 0 $((${#DIR[#]}-1))) # counts from 0 to array-1
do
echo "$(tput setaf 2) backup$(tput sgr0)"
bak "${DIR[i]}"
archive "${DIR[i]}"
done
exit $?
fi
# case #2: one argument, "N"
if [[ "$#" -eq 1 && "$1" == N ]]
then
for i in $(seq 0 $((${#DIR[#]}-1)))
do
echo "$(tput setaf 1) no backup needed, removing$(tput sgr0)"
rm -v "${DIR[i]}".zip
archive "${DIR[i]}"
done
exit $?
fi
# case #3: folders as arguments with "N"
if [[ "$#" -gt 1 && "$*" == *N* ]]
then
while [ "$#" -gt 1 ]
do
if [ "$1" == N ]
then
:
else
echo "$(tput setaf 1) no backup needed, removing$(tput sgr0)"
rm -v "$1".zip
fi
archive "$1"
shift
done
# case #4: folders as arguments without "N"
else
while [ "$#" -ge 1 ]
do
echo "$(tput setaf 2) backup$(tput sgr0)"
bak "$1"
archive "$1"
shift
done
fi
exit $?

How to check for a folder in 2 machines using shell script?

I am working on a shell script which I need to run on machineX. It will check for a certain folder which is in this format YYYYMMDD inside this folder MAPPED_LOCATION in other two machines - machineP and machineQ. So the path will be like this in both machineP and machineQ-
/bat/testdata/t1_snapshot/20140311
And inside the above folder path, there will be some files inside in it. Below is my shell script -
#!/bin/bash
readonly MACHINES=(machineP machineQ)
readonly MAPPED_LOCATION=/bat/testdata/t1_snapshot
readonly FILE_TIMESTAMP=20140311
# old code which I was using to get the latest folder inside each machine (P and Q)
dir1=$(ssh -o "StrictHostKeyChecking no" david#${MACHINES[0]} ls -dt1 "$MAPPED_LOCATION"/[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] | head -n1)
dir2=$(ssh -o "StrictHostKeyChecking no" david#${MACHINES[1]} ls -dt1 "$MAPPED_LOCATION"/[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] | head -n1)
dir3=$MAPPED_LOCATION/$FILE_TIMESTAMP # /bat/testdata/t1_snapshot/20140311
echo $dir1
echo $dir2
echo $dir3
if dir3 path exists in both the machines (P and Q) and number of files is greater than zero in each machine
then
# then do something here
echo "Hello World"
else
# log an error - folder is missing or number of files is zero in which servers or both servers
fi
Noow what I am supposed to do is - If this path exists /bat/testdata/t1_snapshot/20140311 in both of the machines and number of files are greater than zero in both of the machines, then do somethting. Else if the folder is missing in any of the servers or number of files is zero in any of ther servers, I will exit out of the shell script with non zero status and a message with an actual error.
How can I do this in shell script?
Update:-
for machine in $MACHINES; do
dircheck=($(ssh -o "StrictHostKeyChecking no" david#${machine} [[ ! -d "$dir3" ]] \&\& exit 1 \; ls -t1 "$dir3"))
#On the ssh command, we exit 1 if the folder doesn't exist. We check the return code with `$?`
if [[ $? != 0 ]] ;then
echo "Folder doesn't exist on $machine";
exit 1
fi
# check number of files retrieved
if [[ "${dircheck[#]}" = 0 ]] ;then
echo "0 Files on server $machine";
exit 1
fi
#all good for $machine here
done
echo "Everything is Correct"
If I am adding a new empty folder 20140411 inside machineP and then execute the above script, it always prints out -
echo "Everything is Correct"
Infact, I didn't added any folder in machineQ. Not sure what is the problem?
Another Update-
I have created an empty folder 20140411 in machineP only. And then I ran the script in debug mode -
david#machineX:~$ ./test_file_check_1.sh
+ FILERS_LOCATION=(machineP machineQ)
+ readonly FILERS_LOCATION
+ readonly MEMORY_MAPPED_LOCATION=/bexbat/data/be_t1_snapshot
+ MEMORY_MAPPED_LOCATION=/bexbat/data/be_t1_snapshot
+ readonly FILE_TIMESTAMP=20140411
+ FILE_TIMESTAMP=20140411
+ dir3=/bexbat/data/be_t1_snapshot/20140411
+ echo /bexbat/data/be_t1_snapshot/20140411
/bexbat/data/be_t1_snapshot/20140411
+ for machine in '$FILERS_LOCATION'
+ dircheck=($(ssh -o "StrictHostKeyChecking no" david#${machine} [[ ! -d "$dir3" ]] \&\& exit 1 \; ls -t1 "$dir3"))
++ ssh -o 'StrictHostKeyChecking no' david#machineP '[[' '!' -d /bexbat/data/be_t1_snapshot/20140411 ']]' '&&' exit 1 ';' ls -t1 /bexbat/data/be_t1_snapshot/20140411
+ [[ 0 != 0 ]]
+ [[ '' = 0 ]]
+ echo 'Everything is Correct'
Everything is Correct
What you want to do is, ls the remote directory (remove the -d flag to ls (which lists only folders), and the head -n1 command as it only prints the first file) and retrieve the data in an array variable.
I also added a check for directory existance [[ -d "$dir3" ]] before executing the ls and escaped the && to not be interpreted on the current bash script.
[[ -d "$dir3" ]] \&\& ls -t1 "$dir3"
To define a bash array, add extra ( ) arround the command., then compare the array size.
dir3="$MAPPED_LOCATION/$FILE_TIMESTAMP" # /bat/testdata/t1_snapshot/20140311
for machine in ${MACHINES[*]}; do
dir3check=($(ssh -o "StrictHostKeyChecking no" david#${machine} [[ -d "$dir3" ]] \&\& ls -t1 "$dir3"))
if [[ "${#dir3check[#]}" -gt 0 ]] ;then
# then do something here
echo "Hello World"
else
# log an error - folder is missing or number of files is zero in server $machine
fi
done
UPDATE:
for machine in ${MACHINES[*]}; do
dircheck=($(ssh -o "StrictHostKeyChecking no" david#${machine} [[ ! -d "$dir3" ]] \&\& exit 1 \; ls -t1 "$dir3"))
#On the ssh command, we exit 1 if the folder doesn't exist. We check the return code with `$?`
if [[ $? != 0 ]] ;then
echo "Folder doesn't exist on $machine";
exit 1
fi
# check number of files retrieved
if [[ "${#dircheck[#]}" = 0 ]] ;then
echo "0 Files on server $machine";
exit 1
fi
#all good for $machine here
done
#all good for all machines here

Resources