{"id":2493,"date":"2018-01-10T15:52:20","date_gmt":"2018-01-10T12:52:20","guid":{"rendered":"https:\/\/www.howtoforge.com\/tutorial\/trigger-commands-on-file-or-directory-changes-with-incron\/"},"modified":"2018-01-10T15:52:20","modified_gmt":"2018-01-10T12:52:20","slug":"how-to-trigger-commands-on-file-directory-changes-with-incron-on-debian","status":"publish","type":"post","link":"https:\/\/afaghhosting.net\/blog\/how-to-trigger-commands-on-file-directory-changes-with-incron-on-debian\/","title":{"rendered":"How to trigger commands on File\/Directory changes with Incron on Debian"},"content":{"rendered":"<p>This guide shows how you can install and use <strong>incron<\/strong> on a Debian 9 (Stretch)\u00a0system. Incron is similar to cron, but instead of running commands based on time, it can trigger commands when file or directory events occur (e.g. a file modification, changes of permissions, etc.).<\/p>\n<h2 id=\"-prerequisites\">1 Prerequisites<\/h2>\n<ul>\n<li>System administrator permissions (root login). All commands in this tutorial should be run as root user on the shell.<\/li>\n<li>I will use the editor &#8220;nano&#8221; to edit files. You may replace nano with an editor of your choice or install nano with &#8220;apt-get install nano&#8221; if it is not installed on your server.<\/li>\n<\/ul>\n<h2 id=\"nbspinstalling-incron\">2\u00a0Installing Incron<\/h2>\n<p>Incron is available in the Debian\u00a0repository, so we install incron\u00a0with the following apt command:<\/p>\n<p class=\"command\">apt-get install incron<\/p>\n<p>The installation process should be similar to the one in this screenshot.<\/p>\n<p><a class=\"fancybox\" id=\"img-incron-debian-9\" href=\"https:\/\/www.howtoforge.com\/images\/trigger-commands-on-file-or-directory-changes-with-incron-on-debian-8\/big\/incron-debian-9.png\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/afaghhosting.net\/blog\/wp-content\/uploads\/2018\/01\/how-to-trigger-commands-on-file-directory-changes-with-incron-on-debian.png\" alt=\"Installing Incron on Debian 9\" width=\"550\" height=\"346\" title=\"\"><\/a><\/p>\n<h2 id=\"nbspusing-incron\">3\u00a0Using Incron<\/h2>\n<p>Incron usage is very much like cron usage. You have the <span class=\"system\">incrontab<\/span> command that let&#8217;s you list (<span class=\"system\">-l<\/span>), edit (<span class=\"system\">-e<\/span>), and remove (<span class=\"system\">-r<\/span>) incrontab entries.<\/p>\n<p>To learn more about it, see:<\/p>\n<p class=\"command\">man incrontab<\/p>\n<p>There you also find the following section:<\/p>\n<p><em>If \/etc\/incron.allow exists only users listed here may use incron. Otherwise if \/etc\/incron.deny exists only users NOT listed here may use incron. If none of these files exists everyone is allowed to use incron. (Important note: This behavior is insecure and will be probably changed to be compatible with the style used by ISC Cron.) Location of these files can be changed in the configuration.<\/em><\/p>\n<p>This means if we want to use incrontab as root, we must either delete <span class=\"system\">\/etc\/incron.allow<\/span> (which is unsafe because then every system user can use incrontab)&#8230;<\/p>\n<p class=\"command\">rm -f \/etc\/incron.allow<\/p>\n<p>&#8230; or add root to that file (recommended). Open the \/etc\/incron.allow file with nano:<\/p>\n<p class=\"command\">nano\u00a0\/etc\/incron.allow<\/p>\n<p>And add the following line. Then save the file.<\/p>\n<pre>root<\/pre>\n<p>Before you do this, you will get error messages like this one when trying to use incrontab:<\/p>\n<p class=\"system\">server1:~# incrontab -l<br \/>user &#8216;root&#8217; is not allowed to use incron<\/p>\n<p>Afterwards it works:<\/p>\n<p class=\"system\">server1:~# incrontab -l<br \/>no table for root<\/p>\n<p>We can use the command:<\/p>\n<p class=\"command\">incrontab -e<\/p>\n<p>To create incron jobs. Before we do this, we take a look at the incron man page:<\/p>\n<p class=\"command\">man 5 incrontab<\/p>\n<p>The man page\u00a0explains the format of the crontabs. Basically, the format is as follows&#8230;<\/p>\n<p class=\"system\">&lt;path&gt; &lt;mask&gt; &lt;command&gt;<\/p>\n<p>&#8230;where <span class=\"system\">&lt;path&gt;<\/span> can be a directory (meaning the directory and\/or the files directly in that directory (not files in subdirectories of that directory!) are watched) or a file.<\/p>\n<p><span class=\"system\">&lt;mask&gt;<\/span> can be one of the following:<\/p>\n<p class=\"system\">IN_ACCESS\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0File\u00a0was\u00a0accessed\u00a0(read)\u00a0(*)<br \/>IN_ATTRIB\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Metadata\u00a0changed\u00a0(permissions,\u00a0timestamps,\u00a0extended\u00a0attributes,\u00a0etc.)\u00a0(*)<br \/>IN_CLOSE_WRITE\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0File\u00a0opened\u00a0for\u00a0writing\u00a0was\u00a0closed\u00a0(*)<br \/>IN_CLOSE_NOWRITE\u00a0\u00a0\u00a0\u00a0File\u00a0not\u00a0opened\u00a0for\u00a0writing\u00a0was\u00a0closed\u00a0(*)<br \/>IN_CREATE\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0File\/directory\u00a0created\u00a0in\u00a0watched\u00a0directory\u00a0(*)<br \/>IN_DELETE\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0File\/directory\u00a0deleted\u00a0from\u00a0watched\u00a0directory\u00a0(*)<br \/>IN_DELETE_SELF\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Watched\u00a0file\/directory\u00a0was\u00a0itself\u00a0deleted<br \/>IN_MODIFY\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0File\u00a0was\u00a0modified\u00a0(*)<br \/>IN_MOVE_SELF\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Watched\u00a0file\/directory\u00a0was\u00a0itself\u00a0moved<br \/>IN_MOVED_FROM\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0File\u00a0moved\u00a0out\u00a0of\u00a0watched\u00a0directory\u00a0(*)<br \/>IN_MOVED_TO\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0File\u00a0moved\u00a0into\u00a0watched\u00a0directory\u00a0(*)<br \/>IN_OPEN\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0File\u00a0was\u00a0opened\u00a0(*)<\/p>\n<p>When monitoring a directory, the events marked with an asterisk (*) above can occur for files in the directory, in which case the name field in the<br \/>returned event data identifies the name of the file within the directory.<\/p>\n<p>The <span class=\"system\">IN_ALL_EVENTS<\/span> symbol is defined as a bit mask of all of the above events. Two additional convenience symbols are <span class=\"system\">IN_MOVE<\/span>, which is a combination of <span class=\"system\">IN_MOVED_FROM<\/span> and <span class=\"system\">IN_MOVED_TO<\/span>, and <span class=\"system\">IN_CLOSE<\/span> which combines <span class=\"system\">IN_CLOSE_WRITE<\/span> and <span class=\"system\">IN_CLOSE_NOWRITE<\/span>.<\/p>\n<p>The following further symbols can be specified in the mask:<\/p>\n<p class=\"system\">IN_DONT_FOLLOW\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Don&#8217;t\u00a0dereference\u00a0pathname\u00a0if\u00a0it\u00a0is\u00a0a\u00a0symbolic\u00a0link<br \/>IN_ONESHOT\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Monitor\u00a0pathname\u00a0for\u00a0only\u00a0one\u00a0event<br \/>IN_ONLYDIR\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Only\u00a0watch\u00a0pathname\u00a0if\u00a0it\u00a0is\u00a0a\u00a0directory<\/p>\n<p>Additionally, there is a symbol which doesn&#8217;t appear in the inotify symbol set. It is <span class=\"system\">IN_NO_LOOP<\/span>. This symbol disables monitoring events until the current one is completely handled (until its child process exits).<\/p>\n<p><span class=\"system\">&lt;command&gt;<\/span> is the command that should be run when the event occurs. The following wildcards may be used inside the command specification:<\/p>\n<p class=\"system\">$$\u00a0\u00a0\u00a0dollar\u00a0sign<br \/><a href=\"https:\/\/www.howtoforge.com\/cdn-cgi\/l\/email-protection\" class=\"__cf_email__\" data-cfemail=\"6e4a2e\" target=\"_blank\" rel=\"noopener\">[email\u00a0protected]<\/a>\u00a0\u00a0\u00a0watched\u00a0filesystem\u00a0path\u00a0(see\u00a0above)<br \/>$#\u00a0\u00a0\u00a0event-related\u00a0file\u00a0name<br \/>$%\u00a0\u00a0\u00a0event\u00a0flags\u00a0(textually)<br \/>$&amp;\u00a0\u00a0\u00a0event\u00a0flags\u00a0(numerically)<\/p>\n<p>If you watch a directory, then <span class=\"system\"><a href=\"https:\/\/www.howtoforge.com\/cdn-cgi\/l\/email-protection\" class=\"__cf_email__\" data-cfemail=\"c9ed89\" target=\"_blank\" rel=\"noopener\">[email\u00a0protected]<\/a><\/span> holds the directory path and <span class=\"system\">$#<\/span> the file that triggered the event. If you watch a file, then <span class=\"system\"><a href=\"https:\/\/www.howtoforge.com\/cdn-cgi\/l\/email-protection\" class=\"__cf_email__\" data-cfemail=\"456105\" target=\"_blank\" rel=\"noopener\">[email\u00a0protected]<\/a><\/span> holds the complete path to the file and <span class=\"system\">$#<\/span> is empty.<\/p>\n<p>If you need the wildcards but are not sure what they translate to, you can create an incron job like this. Open the incron incrontab:<\/p>\n<p class=\"command\"><span>incrontab -e<\/span><\/p>\n<p><span>and add the following line:<\/span><\/p>\n<pre>\/tmp\/ IN_MODIFY echo \"$$ <a href=\"https:\/\/www.howtoforge.com\/cdn-cgi\/l\/email-protection\" class=\"__cf_email__\" data-cfemail=\"4a6e0a\" target=\"_blank\" rel=\"noopener\">[email\u00a0protected]<\/a> $# $% $&amp;\"<\/pre>\n<p>Then you create or modify a file in the <span class=\"system\">\/tmp<\/span> directory and take a look at<span class=\"system\"> \/var\/log\/syslog<\/span> &#8211; this log shows when an incron job was triggered, if it succeeded or if there were errors, and what the actual command was that it executed (i.e., the wildcards are replaced with their real values).<\/p>\n<p class=\"command\">tail \/var\/log\/syslog<\/p>\n<p class=\"system\">&#8230;<br \/>Jan 10 13:52:35 server1 incrond[1012]: (root) CMD (echo &#8220;$ \/tmp .hello.txt.swp IN_MODIFY 2&#8221;)<br \/><span>Jan 10 13:52<\/span>:36 server1 incrond[<span>1012<\/span>]: (root) CMD (echo &#8220;$ \/tmp .hello.txt.swp IN_MODIFY 2&#8221;)<br \/><span>Jan 10 13:52<\/span>:39 server1 incrond[<span>1012<\/span>]: (root) CMD (echo &#8220;$ \/tmp hello.txt IN_MODIFY 2&#8221;)<br \/><span>Jan 10 13:52<\/span>:39 server1 incrond[<span>1012<\/span>]: (root) CMD (echo &#8220;$ \/tmp .hello.txt.swp IN_MODIFY 2&#8221;)<\/p>\n<p>In this example I&#8217;ve edited the file <span class=\"system\">\/tmp\/hello.txt<\/span>; as you see <span class=\"system\"><a href=\"https:\/\/www.howtoforge.com\/cdn-cgi\/l\/email-protection\" class=\"__cf_email__\" data-cfemail=\"270367\" target=\"_blank\" rel=\"noopener\">[email\u00a0protected]<\/a><\/span> translates to <span class=\"system\">\/tmp<\/span>, <span class=\"system\">$#<\/span> to <span face=\"Courier New, Courier, mono\"><i>hello.txt<\/i><\/span>, <span class=\"system\">$%<\/span> to <span class=\"system\">IN_CREATE<\/span>, and <span class=\"system\">$&amp;<\/span> to <span class=\"system\">256<\/span>. I used an editor that created a temporary .txt.swp file which results in the additional lines in syslog.<\/p>\n<p>Now enough theory. Let&#8217;s create our first incron jobs. I&#8217;d like to monitor the file <span class=\"system\">\/etc\/apache2\/apache2.conf<\/span> and the directory <span class=\"system\">\/etc\/apache2\/vhosts\/<\/span>, and whenever there are changes, I want incron to restart Apache. This is how we do it:<\/p>\n<p class=\"command\">incrontab -e<\/p>\n<pre>\/etc\/apache2\/apache2.conf IN_MODIFY \/usr\/sbin\/service apache2 restart&#13;\n\/etc\/apache2\/sites-available\/ IN_MODIFY \/usr\/sbin\/service apache2 restart<\/pre>\n<p>That&#8217;s it. For test purposes, you can modify your Apache configuration and take a look at <span class=\"system\">\/var\/log\/syslog<\/span>, and you should see that incron restarts Apache.<\/p>\n<p><strong>NOTE<\/strong>: Do not do any action from within an incron job in a directory that you monitor to avoid loops. <strong>Example:<\/strong>\u00a0When you monitor the \/tmp directory for changes and each change triggers a script that writes a log file in \/tmp, this will cause a loop and might bring your system to high load or even crash it.<\/p>\n<p>To list all defined incron jobs, you can run:<\/p>\n<p class=\"command\">incrontab -l<\/p>\n<p class=\"system\">server1:~# incrontab -l<br \/>\/etc\/apache2\/apache2.conf IN_MODIFY \/usr\/sbin\/service apache2 restart<br \/>\/etc\/apache2\/vhosts\/ IN_MODIFY \/usr\/sbin\/service apache2 restart<\/p>\n<p>To delete all incron jobs of the current user, run:<\/p>\n<p class=\"command\">incrontab -r<\/p>\n<p class=\"system\">server1:~# incrontab -r<br \/>removing table for user &#8216;root&#8217;<br \/>table for user &#8216;root&#8217; successfully removed<\/p>\n<h2 id=\"nbsplinks\">4\u00a0Links<\/h2>\n<div>\n<p><b>Share this page:<\/b><\/p>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>This guide shows how you can install and use incron on a Debian 9 (Stretch)\u00a0system. Incron is similar to cron, but instead of running commands based on time, it can trigger commands when file or directory events occur (e.g. a file modification, changes of permissions, etc.). 1 Prerequisites System administrator permissions (root login). All commands &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[36],"tags":[],"class_list":["post-2493","post","type-post","status-publish","format-standard","hentry","category-36"],"_links":{"self":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/2493","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/comments?post=2493"}],"version-history":[{"count":0,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/2493\/revisions"}],"wp:attachment":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/media?parent=2493"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/categories?post=2493"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/tags?post=2493"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}