{"id":55,"date":"2011-03-01T13:53:47","date_gmt":"2011-03-01T12:53:47","guid":{"rendered":"http:\/\/www.blaess.fr\/christophe\/blog\/?page_id=55"},"modified":"2011-03-01T13:53:47","modified_gmt":"2011-03-01T12:53:47","slug":"secure-your-rm-command","status":"publish","type":"page","link":"https:\/\/www.blaess.fr\/christophe\/articles\/secure-your-rm-command\/","title":{"rendered":"Secure your rm command"},"content":{"rendered":"<p>May 1996<\/p>\n<p>&nbsp;<\/p>\n<p style=\"text-align: justify;\">This is a shell script for Bash, called &lsquo;rm_secure&rsquo;. I use it as frontal for the rm command. It stores the deleted files in an archive in the user&rsquo;s directory. A command-line option allows the user to view the content of this archive, and another option permits the restoration of the deleted files.<\/p>\n<p>For example\u00a0:<\/p>\n<pre style=\"padding-left: 30px;\">$ <strong>ls -l<\/strong>\n-rw-r--r-- 1 ccb users 22 May 26 10:33 important_file\n-rw-r--r-- 1 ccb users 23 May 26 10:34 not_important\n$ <strong>rm *<\/strong> (<em>OOPS!<\/em>)\n$ <strong>ls -l<\/strong>\n$ <strong>rm --viewtrash<\/strong>\n-rw-r--r-- 1 ccb users 22 May 26 10:35 1996 important_file\n-rw-r--r-- 1 ccb users 23 May 26 10:35 1996 not_important\n$ <strong>rm --restore important_file<\/strong>\n$ <strong>ls -l<\/strong>\n-rw-r--r-- 1 ccb users 22 May 26 10:35 important_file\n$ <strong>rm --viewtrash<\/strong>\n-rw-r--r-- 1 ccb users 23 May 26 10:35 1996 not_important\n$ <strong>rm --emptytrash<\/strong>\n$ <strong>rm --viewtrash<\/strong>\n$<\/pre>\n<p style=\"text-align: justify;\">Okay, it slows down a few the rm command. But it may also save hours of work lost due to a keystroke error\u2026<\/p>\n<p style=\"text-align: justify;\">There is the script &lsquo;rm_secure&rsquo;\u00a0:<\/p>\n<pre style=\"padding-left: 30px;\">#!\/bin\/bash\n\n# Configuration\n# the real 'rm' command\nbin_rm=\/bin\/rm\n# where archiving the files\nArchive=~\/.rm_saved.tar\n# you may prefer something like\u00a0:\n# Archive=\/var\/trash\/$USER\/saved_file.tar\n# (with write access permission on the directory)\n\n# global variables for the options\nOpt_recursive=0\nOpt_no_secure=0\nOpt_restore=0\nOpt_rm=\"\"\n\n# function for archiving a file or a directory\nsave_file() {\n  if [ $Opt_no_secure -ne 1 ]\u00a0; then\n  # set date\/time of deletion\n  touch \"$1\" &gt; \/dev\/null 2&gt;&amp;1\n    if [ -f $Archive ]\u00a0; then\n      tar --delete -f \"$Archive\" \"$1\" &gt; \/dev\/null 2&gt;&amp;1\n      tar -rf \"$Archive\" \"$1\" &gt; \/dev\/null 2&gt;&amp;1\n    else\n      tar -cf \"$Archive\" \"$1\" &gt; \/dev\/null 2&gt;&amp;1\n      # r\/w access only for the user\n      chmod 600 \"$Archive\"\n    fi\n  fi\n}\n\n# function for restoring file or directory\nrestore_file () {\n  if [ -f $Archive ]\u00a0; then\n    tar -xf \"$Archive\" \"$1\" &gt; \/dev\/null 2&gt;&amp;1\n    tar --delete -f \"$Archive\" \"$1\" &gt; \/dev\/null 2&gt;&amp;1\n  fi\n}\n\n# reading the command-line args\nwhile getopts \"dfirRvns-:\" opt\u00a0; do\n  case $opt in\n    d ) Opt_rm=\"$Opt_rm -d\"\u00a0;;\n    f ) Opt_rm=\"$Opt_rm -f\"\u00a0;;\n    i ) Opt_rm=\"$Opt_rm -i\"\u00a0;;\n    r | R ) Opt_recursive=1\n            Opt_rm=\"$Opt_rm -r\"\u00a0;;\n    v ) Opt_rm=\"$Opt_rm -v\"\u00a0;;\n    n ) Opt_no_secure=1\u00a0;;\n    s ) Option_restore=1\u00a0;;\n    - ) case $OPTARG in\n      directory ) Opt_rm=\"$Opt_rm -d\"\u00a0;;\n      force ) Opt_rm=\"$Opt_rm -f\"\u00a0;;\n      interactive ) Opt_rm=\"$Opt_rm -i\"\u00a0;;\n      recursive ) Opt_recursive=1\n                  Opt_rm=\"$Opt_rm -r\"\u00a0;;\n     help ) $bin_rm --help\n             echo \"(rm_secure)\"\n             echo \" -n, --nosecure delete without backup\"\n             echo \" --viewtrash list the saved files\"\n             echo \" --emptytrash erase the saved files\"\n             echo \" -s, --restore restore the specified files\"\n             exit 0\u00a0;;\n      version ) $bin_rm --version\n                 echo \"(rm_secure 1.0)\"\n                 exit 0\u00a0;;\n      verbose ) Opt_rm=\"$Opt_rm -v\"\u00a0;;\n      viewtrash ) if [ -f $Archive.gz ]\u00a0; then\n                    tar -tvzf $Archive.gz\n                  fi\n                  exit 0\u00a0;;\n      nosecure ) Opt_no_secure=1\u00a0;;\n      emptytrash ) if [ -f $Archive.gz ]\u00a0; then\n                     $bin_rm $Archive.gz\n                   fi\n                   exit 0\u00a0;;\n      restore ) Opt_restore=1\u00a0;;\n      * ) \u00a0;;\n    esac\u00a0;;\n    ? ) \u00a0;;\n  esac\ndone\n\nshift $(($OPTIND - 1))\ngunzip $Archive.gz &gt;; \/dev\/null 2&gt;&amp;1\n\n# restoration ?\nif [ $Opt_restore -ne 0 ]\u00a0; then\n  while [ -n \"$1\" ]\u00a0; do\n    restore_file \"$1\"\n    shift\n  done\n  exit 0\nelse\n  while [ -n \"$1\" ]\u00a0; do\n    if [ -d \"$1\" ]\u00a0; then\n      # the directories are archived only with\n      # the -r option\n      if [ $Opt_recursive -ne 0 ]\u00a0; then\n        save_file \"$1\"\n      fi\n      $bin_rm $Opt_rm $1\n    elif [ -e \"$1\" ]\u00a0; then\n      # existing file\n      save_file \"$1\"\n      $bin_rm $Opt_rm $1\n    else\n      # let 'rm' give his error message\n      $bin_rm $1\n    fi\n  shift\ndone\nfi\n\nnice gzip $Archive &gt; \/dev\/null 2&gt;&amp;1 &amp;\n# -- end of script --<\/pre>\n<p>Place it in \/usr\/bin or \/usr\/local\/bin then insert a ligne\u00a0:<\/p>\n<pre style=\"padding-left: 30px;\">alias rm='\/usr\/local\/bin\/rm_secure'<\/pre>\n<p>in \/etc\/profile, so this script will be called by Bash in the place of the true rm command.<\/p>\n<p style=\"text-align: justify;\">You can use the &lsquo;&#8211;nosecure&rsquo; or &lsquo;-n&rsquo; option to delete a file without archiving it. This is useful when you decide to erase huge amount of files in recursive directories (for example a package you have tested but find uninteresting).<\/p>\n<p>I use a cron job to deleted the archived files every day (running as root job).<\/p>\n<pre style=\"padding-left: 30px;\"># <strong>crontab -l<\/strong>\n[ \u2026]\n00 04 * * * \/usr\/local\/bin\/empty_trash\n#<\/pre>\n<p>Here is the &#8217;empty_trash&rsquo; script\u00a0:<\/p>\n<pre style=\"padding-left: 30px;\">#! \/bin\/bash\n  for user in \/home\/*\u00a0; do\n    \/bin\/rm $user\/.rm_saved.tar.gz\n  done\n  \/bin\/rm \/root\/.rm_saved.tar.gz\n# -- end of script --<\/pre>\n<p>Maybe you can prefer something like\u00a0:<\/p>\n<pre style=\"padding-left: 30px;\">trap '\/bin\/rm ~\/.rm_saved.tar.gz EXIT<\/pre>\n<p>in \/etc\/profile, which erase the archive each time the user exits the shell. (I&rsquo;ve not fully tested this)<\/p>\n<p>Obviously this tips doesn&rsquo;t secure the deletion of files or directories by a file-manager, but I find it quite usefull, especially when doing administrative jobs as root (&lsquo;rm tmp\/ *&rsquo; in place of &lsquo;rm tmp\/*&rsquo; \u2026)<\/p>","protected":false},"excerpt":{"rendered":"<p>May 1996 &nbsp; This is a shell script for Bash, called &lsquo;rm_secure&rsquo;. I use it as frontal for the rm command. It stores the deleted files in an archive in the user&rsquo;s directory. A command-line option allows the user to view the content of this archive, and another option permits the restoration of the deleted [&hellip;]<\/p>","protected":false},"author":1,"featured_media":0,"parent":20,"menu_order":5,"comment_status":"open","ping_status":"open","template":"","meta":{"footnotes":""},"class_list":["post-55","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/pages\/55","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/comments?post=55"}],"version-history":[{"count":0,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/pages\/55\/revisions"}],"up":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/pages\/20"}],"wp:attachment":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/media?parent=55"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}