Automate xmodem file upload - ruby

I have a device where a software update is done by uploading a file through xmodem.
I was able to do this in two ways using the lrzsz (http://ohse.de/uwe/software/lrzsz.html) package.
1) Using screen
screen /dev/tty.myserialdevice 115200
and then
^A:exec !! sz -X file.bin
or
2) Using cu
cu -l /dev/tty.myserialdevice -s 115200
and then
~+lsz -X file.bin
Now I would like to write a script (preferably a ruby or a bash script) to automate the file upload.
Is there a way to pipe the file into screen or cu or use standard input?
When I tried to write a script I only got to the point of opening a connection.
But even then I had problems to properly close this connection again.

Not sure if you are still having this problem, but I just recently had to piece together something for a similar situation.
I used screen to automate this portion, as it has some command line options to run in the background. First, I create a detached screen session, like this:
screen -d -m /dev/tty.myserialdevice 115200
Then, I can reference my created session with the -p0 option, and give it a command to execute with -X, which in this case is a command to screen itself to start an xmodem file transfer.
screen -p0 -X exec \!\! sz -X filetosend
I had noticed in other places on the web that .\!\! was also sometimes used, so keep this in mind to try if you still have problems.

Related

How to use tee or > within "screen" while also supplying the name of the screen to them?

I am trying to start a number of jobs in different screens from a shell script. Each job will read in a different value of a parameter from a premade input file and run a simulation based on that value, then tee or > the output to a differently named file. So in a do loop around all the jobs, job 40 on screen "session40" will read in line 40 of the input file, run the simulation, and output to output40.dat, for example. (I am basically trying to run a few jobs in parallel in a very elementary way; it appears my computer has plenty of RAM for this).
I am encountering the issue that the > and | tee commands do not seem to work when I use "exec" to run a command on the remote screen, despite having attempted to start a bash shell there; when I use these commands, it just prints to standard output. Although these commands do work with the command "stuff," I do not know how to pass the job number to stuff, as it appears to only work with string inputs.
The current attempted script is as follows. I have replaced the simulation script with echo and > for a simpler example of the problem. Neither of the last two screen lines work.
for i in 1:10; do
screen -Sdm session$i bash
screen -S session$i -X exec echo $i > runnumber$i.output (method 1)
screen -S session$i -X stuff $'echo $i > runnumber$i.output\r' (method 2)
done
Might there be an easy fix?

Screen CS:GO server cvar change

i want to send commands into a screen with .sh script.
Start a CSGO server with:
screen -S cs ./srcds_run -game csgo -usercon
How can i send a command to the csgo server like:
sv_cheats 1
From the screen manpage:
-X Send the specified command to a running screen session.
At https://unix.stackexchange.com/questions/13953/sending-text-input-to-a-detached-screen you find a similar question.
So for your specific problem the solution would be:
screen -S cs -X stuff "sv_scheats 1"

Getting a shell error code from curl in Jenkins while still displaying output in console

I am using a shell script in Jenkins that, at a certain point, uploads a file to a server using curl. I would like to see whatever output curl produces but also check whether it is the output I expect. If it isn't, then I want to set the shell error code to > 0 so that Jenkins knows the script failed.
I first tried using curl -f, but this causes the pipe to be cut as soon as the upload fails and the error output never gets to the client. Then I tried something like this:
curl ...params... | tee /dev/tty | \
xargs -I{} test "Expected output string" = '{}'
This works from a normal SSH shell but in the Jenkins console output I see:
tee: /dev/tty: No such device or address
I'm not sure why this is since I thought Jenkins was communicating with the slave using a normal SSH shell. In any case, the whole xargs + test thing strikes me as a bit of a hack.
Is there a way to accomplish this in Jenkins so that I can see the output and also test whether it matches a specific string?
When Jenkins communicates with slave via SSH, there is no terminal allocated, and so there is no /dev/tty device for that process.
Maybe you can send it to /dev/stderr instead? It will be a terminal in an interactive session and some log file in non-interactive session.
Have you thought about using the Publish over SSH Plugin instead of using curl? Might save you some headache.
If you just copy the file from master to slave there is also a plugin for that, copy to slave Plugin.
Cannot write any comments yet, so I had to post it as an answer.

Problems in sending input to detached 'screen' via readreg and paste

