{"id":138,"date":"2005-01-23T12:41:52","date_gmt":"2005-01-23T12:41:52","guid":{"rendered":"http:\/\/www.hamzy.net\/blog2\/?p=138"},"modified":"2005-01-23T12:41:52","modified_gmt":"2005-01-23T12:41:52","slug":"script_writing","status":"publish","type":"post","link":"http:\/\/www.hamzy.net\/blog2\/?p=138","title":{"rendered":"Script writing"},"content":{"rendered":"<p>\nFor work, I was asked to help port a project to Linux.  This involved<br \/>\nworking on a computer behind a firewall.  I am sure that every one is<br \/>\nfamiliar with ssh.  For those of you who are not, ssh is a program that<br \/>\nencrypts a telnet session.  And telnet is a program that allows someone to<br \/>\nlog into a computer remotely.  So, to access the computer, all I would<br \/>\nneed to do is to ssh into it.  Unfortunately, it was not that easy.\n<\/p>\n<p>\nMore follows:\n<\/p>\n<p><!--more--><\/p>\n<p>\nThe first problem is the firewall which exists to provide some measure of<br \/>\nsecurity.  The computer that I wanted to access (bob), was behind a<br \/>\nfirewall and as a result was not accessable.  To bypass the firewall, I<br \/>\nwas provided with an account on that machine.  Once I logged into the<br \/>\nfirewall (bill), I could then turn around and access bob.\n<\/p>\n<blockquote><p>\n<code><br \/>\nssh hamzy@bill<br \/>\n<\/code>\n<\/p><\/blockquote>\n<p>\nand then from within the ssh session\n<\/p>\n<blockquote><p>\n<code><br \/>\nssh hamzy@bob<br \/>\n<\/code>\n<\/p><\/blockquote>\n<p>\nWhat if I wanted to run the second ssh on my own machine (localhost)?<br \/>\nFortunately, ssh provides a solution called port forwarding.  Port<br \/>\nforwarding essentially is a small program the reads input from one port<br \/>\nand sends it to another and at the same time reads output from that port<br \/>\nand sends it back to the first port.  Ssh uses port 22.  If I were to<br \/>\ncreate a virtual port (7777) and use port forwarding to connect bill with<br \/>\nbob (7777 &lt;-&gt; 22), then I could ssh from my machine as if bob were<br \/>\ndirectly accessible from my machine.\n<\/p>\n<blockquote><p>\n<code><br \/>\nssh -L 7777:bob:22 hamzy@bill<br \/>\n<\/code>\n<\/p><\/blockquote>\n<p>\nand then from my machine\n<\/p>\n<blockquote><p>\n<code><br \/>\nssh -p 7777 hamzy@localhost<br \/>\n<\/code>\n<\/p><\/blockquote>\n<p>\nIt is still easy, right?  Unfortunately, it wasn&#8217;t.  The second problem<br \/>\nwas the my connection is unreliable.  Whatever the cause, some machine<br \/>\nalong the chain from my computer to the remote computer had some temporary<br \/>\nproblem and I would loose the connection.  Whatever work I was in the<br \/>\nmiddle of performing would be lost and I would start over.  To solve this<br \/>\nI turned to another powerful unix program called screen.  Screen<br \/>\nessentially allows one session to controll many children session.  While<br \/>\ndoing this, screen has the ability to run in the background and not mind<br \/>\nif you exit the session (logout) which would normally finish the session.<br \/>\nSo, on my local machine, I would normally start screen as follows\n<\/p>\n<blockquote><p>\n<code><br \/>\nscreen<br \/>\n<\/code>\n<\/p><\/blockquote>\n<p>\nSsh allows any program to be run instead of the default login program by<br \/>\nperforming\n<\/p>\n<blockquote><p>\n<code><br \/>\nssh -p 7777 hamzy@localhost screen<br \/>\n<\/code>\n<\/p><\/blockquote>\n<p>\nEvery time you start screen a new screen process is created.  To access a<br \/>\npreviously running screen process, I would need to provide some command<br \/>\nline arguments\n<\/p>\n<blockquote><p>\n<code><br \/>\nscreen -DR<br \/>\n<\/code>\n<\/p><\/blockquote>\n<p>\nThis will tell screen to detach the first screen process it finds and<br \/>\nreattach to it.  All I have to do is add a -t option to ssh to provide a terminal for screen to use.  So, now I will not loose my work if the connection is<br \/>\nlost.  All I need to do is put the commands into a loop that sleeps for a<br \/>\nlittle bit (to be nice) and retry the connection process.  So, was<br \/>\neverything solved?  No.  When I would go back to my session and press a<br \/>\nkey, the program would wake up and realize that the connection was lost.<br \/>\nAfter waiting for a little while, I would automatically reconnect.  I<br \/>\ncould improve this.  The version that I was using was an old version<br \/>\nof ssh.  When I used the latest version, I found that I could create a<br \/>\nfile called ~\/.ssh\/config and add the following:\n<\/p>\n<blockquote><p>\n<code><br \/>\nServerAliveInterval     15<br \/>\n<\/code><br \/><code><br \/>\nServerAliveCountMax     4<br \/>\n<\/code><br \/><code><br \/>\nTCPKeepAlive            yes<br \/>\n<\/code>\n<\/p><\/blockquote>\n<p>\nThis would tell ssh to ping the remote machine every 15 seconds and<br \/>\nterminate the connection if the remote machine did not respond after four<br \/>\nattempts.  The connection would be lost and my loop would reconnect.\n<\/p>\n<p>\nThis automation runs automatically but everytime I login to a machine it<br \/>\nwants a username and a password.  I provide the username on the command<br \/>\nline since I do not care who knows that fact, but I do not want to provide<br \/>\nthe password on the command line.  How can I solve this?  Ssh has the<br \/>\nability to encrypt a password and if I do not want to be asked for a<br \/>\npassword, then I can tell it to encrypt an empty password.  I do this by<br \/>\nthe following:\n<\/p>\n<blockquote><p>\n<code><br \/>\ncd ~\/.ssh<br \/>\n<\/code><br \/><code><br \/>\nssh-keygen -t dsa<br \/>\n<\/code>\n<\/p><\/blockquote>\n<p>\nSsh will ask me what password I want and encrypt it with the DSA<br \/>\nalgorithm.  It creates a plain text file called ~\/.ssh\/id_dsa.pub .  I can<br \/>\nnotify ssh of this on the remote machine, bob, by putting the contents of<br \/>\nthis file into another file called ~\/.ssh\/authorized_keys .  This is of<br \/>\ncourse not as secure as asking for a password every time.  But the<br \/>\ntradeoff is it will allow you to automate the connection.\n<\/p>\n<p>\nNow, I can run commands on the remote machine and port the program.  To<br \/>\ntest the program, I need to run it locally.  I will build the program on<br \/>\nthe remote machine and copy the data to my local machine.  This is called<br \/>\nmirroring.  How can I copy the files?  I could run tar on bob to bundle<br \/>\nfiles up and copy that bundle to a tar running on localhost that would<br \/>\nunbundle those files.  The steps to accomplish this is 1) run tar to<br \/>\ncreate a bundle, 2) copy the bundle, and 3) run tar to unbundle the files.<br \/>\nThis is too many separate steps.  I can improve this.\n<\/p>\n<p>\nUnix allows you to chain programs together by taking program A&#8217;s output<br \/>\nand forwarding it to program B.  Ssh follows this philosophy.  So, using<br \/>\nssh, I can connect task 1 and task 3 together without performing task 2.<br \/>\nNow, I do the following:\n<\/p>\n<blockquote><p>\n<code><br \/>\ncd location_of_files_on_localhost<br \/>\n<\/code><br \/><code><br \/>\nssh -p 7777 hamzy@localhost \"(cd location_of_files_on_bob; tar c *)\" | tar xv<br \/>\n<\/code>\n<\/p><\/blockquote>\n<p>\nHowever, there are more efficient ways to mirror files.  If the data has<br \/>\nnot changed, then nothing needs to be copied.  Also, to speed the copying<br \/>\nprocess, if only small differences exist between two files, then only<br \/>\nthose differences need to be copied.  The program that does this in Unix<br \/>\nis rsync.  The people who wrote rsync knew about ssh.  Connecting the<br \/>\ndots, I would do the following:\n<\/p>\n<blockquote><p>\n<code><br \/>\nrsync --rsh=\"ssh -l hamzy -p 7777\" localhost:location_of_files_on_bob location_of_files_on_localhost<br \/>\n<\/code>\n<\/p><\/blockquote>\n<p>\nBut what if I only wanted to copy files?  I first need to set up the port<br \/>\nforwarding but that creates a login session.  This session needs to be<br \/>\nclosed manually by logging out.  After I copy the files, I would leave<br \/>\nthis session running.  This is not very clean.  To solve this I could<br \/>\ninstead run some other program which would end automatically.  I chose to<br \/>\nrun sleep which runs for some amount of time which I arbitrarly set as<br \/>\nlong enough (one day).\n<\/p>\n<blockquote><p>\n<code><br \/>\nssh -L 7777:bob:22 hamzy@bill \"sleep 1d\"<br \/>\n<\/code><br \/><code><br \/>\n# run rsync<br \/>\n<\/code>\n<\/p><\/blockquote>\n<p>\nOne day is of course not a perfect fit and I am not looking for perfect<br \/>\nbut &#8220;good enough.&#8221;  At least, it consumes a minimal amount of resources on<br \/>\nbob.  And I can actually programmatically find it and kill it (unix<br \/>\nterminology).\n<\/p>\n<blockquote><p>\n<code><br \/>\n# kill the sleep session<br \/>\n<\/code>\n<\/p><\/blockquote>\n<p>\nNow, I am happy.  I can edit files and copy files.  But inspiration hit me<br \/>\nand I thought I can use what I just learned and do something else with it.<br \/>\nScreen is a pretty powerful program.  You can name screen sessions.  You<br \/>\ncan list running screen sessions.  Screen even allows programmatic<br \/>\nmanipulation.\n<\/p>\n<p>\nI can start a named screen session that is initially detached:\n<\/p>\n<blockquote><p>\n<code><br \/>\nscreen -dm -S AR<br \/>\n<\/code>\n<\/p><\/blockquote>\n<p>\nI can check to see if that session is running:\n<\/p>\n<blockquote><p>\n<code><br \/>\nscreen -r AR -ls -q<br \/>\n<\/code>\n<\/p><\/blockquote>\n<p>\nI can close a named screen session:\n<\/p>\n<blockquote><p>\n<code><br \/>\nscreen -dr AR -X quit<br \/>\n<\/code>\n<\/p><\/blockquote>\n<p>\nI can add a program Y to a named screen session:\n<\/p>\n<blockquote><p>\n<code><br \/>\nscreen -dr AR -X screen Y<br \/>\n<\/code>\n<\/p><\/blockquote>\n<p>\nOne of thing that I do, is use a program called bittorrent.  Of course,<br \/>\nbittorrent is despised by Hollywood since it allows people to digitally<br \/>\ncopy media.  And I am not going to go into that can of worms.  It does<br \/>\nhave its legal uses to copy programs that allow themselves to be freely<br \/>\ncopied like Linux.  This downloading takes a lot of time.  So I want to<br \/>\nstart the downloading process simply and walk away.\n<\/p>\n<p>\nNow I have all the tools that I need to accomplish that.  I can remotely<br \/>\ncontrol a machine.  I can remotely start a standalone session (screen).<br \/>\nAnd I can remotely start bittorrent with screen.  So what did I do?  I<br \/>\nwrote a shell script to do all of that.  And how did I start that process?<br \/>\nEmail!  Huh?  Unix people allow email to run programs.  When I send a<br \/>\nspecially formatted email to a machine, that machine will turn around and<br \/>\nrun my script.  My script will then start the downloading.  Mission<br \/>\naccomplished!\n<\/p>\n<p>\nLinks:\n<\/p>\n<ol>\n<li>\n<a href=\"http:\/\/www.wlug.org.nz\/SSHNotes\">http:\/\/www.wlug.org.nz\/SSHNotes<\/a>\n<\/li>\n<li>\n<a href=\"http:\/\/shfs.sourceforge.net\/\">http:\/\/shfs.sourceforge.net\/<\/a>\n<\/li>\n<li>\n<a href=\"http:\/\/savannah.gnu.org\/projects\/screen\/\">http:\/\/savannah.gnu.org\/projects\/screen\/<\/a>\n<\/li>\n<li>\n<a href=\"http:\/\/groups-beta.google.com\/group\/comp.unix.shell\/search?group=comp.unix.shell&amp;q=screen&amp;qt_g=1&amp;searchnow=Search+this+group\">http:\/\/groups-beta.google.com\/group\/comp.unix.shell\/search?group=comp.unix.shell&amp;q=screen&amp;qt_g=1&amp;searchnow=Search+this+group<\/a>\n<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>For work, I was asked to help port a project to Linux. This involved working on a computer behind a firewall. I am sure that every one is familiar with ssh. For those of you who are not, ssh is a program that encrypts a telnet session. And telnet is a program that allows someone [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-138","post","type-post","status-publish","format-standard","hentry","category-programming"],"_links":{"self":[{"href":"http:\/\/www.hamzy.net\/blog2\/index.php?rest_route=\/wp\/v2\/posts\/138","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.hamzy.net\/blog2\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.hamzy.net\/blog2\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.hamzy.net\/blog2\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.hamzy.net\/blog2\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=138"}],"version-history":[{"count":0,"href":"http:\/\/www.hamzy.net\/blog2\/index.php?rest_route=\/wp\/v2\/posts\/138\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.hamzy.net\/blog2\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=138"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.hamzy.net\/blog2\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=138"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.hamzy.net\/blog2\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=138"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}