What does the following line in this bash script do? - linux

This line is inside my /etc/rc.sysinit file on linux:
[ -r /proc/mdstat -a -r /dev/md/md-device-map ] && /sbin/mdadm -IRs
I'm not so much interested in what it actually accomplishes as opposed to how the syntax works.

It tests if the files /proc/mdstat and /dev/md/md-device-map exists and are readable (-r), and if yes executes /sbin/mdadm -IRs.
The square brackets are an alternative name of the program test (or a Bash replacement thereof), which can test for lots of stuff, such as existence of files. The -a is a logical "and".
For more details, see "CONDITIONAL EXPRESSIONS" in man bash.

The [ is actually a command name itself, that is equivalent to the test command. So, use man test to find out what -r means.
Depending on your system, you may find [ in /usr/bin:
$ ls -l /usr/bin/[
-rwxr-xr-x 1 root root 37000 Oct 5 2011 /usr/bin/[
or it could be a symlink:
$ ls -l /usr/bin/[
-rwxr-xr-x 1 root root 4 Oct 5 2011 /usr/bin/[ -> test
Some shells also have [ as a built-in command (and some even have [[ which provides additional options). As with most built-in commands though, you'll also find an implementation in the filesystem.

This means :
if /proc/mdstat is readable by you and /dev/md/md-device-map is readable by you, then run /sbin/mdadm -IRs
See help test
NOTE
[[ is a bash keyword similar to (but more powerful than) the [ command. See http://mywiki.wooledge.org/BashFAQ/031 and http://mywiki.wooledge.org/BashGuide/TestsAndConditionals
Unless you're writing for POSIX sh, we recommend [[.

Related

How to enable debugging for all bash scripts at system-wide level [duplicate]

This question already has answers here:
bash recursive xtrace
(2 answers)
Closed 11 months ago.
I have a linux system that uses lots of bash scripts as the bootup scripts. I want to print all the bash statements that are being executed in order to debug some issue. How can I do that at system-wide level?
I had the following as init in my system :
$ls -la /init
lrwxrwxrwx. 1 root root 20 Feb 10 04:46 /init -> /lib/systemd/systemd
I replaced init with a script like below :
#!/bin/bash
set -x
/lib/systemd/systemd
but no prints.
Download bash sources, change https://github.com/bminor/bash/blob/f3a35a2d601a55f337f8ca02a541f8c033682247/flags.c#L88 to echo_command_at_execute = 1. echo_command_at_execute might be reset somewhere later, in reset_shell_flags() and with change_flag('x', 0) - make echo_command_at_execute const and remove all assignments to it. Recompile and install. Create sh -> bash symlinks appriopriate for your system.
Note, that some scripts may parse stderr output of some shell programs. This modification may result in unstable system.
Copy /bin/bash to for example /bin/bash2, and similar with sh. Create an executable script:
#!/bin/bash2
/bin/bash2 -x "$#"
Repeat the process for sh. The paths have to be absolute.
Note, that for initrd you will have to regenerate it and include the copied executables and the scripts in the image. the copied executables in the image. Research your distribution specific ways about generating initrd.
I give an idea that do not confirm:
mv /bin/bash /bin/bashx
vi /bin/bash
/bin/bashx -x $#

Script command: separate input and output

I'm trying to monitor command execution on a shell.
I need to separate the input command, for example:
input:
ls -l /
output:
total 76
lrwxrwxrwx 1 root root 7 Aug 11 10:25 bin -> usr/bin
drwxr-xr-x 3 root root 4096 Aug 11 11:18 boot
drwxr-xr-x 17 root root 3200 Oct 11 11:10 dev
...
Also, I want to do the same if I open another shell, for example, after connection through ssh to another server.
I've been using script command to do this and it works just fine!
It logs all command input and output even if the shell changes (through ssh, or entering a msfconsole, for example).
Nevertheless, I found two main issues:
For my project, I need to separate (using a decoder) each command from the rest, also it would be awesome to be able to separate command input and output, for example:
cmd1. pwd ---> /var/
cmd2. echo "hello world" ---> "hello world"
....
Sometimes the script command could generate an output with garbage due to shell special characters (for colors, for example) which I would like to filter out.
So I've been thinking about this and I guess I could create a simple script that read from the file written by "script" command and processed the data.
Nevertheless, I'm not sure about what could be the best approach to do this.
I'm evaluating different solutions and I would like to know different proposals from the community.
Maybe I'm losing something and you know a better tool rather than script command or have some idea I've not considered.
Best regards,
A useful util for distinguishing stdout from stderr is annotate-output, (install the "devscripts" package), which sends stderr and stdin both to stdout along with helpful little prefixes. For example, let's try counting characters of a file that exists, plus one that doesn't exist:
annotate-output wc -c /bin/bash /bin/nosuchshell
Output:
00:29:06 I: Started wc -c /bin/bash /bin/nosuchshell
00:29:06 E: wc: /bin/nosuchshell: No such file or directory
00:29:06 O: 1099016 /bin/bash
00:29:06 O: 1099016 total
00:29:06 I: Finished with exitcode 1
That output could be parsed separately using sed, awk, or even a tee and a few greps.

user-data (cloud-init) script not executing on EC2

my user-data script
#!
set -e -x
echo `whoami`
su root
yum update -y
touch ~/PLEASE_WORK.txt
which is fed in from the command:
ec2-run-instances ami-05355a6c -n 1 -g mongo-group -k mykey -f myscript.sh -t t1.micro -z us-east-1a
but when I check the file /var/log/cloud-init.log, the tail -n 5 is:
[CLOUDINIT] 2013-07-22 16:02:29,566 - cloud-init-cfg[INFO]: cloud-init-cfg ['runcmd']
[CLOUDINIT] 2013-07-22 16:02:29,583 - __init__.py[DEBUG]: restored from cache type DataSourceEc2
[CLOUDINIT] 2013-07-22 16:02:29,686 - cloud-init-cfg[DEBUG]: handling runcmd with freq=None and args=[]
[CLOUDINIT] 2013-07-22 16:02:33,691 - cloud-init-run-module[INFO]: cloud-init-run-module ['once-per-instance', 'user-scripts', 'execute', 'run-parts', '/var/lib/cloud/data/scripts']
[CLOUDINIT] 2013-07-22 16:02:33,699 - __init__.py[DEBUG]: restored from cache type DataSourceEc2
I've also verified that curl http://169.254.169.254/latest/user-data returns my file as intended.
and no other errors or the output of my script happens. how do I get the user-data scrip to execute on boot up correctly?
Actually, cloud-init allows a single shell script as an input (though you may want to use a MIME archive for more complex setups).
The problem with the OP's script is that the first line is incorrect. You should use something like this:
#!/bin/sh
The reason for this is that, while cloud-init uses #! to recognize a user script, the operating system needs a complete shebang line in order to execute the script.
So what's happening in the OP's case is that cloud-init behaves correctly (i.e. it downloads and tries to run the script) but the operating system is unable to actually execute it.
See: Shebang (Unix) on Wikipedia
Cloud-init does not accept plain bash scripts, just like that. It's a beast that eats YAML file that defines your instance (packages, ssh keys and other stuff).
Using MIME you can also send arbitrary shell scripts, but you have to MIME-encode them.
$ cat my-boothook.txt
#!/bin/sh
echo "Hello World!"
echo "This will run as soon as possible in the boot sequence"
$ cat my-user-script.txt
#!/usr/bin/perl
print "This is a user script (rc.local)\n"
$ cat my-include.txt
# these urls will be read pulled in if they were part of user-data
# comments are allowed. The format is one url per line
http://www.ubuntu.com/robots.txt
http://www.w3schools.com/html/lastpage.htm
$ cat my-upstart-job.txt
description "a test upstart job"
start on stopped rc RUNLEVEL=[2345]
console output
task
script
echo "====BEGIN======="
echo "HELLO From an Upstart Job"
echo "=====END========"
end script
$ cat my-cloudconfig.txt
#cloud-config
ssh_import_id: [smoser]
apt_sources:
- source: "ppa:smoser/ppa"
$ ls
my-boothook.txt my-include.txt my-user-script.txt
my-cloudconfig.txt my-upstart-job.txt
$ write-mime-multipart --output=combined-userdata.txt \
my-boothook.txt:text/cloud-boothook \
my-include.txt:text/x-include-url \
my-upstart-job.txt:text/upstart-job \
my-user-script.txt:text/x-shellscript \
my-cloudconfig.txt
$ ls -l combined-userdata.txt
-rw-r--r-- 1 smoser smoser 1782 2010-07-01 16:08 combined-userdata.txt
The combined-userdata.txt is the file you want to paste there.
More info here:
https://help.ubuntu.com/community/CloudInit
Also note, this highly depends on the image you are using. But you say it is really cloud-init based image, so this applies. There are other cloud initiators which are not named cloud-init - then it could be different.
This is a couple years old now, but for others benefit I had the same issue, and it turned out that cloud-init was running twice, from inside /etc/rc3.d . Deleting these files inside the folder allowed the userdata to run correctly:
lrwxrwxrwx 1 root root 22 Jun 5 02:49 S-1cloud-config -> ../init.d/cloud-config
lrwxrwxrwx 1 root root 20 Jun 5 02:49 S-1cloud-init -> ../init.d/cloud-init
lrwxrwxrwx 1 root root 26 Jun 5 02:49 S-1cloud-init-local -> ../init.d/cloud-init-local
The problem is with cloud-init not allowing the user script to run on the next start-up.
First remove the cloud-init artifacts by executing:
rm /var/lib/cloud/instances/*/sem/config_scripts_user
And then your userdata must look like this:
#!/bin/bash
echo "hello!"
And then start you instance. It now works (tested).

File/Calls substitution like LD_PRELOAD

Does there is usual utility which makes a substitution on some calls like execve and open? Like LD_PRELOAD for calls.
Example:
we have prog_A which uses prog_B.
some days ago prog_B was updated and now prog_A failed!(
usual solution is the next:
$: mv /usr/bin/prog_b /usr/bin/prog_B.new
$: ln -s /usr/bin/prog_b.old /usr/bin/prog_b
$: ./prog_a # now run
but sometimes it's uncomfortably and dirty solution. In some stories the correct way to do so:
$: util "execve+open+stat:/usr/bin/prog_b=/usr/bin/prog_b.old" ./prog_a
where execve,open & stat are system calls. What is the name of this util?
I just write a special FILE_PRELOAD utility to solve my problem.
$: FILE_PRELOAD -C "execve+open+stat:/usr/bin/prog_b:/usr/bin/prog_b.old" ./prog_a
it generates c++ code, then compiles it and then LD_PRELOAD the result lib.so file before run ./prog_a.
Using it you can hook the next calls:
open,fopen,fopen64
opendir,mkdir,rmdir
execve
unlink,unlinkat
stat,lstat,lstat64,_lxstat,_lxstat64,stat64
_xstat,_xstat64,__fxstatat
freopen,freopen64
Please, run docs/tut.sh firstly (it's a tutorial for FP utility).
The common solution is the symlink solution. It isn't dirty. Have a look at debian or Ubuntu for example. They have /etc/alternatives for that purpose.
Here comes an example listing for the view command on Ubuntu:
user#server ls -al /usr/bin/view
lrwxrwxrwx 1 root root 22 Dez 5 2009 /usr/bin/view -> /etc/alternatives/view
user#server ls -al /etc/alternatives/view
lrwxrwxrwx 1 root root 18 Dez 5 2009 /etc/alternatives/view -> /usr/bin/vim.basic

Custom commands with git-shell

How to create custom commands for git-shell? According to the documentation:
When -c is given, the program executes non-interactively;
can be one of git receive-pack, git upload-pack, git
upload-archive, cvs server, or a command in COMMAND_DIR. The shell is
started in interactive mode when no arguments are given; in this case,
COMMAND_DIR must exist, and any of the executables in it can be
invoked.
However, I'm not sure I'm understanding this correctly. I created a user called gituser, and gave him /usr/bin/git-shell as a shell. I created a directory called git-shell-commands, and put a script called 'testy' in it, but I can't make it run via git-shell.
Here is what I'm trying from an other machine:
$ ssh gituser#server.com testy
fatal: unrecognized command 'testy'
Note that git-shell is working, and responding, it just can't find my custom command.
And here is the script:
:/home/gituser/git-shell-commands# ls -l -a
total 12
drwxr-xr-x 2 gituser gituser 4096 Jan 22 17:35 .
drwxr-xr-x 4 gituser gituser 4096 Jan 22 13:57 ..
-rwxr-xr-x 1 gituser gituser 26 Jan 22 13:58 testy
:/home/gituser/git-shell-commands# ./testy
hello!
:/home/sodigit/git-shell-commands# cat testy
echo "hello!"
What am I doing wrong? How to run custom commands with git-shell?
As it turned out, this feature has been introduced in git 1.7.4. I am using debian squeeze, wich contains an older version of git, so that was why it did not work.
If you experience this problem, check your git version.
However, as of git 1.7.10, the custom commands only work in interactive mode, and not with -c. I haven't tried the newest git though, so it is possible that this problem is unrelated to the version of the software.
To allow custom commands for pre-1.7.4 (and in non-interactive mode for 1.7.10), you can use a shell script wrapper for git-shell:
#!/bin/bash
cmdline=($1)
cmd=$(basename "${cmdline[0]}")
if [ -z "$cmd" ] ; then
exec git-shell
elif [ -n "$cmd" -a -x ~/git-shell-commands/"$cmd" ] ; then
~/git-shell-commands/"$cmd" "${cmdline[#]:1}"
else
exec git-shell -c "$1"
fi
Wherever you would normally use "git-shell", refer to this script instead, though leave out any "-c" argument to this script.
As with git-shell, the above script requires that the entire command line be passed as the first argument. If you'd rather pass the command line as separate arguments:
#!/bin/bash
cmd=$(basename $1)
if [ -z "$cmd" ] ; then
exec git-shell
elif [ -n "$cmd" -a -x ~/git-shell-commands/"$cmd" ] ; then
shift
~/git-shell-commands/"$cmd" "$#"
else
exec git-shell -c "$*"
fi
For example, this lets you invoke the restricted shell in authorize_keys as:
command="sshsh $SSH_ORIGINAL_COMMAND" ...
Note that neither script creates an interactive mode for pre-1.7.4 (attempting to start an interactive session will result in a "fatal: What do you think I am? A shell?" error from git-shell), but shouldn't interfere with interactive mode in 1.7.4 and newer.
Disclaimer: this has not been vetted for security holes. Use at your own risk. In particular, each command in ~/git-shell-commands is a potential security hole (though this is true of git-shell 1.7.4 and later, even without any of the above scripts).

Resources