en
ru
1 / 1

Tag: linux

  1. June 4, 2016 Copying script output to a logfile

    Sometimes there's a need to redirect stdout and stderr streams of a shell script to a logfile while preserving its output in the terminal. In such cases I used to wrap relevant portions of the script into compound commands and piping them to tee command. Below is a cleaner way to achieve the same results using named pipes.

    #!/usr/bin/env bash
    
    # stdout and stderr are redirected to this file.
    log_file="script.log"
    
    # Terminate script if any command results in unhandled error.
    set -e
    
    # There is no option to create a temporary fifo so we'll create a temporary
    # directory instead and put fifo inside of it.
    fifo_dir="$(mktemp -d)"
    fifo="${fifo_dir}/fifo"
    mkfifo "${fifo}"
    
    # `tee` command copies everything from fifo to both stdout and ${log_file}.
    tee "${log_file}" < "${fifo}" & tee_pid=$!
    
    # Redirect stdout and stderr to fifo.
    exec &> "${fifo}"
    
    cleanup() {
        # Remember exit code.
        code=$?
    
        # Allow cleanup code to finish even if error occurs.
        set +e
    
        echo "Exiting with code ${code}"
    
        # Close redirected stdout and stderr to finish `tee` process.
        exec 1>&- 2>&-
        wait ${tee_pid}
        rm -rf "${fifo_dir}"
    
        # Do something with generated log file, e.g.:
        # cat "${log_file}" | mail -s "${log_file}" user@example.com
    
        exit ${code}
    }
    
    # cleanup() will be called with appropriate exit code even if script finishes
    # due to an error (see `set -e` above).
    trap cleanup EXIT
    
    # Script body goes here.
    # Note that if the script process is replaced using `exec` at some point the
    # cleanup code will not be executed, i.e. temporary files will not be deleted.
    $@
    

    Closing output descriptors and waiting in cleanup() function is only needed to flush the logfile if we want to do something more with it inside of the script. Otherwise deleting the temporary directory containing the pipe is sufficient.

    There's an alternative way that uses builtin coproc command described here and some relevant discussion here. It has some benefits (e.g. not having to have access to a writable directory) but personally I'm sticking with named pipes for this purpose since the code looks more readable that way.

  2. May 17, 2016 Fixing TP-LINK login

    TP-LINK broke settings import after firmware update. Actually it was broken for quite some time (at least since 2014 according to some forums), but I've only just encountered this problem on my WDR3600 router. I don't update router firmware frequently. The breaking change was they stopped storing admin login passwords in plain text and switched to some hash sum instead (which is probably a good thing). As a result people are no longer able to login into their routers anymore after backing up and restoring their configs.

    One possible solution is resetting router to factory defaults and repeating setup from memory or from some web UI screenshots conveniently taken beforehand. I had no such screenshots and the option to reconfigure various port-forwarding and IP-binding rules wasn't very attractive.

    After some googling around I've learned that backed up config is actually more or less a text file encrypted with symmetric cypher (DES-ECB). Fortunately other people already done the research needed to decode it. Decoded config (backed up using older firmware) consists of ~1300 key-value pairs and looks like this:

    lan_ip 192.168.8.200
    lan_msk 255.255.255.0
    ...
    lgn_ousr admin
    lgn_opswd admin
    lgn_usr **********
    lgn_pwd **********
    ...
    

    To encode it back to a form consumable by the router you need to prepend the file by its MD5 sum and to pad with null bytes to the next 8 byte boundary (before encoding it using the same cypher). I've made a helpful script to automate encoding/decoding process:

    ( tlrecode.sh )

    To restore router login using this script you need to:

    • back up config before firmware update;
    • reset to hardware defaults after the update (if you tried importing the backed up settings and are unable to log in);
    • change login/password to the desired ones and back up the new config;
    • decode both configs with tlrecode.sh config.bin config.txt && tlrecode.sh config-new.bin config-new.txt;
    • update the old config, replacing lgn_ lines with the ones from the new config;
    • encode the updated config with tlrecode.sh -e config.txt config-updated.bin;
    • restore router settings using config-updated.bin.

    After update process finishes you should be able to login with your desired credentials.

  3. September 5, 2015 Switching to XFCE

    I really like Gnome 3 for its look and feel. In fact I've been using Gnome since at least version 1.2, when it came with Enlightenment for a window manager. However after recent update to Fedora 22 I've found several things in it to be just too annoying. Namely, sometimes it starts to use 100% of one of CPU cores, sometimes extensions get spontaneously unloaded, some extensions are never being updated for current Gnome versions, GDM is always running, etc. All these things compelled me to switch to something lighter and less complex.

    I've already been using xfce4-panel in a sidebar mode along with Gnome Shell, so XFCE was the natural place for me to move. Here I tried to recreate familiar environment which resulted in the following layout:

    top running in gnome-terminal and Midnight Commander with xoria256 theme running in xterm

    top running in gnome-terminal and Midnight Commander with xoria256 theme running in xterm

    ( another couple of screenshots and a bunch of patches )

    All in all, I'm quite pleased with the results. Here's the before picture (running Gnome 3) for comparison:

    gnome-shell with similar customizations

    gnome-shell with similar customizations

    It's not a whole lot different from the after version but that was the whole point.