GNU make: How to wait "cp" command to finish - bash

my makefile:
make:
# Mount Loader.bin
sudo mount -t vfat -o loop Boot.img mnt
sudo cp Loader.bin mnt
sudo umount mnt
However, the results present an error with "target busy"
$ make make
sudo mount -t vfat -o loop Boot.img mnt
[sudo] password for shore:
sudo cp Loader.bin mnt
sudo umount mnt
umount: /home/shore/MineOS/mnt: target is busy.
makefile:7: recipe for target 'make' failed
make: *** [make] Error 32
It randomly occurs and I guess the main idea is that unmouont are executed while copy is in process.
Thus I would like to ask if there is a way that it will wait the previous command finish then execute the next command
By the way, my platform is Ubuntu 18.4
Thanks very much!!

make only ever runs one line in a recipe at a time and it always waits for the previous line to complete before running the next one. It has to wait, because if the current line fails the recipe must fail without starting the next line.
What is probably happening is that the cp is exiting, but the data has not been fully flushed to the mounted filesystem: the kernel is still writing out the buffered data. So even though the copy command has finished, the partition is still busy.
Perhaps you can force it to sync using something like (here I'm assuming you're using GNU/Linux or something compatible):
make:
# Mount Loader.bin
sudo mount -t vfat -o loop Boot.img mnt
sudo cp Loader.bin mnt
sudo sync -f mnt/Loader.bin
sudo umount mnt
I don't know if that will be sufficient to force it or not.
BTW, it's usually a good idea to use sudo -n when you're using sudo in a makefile or any other non-interactive environment.

Related

Makefile running command with whoami

I am trying to use a makefile to setup my machine. I am trying to setup FZF and have the following code. However, it seems to be replacing that command with empty space instead of the user I am logged as. I have SSH'd into the Pi, so not sure if that is the cause or if it's something else.
linuxfxf:
sudo mkdir -p /usr/local/opt
sudo chown -R $(whoami) /usr/local/opt
$ is a special character for make: it introduces a make variable. If you want to run a recipe and have the shell see the $ you have to escape it:
linuxfxf:
sudo mkdir -p /usr/local/opt
sudo chown -R $$(whoami) /usr/local/opt
Or you could use the old-school syntax `whoami` instead.

Pseudo-terminal will not allocated because stdin is not a terminal & mess: ttyname failed: Inappropriate ioctl for device