I am trying to send input to a interactive command running via screen. Here is my initial command
screen -L -c ./customrc -S psql -d -m /opt/PostgreSQL/9.0/bin/psql
The above command will run interactive psql in screen detach mode. The customrc is used to define a log file for the output (which I will read from another process by polling)
I am using following two commands to send input to psql running in screen
screen -S psql -X readreg p psqlcommands.sql
screen -S psql -X paste p
The problem is that the above commands do not work unless I reattach screen at least once. Once I have attached screen and detached, the above commands work as expected. I have to launch these commands via background java process hence the interactive shell (bash) is not available. My goal is to run psql in interactive mode and pass input to it and capture its output via a log file.
So far I have tried to run screen via xterm (or konsole or gnome-terminal) in attach mode, use readreg/paste and then detach, but I realise that xterm will not be available in my production environment. I've also tried sending output to /proc//fd/0 but I am unable to emulate 'ENTER' from keyboard (I have to attach and press in order for the output to be accepted by psql). I think pipes and fifo may help but I am unable to figure out how to proceed with them using screen and psql.
I appreciate any further hints or workarounds.
Thank you,
Usman.
Well, you can use
screen -S psql -p 0 -X stuff $'\n'
or better (works for me)
screen -S mname -p 0 -X stuff `echo -ne '\015'`
-p 0 is needed to select the window.
Have you tried this to "press enter" after your readreg and paste?
screen -S psql -X stuff $'\n'
FINAL ANSWER: It is a bug/feature in 'GNU screen' that it needs a DISPLAY atleast once for 'paste' command to work. Following are possible workarounds this problem:
Finally figured out how to utilise psql with pipes and screen. Here is the solution:
mkfifo psql.pipe
screen -L -c ./customrc -S psql -d -m bash -i -c "while (true); do cat psql.pipe; done | /opt/PostgreSQL/9.0/bin/psql -a"
After that, I can cat my commands to the pipe:
cat ./mycommands.sql > psql.pipe
To quit from screen and terminating psql, I used
screen -S psql -X quit
EDIT: (finally) figured out the solution for my problem without using screen command. Meet 'empty' utility.
empty -f -i psql.in -o psql.o -p psql.pid <psqlpath>
This allows psql to run in full interactive mode as opposed to the original solution that I used (in which psql does not run in interactive mode).
Thanks.
Usman
I had this same problem. My workaround was to launch screen attached but pass it a screenrc file where the last command is "detach"
So this is my screenrc
#change the hardstatus settings to give an window list at the bottom of the
#Set this first otherwise messes with bash profile
hardstatus alwayslastline
#screen, with the time and date and with the current window highlighted
#hardstatus string '%{= kG}%-Lw%{= kW}%50> %n%f* %t%{= kG}%+Lw%< %{= kG}%-=%c:%s%{-}'
hardstatus string '%{= kG}[ %{G}%H %{g}][%= %{= kw}%?%-Lw%?%{r}(%{W}%n*%f%t%?(%u)%?%{r})%{w}%?%+Lw%?%?%= %{g}][%{B} %m-%d %{W}%c %{g}]'
#set scrollback
defscrollback 4096
#detach
detach
Hope this helps
P

How do you start Unix screen command with a command?

According to the docs for the Unix "screen" command, you can configure it in .screenrc to start with a bunch of default screens, each running a command that you specify.
Here's my cofig:
# Default screens
screen -t "shell_0" 1
screen -t "autotest" 2 cd ~/project/contactdb ; autotest
It will not run the autotest command. That window where I'm trying to run autotest just closes instantly when I start screen.
I also tried it with just...
screen -t "autotest" 2 cd ~/project/contactdb
Same result.
I also tried...
screen -t "autotest" 2 ls
Same result there too.
What's the secret to getting it to run a command in a given screen on startup?
Your program is being run (well, except the cd), it's just that it's being run without a parent shell, so as soon as it completes, it exits and you're done.
You could do:
screen -t "autotest" 2 bash -c 'cd ~/project/contactdb ; autotest'
Spawns two shells, but life will probably go on.
Try this:
$ screen -S 'tailf messages' -d -m tailf /var/log/messages
Then later you can do:
$ screen -ls
1234.tailf messages
Followed by:
$screen -r 1234
This might help but may not be entirely what you want.
Put "zombie az" or "defzombie az" as the first line of your .screenrc. "az" can be whatever 2 keys you'd like. Now, when a screen ought to close (command finished executing, for instance), it won't actually close; hitting 'a' will close it, hitting 'z' will re-execute the command attached to that screen.
I found that at the screen user's manual.
You can also "stuff" characters into the screen as if you had typed them.
Here's how you can do that with your example:
screen -t "shell_0" 1
# create the following screen in the desired dir, instead of cd-ing afterwards :)
chdir ~/project/contactdb
screen -t "autotest" 2
# (without this sometimes screens fail to start correctly for me)
sleep 5
# paste some text into screen number 2:
select 2
stuff "autotest\012"
Here's how mine looks. It seems to work fine. I think either the parenthesis might be causing the problem or screen will not open a window if the command "autotest" does not exist.
screen -t zsh 1
screen -t emacs 2 emacs -nw
screen -t mutt 3 mutt
monitor on
screen -t mc 4 mc -s
screen -t elinks 4 elinks
Here's how I'd do it.
screen -t shell_0
chdir ~/project/contactdb
screen -t autotest autotest
The above appears to be evaluated procedurally by screen. First we establish a new screen with the title shell_0. Since we gave no other options, current working directory will be that of the parent shell or the user's home directory. We then set the default directory for new screens to ~/project/contactdb. Next, we establish a new screen running the autotest command.
Window number (n) is optional, I generally omit it.

Resources