1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Help: Entware/Optware safe shutdown

Discussion in 'Tomato Firmware' started by Sean Rhodes, May 30, 2014.

  1. Sean Rhodes

    Sean Rhodes Networkin' Nut Member

    Going through the forum, I see lots of threads on how to mount optware/entware using the fstab, and mount -o bind etc, but nothing on how to unmount optware/entware in order to remove the USB.

    typically there is always something writing to entware, so you have to kill the process before using the gui umount feature, which kind of makes it redundant without calling up a good unmount script.

    I was trying to use the following script:
    Code:
    # Unmount Opt from flash drive
    killall ???
    sleep 5
    umount /swap
    umount /opt
    umount /data
    umount /BKUP
    sleep 10
    but there's no way to know if it's going to be the same process that I need to add to the killall command.

    I would like to have something like Koitsu's mount.autorun script, but for unmounting, i.e. can globally shutdown the processes, or make the USB non writeable before unmounting.

    Does anyone have any ideas?

    I looked at the rc.unslung script, to see if I could stop it, but since I don't fully understand it I thought I should post my question here first.

    Thanks in advance.
     
  2. szpunk

    szpunk Networkin' Nut Member

    Code:
    fuser -km /opt
    swapoff /dev/sda3
    sleep 5
    umount /opt
    umont /dev/sda1
    umount /dev/sda2
    You can install fuser from optware.
     
  3. koitsu

    koitsu Network Guru Member

    Are you manually unmounting something? If so, how? In the GUI? Physically removing the USB drive?

    If manually: you have two options:

    1) Make a script called whatever.autostop (I'd call it unmount.autostop, but the important part is that the file ends with .autostop and have execute permissions, i.e. chmod 755 unmount.autostop) and place it in the root of the mounted filesystem (i.e. the same place you have mount.autorun) and put whatever commands you want into there. You could call it sjkdfkjsdfhjk.autostop and it'd work just as well.

    How did I know this? Reviewing the source code. References to this are in files cifs.c (for CIFS mounts), jffs2.c (for JFFS stuff), misc.c, and usb.c (for USB devices).

    2) Use the "Run before unmounting" field in the GUI (to call a script on the USB stick presumably).

    It is your responsibility to properly shut down daemons before the actual unmounting is done by TomatoUSB, same with running swapoff (although TomatoUSB might do this for you -- I can try to figure it out by looking at the code if you want). TomatoUSB does not know what daemons you've started; there is no true rc or init framework on TomatoUSB, at least not like a real Linux distro. I have tried repeatedly to drive this into people's heads: DO NOT TREAT TOMATOUSB LIKE A DESKTOP LINUX DISTRIBUTION. It isn't. There is no real "rc/init/SysV script" support of any kind -- what's there is best-effort and will likely never be improved. If you really need this level of support, run OpenWRT -- that firmware aims to be more like a real Linux router distro.

    If Optware or Entware have rc.X scripts of their own that do things, then the folks who maintain those third-party bits should document how they work and explain to you what's needed.

    You should not use killall, by the way -- this is a very bad habit to get into. I've talked at length about this in another thread (I can dig it up if you'd like). Assuming the daemons you want to shut down use pidfiles (good daemons do, and they usually will write them to /var/run or possibly /opt/somewhere), you should use kill `cat /path/to/daemon.pid` or kill `pidof daemonname`. A common methodology to use that's safe is one of these:

    Code:
    #!/bin/sh
    
    # Option 1
    if [ -f /var/run/daemon.pid ]
    then
      kill `cat /var/run/daemon.pid`
    fi
    
    # Option 2
    kill `pidof daemon` 2>/dev/null
    
    If physically removing the USB drive (yanking it out with no prior actions):

    There is nothing you can do in this situation. Any daemons relying upon the filesystem as part of the physical device which you've now physically removed from the bus will need to handle the situation on their own (many are badly written and will freak out, getting stuck in loops on EIO (I/O error), and so on). There is no true, reliable solution for this issue on any system on ANY OS (including Windows). Don't let anyone tell you otherwise.
     
    Last edited: May 30, 2014
  4. Sean Rhodes

    Sean Rhodes Networkin' Nut Member

    Thanks for the info guys, It's definitely gave me something to think about.

    Koistsu, when you mention killing the daemon.pid above, can you elaborate a little more?

    Here's my output of running tasks:

    Code:
    root@Tomato:/tmp/home/root# ps
      PID USER       VSZ STAT COMMAND
        1 root      1320 S    /sbin/init noinitrd
        2 root         0 SW<  [kthreadd]
        3 root         0 SW<  [ksoftirqd/0]
        4 root         0 SW<  [events/0]
        5 root         0 SW<  [khelper]
       21 root         0 SW<  [kblockd/0]
       24 root         0 SW<  [khubd]
       52 root         0 SW   [pdflush]
       53 root         0 SW   [pdflush]
       54 root         0 SW<  [kswapd0]
       55 root         0 SW<  [aio/0]
       97 root         0 SW<  [mtdblockd]
      294 root       620 S    hotplug2 --persistent --no-coldplug
      336 root      1304 S    buttons
      337 root      1244 S    console
      338 root      1572 S    /bin/sh
      340 root      1564 S    syslogd -L -s 500 -O /tmp/mnt/BKUP/syslog -b 2
      342 root      1564 S    klogd
      449 root         0 SW<  [scsi_eh_0]
      450 root         0 SW<  [usb-storage]
      459 root         0 SW<  [scsi_eh_1]
      460 root         0 SW<  [usb-storage]
      681 root      1072 S    dropbear -p 22 -p 2222 -s -a
      723 root      1584 S    crond -l 9
      728 root       932 S    rstats
      734 root      1148 S    cstats
    1268 root      2384 S    nmbd -D
    1271 root      2328 S    nmbd -D
    1343 root       988 S    eapd
    1349 root      1168 S    nas
    1518 root      3228 S N  smbd -D
    1972 root       936 S    miniupnpd -f /etc/upnp/config
    1974 root      2728 S    httpd
    1979 root      1576 S    udhcpc -i vlan2 -b -s dhcpc-event -H Tomato -m
    2254 nobody     604 S    /tmp/mnt/BKUP/adblock/pixelserv 10.0.1.254
    2310 nobody    2660 S    dnsmasq -c 1500 --log-async
    2760 root      3508 S N  smbd -D
    4484 root      3512 S N  smbd -D
    4868 root      1140 S    dropbear -p 22 -p 2222 -s -a
    4869 root      1576 S    -sh
    4992 root      1568 R    ps
    root@Tomato:/tmp/home/root# 
    From the above, I just see adblock (PID 2254) and syslog (PID 340) that I would need to unload, is that correct

    ? Also I can see (I think) how to do it with option 2, but I dont fully understand your option 1 as to the daemon that's calling adblock and syslog.
     
  5. koitsu

    koitsu Network Guru Member

    ls -l /var/run and see what's there. I know for a fact syslogd makes a pidfile, but no idea if adblock does (and if it doesn't, it really should). Then to kill the daemon off, you simply do:

    Code:
    kill `cat /var/run/syslogd.pid`
    
    If there is no pidfile (shameful), you can resort to using pidof which may not be as accurate depending on circumstances (multiple processes with the same name/matching the same thing, etc.), ex:

    Code:
    kill `pidof adblock`
    
    As for option #1: use of a whatever.autostop file will allow you to terminate daemons, cleanly shut down things (swapoff, etc.) before the rc "system" on TomatoUSB unmounts the filesystem. This would be done if you were to unmount it using the GUI, or through some rc shell command (I would have to look up what it is) -- it will not happen if you simply do unmount /tmp/mnt/BKUP or whatever (the rc "system", not the Linux kernel, is what runs the *.autorun and *.autostop scripts in the root of a filesystem).

    Does this answer your question? If not, can you maybe revamp/re-explain what it is you're trying to do? As I understand it all you're trying to do is kill off daemons / shut down programs before a filesystem gets unmounted, in which case whatever.autostop will work for you, as long as you're unmounting the filesystem through some Tomato methodology (the GUI, etc.).
     
  6. Sean Rhodes

    Sean Rhodes Networkin' Nut Member

    Basically I have an issue where /opt doesn't always bind, and when it does I can't see that partition in windows (via ext2fs driver), but I see all the other ext2 partitions. I tried to umount (from the gui) to run e2fsck, but found I couldn't because of my running processes.

    From that point, I wanted to add a script in the "run before unmounting" section, but I wanted it to be generic so it could automatically close the pid's and unmount. I thought the autostop would be a better way to go, since it would do it automatically, but also it could be called directly from the gui, killing 2 birds with one stone so to speak.
     
  7. koitsu

    koitsu Network Guru Member

    Yeah, the autostop script is likely the best way to go, as long as you're unmounting the filesystem via some "Tomato-centric" way (GUI, etc.). Stopping the daemons in advance of filesystem unmounting is definitely the 100% correct thing to do. So you're doing the right thing by solving it that way (vs. using umount -f -- please don't do that).

    Personally I'd be more concerned with why your /opt bind doesn't always work. I've never seen that myself. :\ If you need me to post my automount script that handles /opt binding creation automatically I can paste it (it's not long, commented, and won't ever end up with multiple bind mounts in place (naughty Linux shouldn't allow that anyway but it does)).
     
  8. Sean Rhodes

    Sean Rhodes Networkin' Nut Member

    Thanks Koitsu,

    I have this in my init page:
    Code:
    echo "#device Mountpoint FStype Options Dump Pass#" >> /etc/fstab
    echo "LABEL=swap none swap sw 0 0" >> /etc/fstab
    echo "LABEL=optware /opt ext2 rw,nodev,noatime 1 1" >> /etc/fstab
    
    if ! grep -q -s "/opt" /proc/mounts; then
      mount -o bind /mnt/optware /opt
    fi
    
    and I also have a mount.autorun script in my /opt directory:
    Code:
    #!/bin/sh
    if /bin/grep -q /opt /proc/mounts
    then
            /bin/umount /opt
    
            if [ $? -ne 0 ]; then
                    echo "umount failed, script not continuing"
                    exit 1
            fi
    fi
    
    /bin/mount -o bindable /tmp/mnt/optware /opt
    That I got from one of your previous posts.

    occasionally though, when I ssh to my router and ls -al on the /opt directory it is empty, so I have to perform a bind mount and then its fine, except windows no longer sees , or can connect to the optware partition, but it sees all the other ext2 partitions fine.

    btw, its actually entware I'm using (I guess I should really change the mount point to ent)
     
  9. koitsu

    koitsu Network Guru Member

    Part of your Init effectively conflicts with your mount.autorun script. I'm not sure which would actually get run first, however.

    Basically, remove the if/mount/fi stuff from Init and your shouldn't have problems. I've never had any issues, ever, with the mount.autorun methodology I wrote, and I've rebooted my router many times, and across models (RT-N16 and RT-N66U both). You should always end up with something that looks like this:

    Code:
    root@gw:/tmp/home/root# df -k
    Filesystem           1K-blocks      Used Available Use% Mounted on
    /dev/root                 6528      6528         0 100% /
    tmpfs                   127976       176    127800   0% /tmp
    devfs                   127976         0    127976   0% /dev
    /dev/sda1             15599232    181624  14625204   1% /tmp/mnt/usbflash
    /dev/sda1             15599232    181624  14625204   1% /opt
    
    Where /tmp/mnt/usbflash would be /tmp/mnt/optware on your setup, of course.

    If you want my full scripts, here they are, untouched/unedited.

    mount.autorun:

    Code:
    #!/bin/sh
    #
    # automount script for CIFS/SMB or USB flash drives
    #
    # Details about automount scripts:
    # http://www.linksysinfo.org/index.php?threads/status-logs-dont-update-correctly.69614/#post-240957
    #
    # CIFS/SMB:
    #
    # When /cifs1 is mounted by TomatoUSB, this script will get run
    # automatically.  The reason we need this script rather than use
    # the "Execute When Mounted" features is that clicking "Save"
    # under Basic -> Network results in the "Executed When Mounted"
    # command being run mindlessly -- and we end up with two /opt
    # bindable mounts on the system simultaneously.
    #
    # USB flash drives:
    #
    # Same situation, but the drive will be auto-mounted under
    # /tmp/mnt/{drivelabel}.
    # The drivelabel is generated during mkfs.ext3:
    # http://www.linksysinfo.org/index.php?threads/creating-ext3-swap-partitions-on-tomato.48655/
    #
    # To format a drive:
    #
    # mkfs.ext3 -L usbflash /dev/sda1
    # {refresh/save in TomatoUSB GUI}
    # tune2fs -c 0 /dev/sda1
    # {manually unmount/remount in TomatoUSB GUI}
    #
    
    if /bin/grep -q /opt /proc/mounts
    then
            /bin/umount /opt
    
            if [ $? -ne 0 ]; then
                    echo "umount failed, script not continuing"
                    exit 1
            fi
    fi
    
    /bin/mount -o bindable /tmp/mnt/usbflash /opt
    
    #
    # Launch fakeidentd, which is our auth/identd server
    #
    if [ -x /opt/sbin/fakeidentd ]
    then
            kill `pidof fakeidentd` 2>/dev/null
            /opt/sbin/fakeidentd ident
    fi
    
    unmount.autostop:

    Code:
    #!/bin/sh
    #
    # autostop script for CIFS/SMB or USB flash drives
    #
    # Details about autostop scripts:
    # http://www.linksysinfo.org/index.php?threads/help-entware-optware-safe-shutdown.70071/#post-246450
    
    #
    # Stop fakeidentd
    #
    kill `pidof fakeidentd` 2>/dev/null
    
    And if you're wondering why I have a kill `pidof ...` inside the mount script: it's because some of the TomatoUSB GUI features, particularly when clicking Save in some areas, cause the filesystem to be unmounted then remounted, and I didn't want the possibility of fakeidentd being run twice (the 2nd run would ideally would fail to bind to TCP port 113 + probably exit, but I'm not taking any chances).

    I don't use swap, as you can tell.

    P.S. -- I'm not entirely sure what the point of populating /etc/fstab is. Part of me wonders if that's somehow confusing some particular libc or syscall at some random point. {Edit: Removed stuff about Optware -- missed your last paragraph}
     
    Last edited: Jun 11, 2014
  10. Sean Rhodes

    Sean Rhodes Networkin' Nut Member

    Hi Koitsu, I want to follow-on on this thread, since my question is a follow-on due to the addition of extra lines in the above autorun script to run some wanup scripts.

    Basically I'm finding that my firewall script in the gui does not always run correctly since some mac addresses can still connect and also the vpn client blocks all when the client is running (and blocks remote access to my router, but that's another story) which means it hasn't loaded correctly since its supposed to allow all except one.

    I'm thinking either there is a race issue, or a bug in the gui, since sometimes when I open the gui, parts of the scripts are not there.

    I think my one issue in my script attempt below, is where I'm calling up the wanup scripts in the mount.autorun script.

    Code:
    #!/bin/sh
    
    if /bin/grep -q /opt /proc/mounts
    then
            /bin/umount /opt
           
    if [ -f /var/notice/wan ]; then
       for s in /opt/etc/config/fire.wanup; do $s; done
       for s in /opt/etc/config/misc.wanup; do $s; done
       for s in /opt/etc/config/vpn.wanup; do $s; done
       exit 1
    fi
       if [ $? -ne 0 ]; then
          echo "umount failed, script not continuing"
          exit 2
       fi
    fi
    
    /bin/mount -o bindable /tmp/mnt/optware /opt
    
    if [ -x /opt/sbin/fakeidentd ]
    then
            kill `pidof fakeidentd` 2>/dev/null
            /opt/sbin/fakeidentd ident
    fi
    
    It looks like there is no ideal place to call the wanup scripts due to the umount and obviously after the exit is pointless since the wanup scripts would never get called.

    I'm thinking another autorun script, or some script called from mount.autorun, but with a delay added.

    Can you offer any advice
     
  11. koitsu

    koitsu Network Guru Member

    That script is botched. You added this:

    Code:
    if [ -f /var/notice/wan ]; then
       for s in /opt/etc/config/fire.wanup; do $s; done
       for s in /opt/etc/config/misc.wanup; do $s; done
       for s in /opt/etc/config/vpn.wanup; do $s; done
       exit 1
    fi
    
    ...in the middle of an area where you shouldn't have. The if [ $? -ne 0 ] ... fi part is intended to examine the exit code of the /bin/umount attempt. By doing what you did you basically break this functionality.

    Regarding what you DID add, I'm not sure where to start, so I'll just go off the cuff:

    First, the for s ... done stuff makes absolutely no sense. What that does is iterate over an array of values (in this case, there is only one value: the filename of the /opt/etc/config/{whatever}.wanup) and proceed to "execute" that value. So basically the loop part serves no purpose. You could have accomplished the exact same by doing:

    Code:
    if [ -f /var/notice/wan ]; then
      . /opt/etc/config/fire.wanup
      . /opt/etc/config/misc.wanup
      . /opt/etc/config/vpn.wanup
    fi
    
    The "dot" at the start causes the interpreter to run the script in question. All of this operates off the blind assumption that those files exist, by the way -- if they don't, the script will just keep going on as if nothing happened, and you won't get any indication of the failure (that's just how this works).

    Next: I do not know why you added exit 1 there, nor why you changed the exit code in the if [ $? -ne 0 ] ... fi area to exit 2. I think you're just screwing around? I don't know what it is you're attempting here. It makes no sense, especially tinkering with exit code values.

    Next: WHERE you added this code is completely wrong! /opt isn't even mounted yet at that phase! So gee, no wonder the scripts didn't run? :p /opt isn't available until after the /bin/mount line that creates a bindable between /tmp/mnt/optware and /opt. What this does is essentially make a "filesystem symlink" (hard to explain here, rather not go into it) where /opt is an actual filesystem that points to the same thing as /tmp/mnt/optware. I can explain the nature of all of that if you want me to.

    AFTER that point, you should have a usable /opt filesystem to run things from. PRIOR to that line you won't.

    Finally: you blindly running /opt/etc/config/*.wanup scripts during the Init script is not going to work regardless. You have to understand that the WAN Up part of Admin/Scripts actually happens when the actual Internet WAN link comes up -- there is a ton of C code/stuff that is going on under the hood prior to that script running. The Init part of Admin/Scripts runs upon boot, usually "as soon as possible", but there's ZERO guarantee there's a working Internet link at that point (in fact in most cases there isn't).

    You need to keep things that "use the Internet link" (like your VPN, etc.) in the WAN Up area (but be aware that can get called multiple times when the router is running, i.e. the Internet connection goes down, your get a new DHCP address, etc. -- so don't just throw commands in there blindly without testing something to see if there's already an existing entry for things (iptables, etc.) in place! Otherwise you end up with a situation where, for example, you keep shoving more and more iptables rules into your firewall chain and make a mess of your router).

    This is a lot easier to explain in person or via voice than it is via text. The bottom line is that what you added is incorrect in numerous regards, and it's no surprise it doesn't work.

    Writing scripts/stuff for Tomato is tedious and very "sensitive". People who think they can just blindly throw stuff into the GUI or into a script somewhere and "it magically works" are mistaken. There are a lot of caveats and things to consider along the way, lots of precautions to take. Embedded environments, especially routers, require a lot more caution.

    P.S. -- None of what we're discussing here right now has to do with the thread Subject. We're not even discussing shutdown at this point. So this thread has gone completely off-topic. :p
     
  12. Sean Rhodes

    Sean Rhodes Networkin' Nut Member

    Wow,

    I guess I was way off base on this one! I was assuming I could include things in the same script, thats why I added it to this. I forgot that I initially started this for the shutdown part.

    I will start another thread,

    Thanks Koitsu
     

Share This Page