I've written a shell script to scp, ssh, delete a directory, unzip, and remove the zip file
#!/bin/bash
tar -czf zipfile.tar.gz ./* .??*
scp zipfile.tar.gz root#some.ip.address:/var/www/html/wp-content/themes
rm zipfile.tar.gz
ssh root#some.ip.address << 'ENDSSH'
cd /some/directory
rm -rf zipfile
mkdir zipfile
tar xf zipfile.tar.gz -C zipfile
rm zipfile.tar.gz
ENDSSH
I am noticing that the files are successfully transferred and unzipped. The zip file is also successfully removed from the server.
However, I notice that I'm receiving these messages in the terminal
zipfile.tar.gz 100% 224KB ...
Pseudo-terminal will not be allocated because stdin is not a terminal.
...
Welcome to Ubuntu 18.04.3 LTS...
...
0 packages can be updated.
0 updates are security updates.
mesg: ttyname failed: Inappropriate ioctl for device
Running the script before the second block (ENDSSH) seems to not output those messages and executes successfully.
Is the ENDSSH causing the issue?
u can write like this:
ssh -tt root#some.ip.address << ENDSSH
your code
exit
ENDSSH
u try it.

How to create symlinks in a specific directory

I'm working on an automated installation of a openSUSE system using AutoYAST, and I'm stumped on a small detail. In order to setup relevant applications in the user's environment, I try to symlink to all applications located in /usr/local/bin in ~/bin (so say /usr/local/bin has the addr2line utility, then I want to have a symlink to that in ~/bin).
I've tried to execute the following snipped to accomplish this:
su -c "for program in `ls /usr/local/bin`; do ln -s /usr/local/bin/$program ~/bin/$program; done" <user>
This snippet executes in the post-script phase of the automatic installation, which is executed as root (and seeing as I want the owner of the symlinks to be the user, this command is executed using su).
However, this does not work, and gives the following output:
++ ls /usr/local/bin
+ su -c 'for program in addr2line
ar
as
c++
c++filt
cpp
elfedit
g++
gcc
gcc-ar
gcc-nm
gcc-ranlib
gcov
gprof
i686-pc-linux-gnu-c++
i686-pc-linux-gnu-g++
i686-pc-linux-gnu-gcc
i686-pc-linux-gnu-gcc-4.9.3
i686-pc-linux-gnu-gcc-ar
i686-pc-linux-gnu-gcc-nm
i686-pc-linux-gnu-gcc-ranlib
ld
ld.bfd
nm
objcopy
objdump
ranlib
readelf
size
strings
strip; do ln -s /usr/local/bin/ ~/bin/; done' <user>
bash: -c: line 1: syntax error near unexpected token `ar'
bash: -c: line 1: `ar'
I've tried several variations of the command, but all seem to not exactly do what I want.
For example, I've also tried:
su -c "for program in /usr/local/bin/*; do ln -s $program ~/bin/; done" <user>
But this only created a symlink to /usr/local/bin in ~/bin.
So I'm a bit stuck on this one... Does anybody have an idea?
You're using double quotes to define your su command, so $program is being evaluated immediately. You want it evaluated when su executes the command. Use single quotes instead:
su -c 'for program in `ls /usr/local/bin`; do ln -s /usr/local/bin/$program ~/bin/$program; done' <user>
You can also use cp -s to create symlinks on a system with GNU cp (like your suse system), which gives you the ability to use recursion and the other fun options of cp.
In the end, I decided to go with the command posted by pacholik to fix this, as my original attempt was over-engineered and thus not necessary.
ln -s /usr/local/bin/* ~/bin

File permissions, root bash script, edit by user

I have a script that needs to be ran as root. In this script I create directories and files. The files and directories cannot be modified by the user who ran the script (unless there root of course).
I have tried several solutions found here and other sites, first I tried to mkdir -m 777 the directories as so:
#!/bin/bash
...
#Check execution location
CDIR=$(pwd)
#File setup
DATE=$(date +"%m-%d_%H:%M:%S")
LFIL="$CDIR/android-tools/logcat/logcat_$DATE.txt"
BFIL="$CDIR/android-tools/backup/backup_$DATE"
mkdir -m 777 -p "$CDIR/android-tools/logcat/"
mkdir -m 777 -p "$CDIR/android-tools/backup/"
...
I have also tried touching every created file and directory with the $USER as root, like so:
#!/bin/bash
...
#Check execution location
CDIR=$(pwd)
#File setup
DATE=$(date +"%m-%d_%H:%M:%S")
LFIL="$CDIR/android-tools/logcat/logcat_$DATE.txt"
BFIL="$CDIR/android-tools/backup/backup_$DATE"
mkdir -p "$CDIR/android-tools/logcat/"
mkdir -p "$CDIR/android-tools/backup/"
sudo -u $USER touch "$CDIR/"
sudo -u $USER touch "$CDIR/android-tools/"
sudo -u $USER touch "$CDIR/android-tools/logcat/"
sudo -u $USER touch "$CDIR/android-tools/backup/"
sudo -u $USER touch "$CDIR/android-tools/logcat/logcat_*.txt"
sudo -u $USER touch "$CDIR/android-tools/logcat/Backup_*"
...
I have also tried manually running sudo chmod 777 /android-tools/*, and sudo chmod 777 /* from the script directory, gave no errors, but I still cannot delete the files without root permission.
Heres the full script, It's not done yet. Don't run it with an android device connected to your computer.
http://pastebin.com/F20rLJQ4
touch doesn't change ownership. I think you want chown.
If you're using sudo to run your script, $USER is root, but $SUDO_USER is the user who ran sudo, so you can use that.
If you're not using sudo, you can't trust $USER to be anything in particular. The caller can set it to anything (like "root cat /etc/shadow", which would make your above script do surprising things you didn't want it to do because you said $USER instead of "$USER").
If you're running this script using setuid, you need something safer, like id -u, to get the calling process's legitimate UID regardless of what arbitrary string happens to be in $USER.
If you cover both possibilities by making makestuff.sh like this:
# $SUDO_USER if set, otherwise the current user
caller="${SUDO_USER:-$(id -u)}"
mkdir -p foo/bar/baz
chown -R "$caller" foo
Then you can use it this way:
sudo chown root makestuff.sh
sudo chmod 755 makestuff.sh
# User runs it with sudo
sudo ./makestuff.sh
# User can remove the files
rm -r foo
Or this way (if you want to use setuid so regular users can run the script without having sudo access -- which you probably don't, because you're not being careful enough for that):
sudo chown root makestuff.sh
sudo chmod 4755 makestuff.sh # Danger! I told you not to do this.
# User runs it without sudo
./makestuff.sh
# User can remove the files
rm -r foo

Permission denied when trying to install gcc, even if logged as root

I'm trying to install gcc 4.7.0 on ubuntu 10.04 following that tutorial http://www.tellurian.com.au/whitepapers/multiplegcc.php. After some time to install the dependencies, I've been able to run make without errors, but the final step, make install doesn't want to succeed, it end up with permission denied.
Here's what I did :
../gcc-4.7.0/configure --prefix=/usr/local/gcc/4.7.7 --enable-languages=c,c++
make
su -l
cd /groups/gobj
make install
the result for the last command :
make[1]: Entering directory `/groups/gobj'
/bin/bash ../gcc-4.7.0/mkinstalldirs /usr/local/gcc/4.7.7 /usr/local/gcc/4.7.7
make[2]: Entering directory `/groups/gobj/fixincludes'
rm -rf /usr/local/gcc/4.7.7/libexec/gcc/x86_64-unknown-linux-gnu/4.7.0/install-tools
/bin/bash ../../gcc-4.7.0/fixincludes/../mkinstalldirs /usr/local/gcc/4.7.7/libexec
...
rm -f /usr/local/gcc/4.7.7/share/info/gccinstall.info
if [ -f doc/gccinstall.info ]; then \
for f in doc/gccinstall.info*; do \
realfile=`echo $f | sed -e 's|.*/\([^/]*\)$|\1|'`; \
/usr/bin/install -c -m 644 $f /usr/local/gcc/4.7.7/share/info/$realfile; \
chmod a-x /usr/local/gcc/4.7.7/share/info/$realfile; \
done; \
else true; fi
if /bin/bash -c 'install-info --version' >/dev/null 2>&1; then \
if [ -f /usr/local/gcc/4.7.7/share/info/gccinstall.info ]; then \
install-info --dir-file=/usr/local/gcc/4.7.7/share/info/dir /usr/local/gcc/4.7.7/share/info/gccinstall.info; \
else true; fi; \
else true; fi;
build/genhooks -d \
../../gcc-4.7.0/gcc/doc/tm.texi.in > tmp-tm.texi
/bin/bash: tmp-tm.texi: Permission denied
make[2]: *** [s-tm-texi] Error 1
make[2]: Leaving directory `/groups/gobj/gcc'
make[1]: *** [install-gcc] Error 2
make[1]: Leaving directory `/groups/gobj'
make: *** [install] Error 2
I've already tried su root, su -, su without succes. Some files are effectively copied to /usr/local/gcc/4.7.0 but the process stopped and I don't understand why as I'm logged as root. I've checked, the file /groups/gcc-4.7.0/gcc/doc/tm.texi.in exists. Any help ?
As puzzling as it sounds that the superuser "root" cannot create files while a normal user can, a likely scenario is that your build directory (that is, the directory in which you ran "make install") is being served from an NFS server, and it is probably mounted such that the server doesn't trust your build machine's request to write files as root.
As a simple test see if you can write an empty file to the build directory by running touch test as root. If that fails then you've found the source of the problem. Another way to confirm it is to check the output of "mount" at at least confirm that your build directory is being served via NFS.
server:/groups 20G 948M 19G 5% /groups
If you see a line like this in the mount output then you know for certain that your build directory is being NFS mounted. To tell whether or not root is being trusted, however, you'll ultimately have to check the settings on the NFS server.
Fixing the problem
The fastest way to fix this issue is to find a local filesystem on your build machine and move the contents of your build directory there, then re-run "make install".
Did you tried sudo?
sudo make install
Edit:
As root, you can add yourself to sudoers.
If you can't get root via sudo, try either
su - root
or
ssh root#...

Resources