Hello community,

here is the log from the commit of package inotify-tools for openSUSE:Factory 
checked in at 2020-12-21 10:24:25
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/inotify-tools (Old)
 and      /work/SRC/openSUSE:Factory/.inotify-tools.new.5145 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "inotify-tools"

Mon Dec 21 10:24:25 2020 rev:6 rq:857150 version:3.20.11.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/inotify-tools/inotify-tools.changes      
2020-08-18 15:10:41.072031563 +0200
+++ /work/SRC/openSUSE:Factory/.inotify-tools.new.5145/inotify-tools.changes    
2020-12-21 10:27:02.388226295 +0100
@@ -1,0 +2,7 @@
+Sun Dec 20 12:56:31 UTC 2020 - Dirk Müller <[email protected]>
+
+- update to 3.20.11.0:
+  * Added --no-dereference to watch a symlink
+  * bugfixes
+
+-------------------------------------------------------------------

Old:
----
  3.20.2.2.tar.gz

New:
----
  3.20.11.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ inotify-tools.spec ++++++
--- /var/tmp/diff_new_pack.IczsHq/_old  2020-12-21 10:27:02.964226948 +0100
+++ /var/tmp/diff_new_pack.IczsHq/_new  2020-12-21 10:27:02.964226948 +0100
@@ -17,20 +17,19 @@
 
 
 Name:           inotify-tools
-Version:        3.20.2.2
+Version:        3.20.11.0
 Release:        0
 Summary:        Tools for inotify
 License:        GPL-2.0-only
 Group:          System/Monitoring
-URL:            https://github.com/rvoicilas/inotify-tools/wiki/
-Source:         
http://github.com/rvoicilas/inotify-tools/archive/%{version}.tar.gz
+URL:            https://github.com/inotify-tools/inotify-tools
+Source:         
https://github.com/inotify-tools/inotify-tools/archive/%{version}.tar.gz
 BuildRequires:  autoconf
 BuildRequires:  automake
 BuildRequires:  doxygen
 BuildRequires:  fdupes
 BuildRequires:  glibc-devel
 BuildRequires:  libtool
-BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 
 %description
 inotify is a kernel facility to watch file system changes. This
@@ -73,39 +72,34 @@
 %configure --disable-static \
     --docdir=%{_docdir}/%{name} \
     --enable-doxygen
-make %{?_smp_mflags}
+%make_build
 
 %install
-make DESTDIR=%{buildroot} install %{?_smp_mflags}
+%make_install
 %fdupes %{buildroot}/%{_docdir}
 rm %{buildroot}/%{_libdir}/libinotifytools.la
 
 %post -n libinotifytools0 -p /sbin/ldconfig
-
 %postun -n libinotifytools0 -p /sbin/ldconfig
 
 %check
-make %{?_smp_mflags} check
+%make_build check
 
 %files
-%defattr(-,root,root)
 %{_bindir}/inotifywait
 %{_bindir}/inotifywatch
-%{_mandir}/man1/inotifywait.1.gz
-%{_mandir}/man1/inotifywatch.1.gz
+%{_mandir}/man1/inotifywait.1%{?ext_man}
+%{_mandir}/man1/inotifywatch.1%{?ext_man}
 
 %files -n libinotifytools0
-%defattr(-,root,root)
 %license COPYING
 %{_libdir}/libinotifytools.so.*
 
 %files devel
-%defattr(-,root,root)
 %{_libdir}/libinotifytools.so
 %{_includedir}/inotifytools/
 
 %files doc
-%defattr(-,root,root)
 %doc %{_docdir}/%{name}
 
 %changelog

++++++ 3.20.2.2.tar.gz -> 3.20.11.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/inotify-tools-3.20.2.2/.cirrus.yml 
new/inotify-tools-3.20.11.0/.cirrus.yml
--- old/inotify-tools-3.20.2.2/.cirrus.yml      2020-02-01 13:05:18.000000000 
+0100
+++ new/inotify-tools-3.20.11.0/.cirrus.yml     2020-11-13 11:52:25.000000000 
+0100
@@ -2,8 +2,7 @@
   name: FreeBSD
   freebsd_instance:
     matrix:
-      # There isn't a stable 13.0 image yet (2019-12)
-      image_family: freebsd-13-0-snap
+      image_family: freebsd-11-3-snap
       image_family: freebsd-12-1
 
   pkginstall_script:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/inotify-tools-3.20.2.2/.github/FUNDING.yml 
new/inotify-tools-3.20.11.0/.github/FUNDING.yml
--- old/inotify-tools-3.20.2.2/.github/FUNDING.yml      1970-01-01 
01:00:00.000000000 +0100
+++ new/inotify-tools-3.20.11.0/.github/FUNDING.yml     2020-11-13 
11:52:25.000000000 +0100
@@ -0,0 +1 @@
+open_collective: inotify-tools
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/inotify-tools-3.20.2.2/.github/ISSUE_TEMPLATE/bug_report.md 
new/inotify-tools-3.20.11.0/.github/ISSUE_TEMPLATE/bug_report.md
--- old/inotify-tools-3.20.2.2/.github/ISSUE_TEMPLATE/bug_report.md     
1970-01-01 01:00:00.000000000 +0100
+++ new/inotify-tools-3.20.11.0/.github/ISSUE_TEMPLATE/bug_report.md    
2020-11-13 11:52:25.000000000 +0100
@@ -0,0 +1,38 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Desktop (please complete the following information):**
+ - OS: [e.g. iOS]
+ - Browser [e.g. chrome, safari]
+ - Version [e.g. 22]
+
+**Smartphone (please complete the following information):**
+ - Device: [e.g. iPhone6]
+ - OS: [e.g. iOS8.1]
+ - Browser [e.g. stock browser, safari]
+ - Version [e.g. 22]
+
+**Additional context**
+Add any other context about the problem here.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/inotify-tools-3.20.2.2/.github/ISSUE_TEMPLATE/feature_request.md 
new/inotify-tools-3.20.11.0/.github/ISSUE_TEMPLATE/feature_request.md
--- old/inotify-tools-3.20.2.2/.github/ISSUE_TEMPLATE/feature_request.md        
1970-01-01 01:00:00.000000000 +0100
+++ new/inotify-tools-3.20.11.0/.github/ISSUE_TEMPLATE/feature_request.md       
2020-11-13 11:52:25.000000000 +0100
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always 
frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features 
you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/inotify-tools-3.20.2.2/.travis.yml 
new/inotify-tools-3.20.11.0/.travis.yml
--- old/inotify-tools-3.20.2.2/.travis.yml      1970-01-01 01:00:00.000000000 
+0100
+++ new/inotify-tools-3.20.11.0/.travis.yml     2020-11-13 11:52:25.000000000 
+0100
@@ -0,0 +1,11 @@
+language: c
+sudo: required
+matrix:
+    include:
+        - os: linux
+          arch: arm64
+          compiler: gcc
+          dist: xenial
+script:
+ - ./build_and_test.sh
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/inotify-tools-3.20.2.2/CODE_OF_CONDUCT.md 
new/inotify-tools-3.20.11.0/CODE_OF_CONDUCT.md
--- old/inotify-tools-3.20.2.2/CODE_OF_CONDUCT.md       1970-01-01 
01:00:00.000000000 +0100
+++ new/inotify-tools-3.20.11.0/CODE_OF_CONDUCT.md      2020-11-13 
11:52:25.000000000 +0100
@@ -0,0 +1,76 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, 
body
+size, disability, ethnicity, sex characteristics, gender identity and 
expression,
+level of experience, education, socio-economic status, nationality, personal
+appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an 
appointed
+representative at an online or offline event. Representation of a project may 
be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at [email protected]. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an 
incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], 
version 1.4,
+available at 
https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see
+https://www.contributor-covenant.org/faq
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/inotify-tools-3.20.2.2/Makefile.am 
new/inotify-tools-3.20.11.0/Makefile.am
--- old/inotify-tools-3.20.2.2/Makefile.am      2020-02-01 13:05:18.000000000 
+0100
+++ new/inotify-tools-3.20.11.0/Makefile.am     2020-11-13 11:52:25.000000000 
+0100
@@ -2,6 +2,8 @@
 
 SUBDIRS = libinotifytools src man
 
+README: README.md
+
 dist-hook:
 # Automake official documentation states that dist-hook should assume files
 # are not writable.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/inotify-tools-3.20.2.2/README.md 
new/inotify-tools-3.20.11.0/README.md
--- old/inotify-tools-3.20.2.2/README.md        2020-02-01 13:05:18.000000000 
+0100
+++ new/inotify-tools-3.20.11.0/README.md       2020-11-13 11:52:25.000000000 
+0100
@@ -1,4 +1,7 @@
-![](https://github.com/inotify-tools/inotify-tools/workflows/build/badge.svg)
+[![GitHub Build 
Status](https://github.com/inotify-tools/inotify-tools/workflows/build/badge.svg)](https://github.com/inotify-tools/inotify-tools/actions)
+[![Travis Build 
Status](https://travis-ci.org/inotify-tools/inotify-tools.svg?branch=master)](https://travis-ci.org/inotify-tools/inotify-tools)
+[![Cirrus Build 
Status](https://api.cirrus-ci.com/github/inotify-tools/inotify-tools.svg?branch=master)](https://cirrus-ci.com/github/inotify-tools/inotify-tools)
+[![Language Grade: 
C/C++](https://img.shields.io/lgtm/grade/cpp/g/inotify-tools/inotify-tools.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/inotify-tools/inotify-tools/context:cpp)
 
 inotify-tools
 =============
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/inotify-tools-3.20.2.2/autogen.sh 
new/inotify-tools-3.20.11.0/autogen.sh
--- old/inotify-tools-3.20.2.2/autogen.sh       2020-02-01 13:05:18.000000000 
+0100
+++ new/inotify-tools-3.20.11.0/autogen.sh      2020-11-13 11:52:25.000000000 
+0100
@@ -1,4 +1,3 @@
 #!/bin/sh
 
-cp README.md README
 autoreconf --install "$@" || exit 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/inotify-tools-3.20.2.2/build_and_test.sh 
new/inotify-tools-3.20.11.0/build_and_test.sh
--- old/inotify-tools-3.20.2.2/build_and_test.sh        2020-02-01 
13:05:18.000000000 +0100
+++ new/inotify-tools-3.20.11.0/build_and_test.sh       2020-11-13 
11:52:25.000000000 +0100
@@ -2,20 +2,27 @@
 
 set -e
 
-j=3
+j=10
 
 printf "gcc build\n"
-git clean -fdx 2>&1
+if [ "$1" == "clean" ]; then
+  git clean -fdx 2>&1
+fi
+
 export CC=gcc
 ./autogen.sh
 ./configure
 make -j$j
 
-printf "\nunit test\n"
-cd libinotifytools/src/
-make -j$j test
-./test
-cd -
+os=$(uname -o)
+
+if [ "$os" != "FreeBSD" ]; then
+  printf "\nunit test\n"
+  cd libinotifytools/src/
+  make -j$j test
+  ./test
+  cd -
+fi
 
 printf "\nintegration test\n"
 cd t
@@ -23,17 +30,22 @@
 cd -
 
 printf "\nclang build\n"
-git clean -fdx 2>&1
+if [ "$1" == "clean" ]; then
+  git clean -fdx 2>&1
+fi
+
 export CC=clang
 ./autogen.sh
 ./configure
 make -j$j
 
-printf "\nunit test\n"
-cd libinotifytools/src/
-make -j$j test
-./test
-cd -
+if [ "$os" != "FreeBSD" ]; then
+  printf "\nunit test\n"
+  cd libinotifytools/src/
+  make -j$j test
+  ./test
+  cd -
+fi
 
 printf "\nintegration test\n"
 cd t
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/inotify-tools-3.20.2.2/configure.ac 
new/inotify-tools-3.20.11.0/configure.ac
--- old/inotify-tools-3.20.2.2/configure.ac     2020-02-01 13:05:18.000000000 
+0100
+++ new/inotify-tools-3.20.11.0/configure.ac    2020-11-13 11:52:25.000000000 
+0100
@@ -2,7 +2,7 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ(2.59)
-AC_INIT([inotify-tools], [3.20.2.2])
+AC_INIT([inotify-tools], [3.20.11.0])
 AC_CONFIG_AUX_DIR([config])
 AC_CONFIG_SRCDIR([src/inotifywait.c])
 AC_CONFIG_HEADERS([config.h])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/inotify-tools-3.20.2.2/libinotifytools/src/Makefile.am 
new/inotify-tools-3.20.11.0/libinotifytools/src/Makefile.am
--- old/inotify-tools-3.20.2.2/libinotifytools/src/Makefile.am  2020-02-01 
13:05:18.000000000 +0100
+++ new/inotify-tools-3.20.11.0/libinotifytools/src/Makefile.am 2020-11-13 
11:52:25.000000000 +0100
@@ -14,7 +14,7 @@
 
 nobase_include_HEADERS = inotifytools/inotifytools.h 
inotifytools/inotify-nosys.h inotifytools/inotify.h
 
-AM_CFLAGS = -std=c99 -Wall -Werror
+AM_CFLAGS = -std=c99 -Wall -Wshadow -Werror
 
 if DOXYGEN_ENABLE
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/inotify-tools-3.20.2.2/libinotifytools/src/inotifytools/inotifytools.h 
new/inotify-tools-3.20.11.0/libinotifytools/src/inotifytools/inotifytools.h
--- old/inotify-tools-3.20.2.2/libinotifytools/src/inotifytools/inotifytools.h  
2020-02-01 13:05:18.000000000 +0100
+++ new/inotify-tools-3.20.11.0/libinotifytools/src/inotifytools/inotifytools.h 
2020-11-13 11:52:25.000000000 +0100
@@ -13,6 +13,20 @@
 
 #include <stdio.h>
 
+#define MAX_STRLEN 4096
+
+/** @struct nstring
+ *  @brief This structure holds string that can contain any charater including 
NULL.
+ *  @var nstring::buf
+ *  Member 'buf' contains character buffer.  It can hold up to 4096 characters.
+ *  @var nstring::len
+ *  Member 'len' contains number of characters in buffer.
+ */
+struct nstring {
+       char buf[MAX_STRLEN];
+       unsigned int len;
+};
+
 int inotifytools_str_to_event(char const * event);
 int inotifytools_str_to_event_sep(char const * event, char sep);
 char * inotifytools_event_to_str(int events);
@@ -49,8 +63,8 @@
 
 int inotifytools_printf( struct inotify_event* event, char* fmt );
 int inotifytools_fprintf( FILE* file, struct inotify_event* event, char* fmt );
-int inotifytools_sprintf( char * out, struct inotify_event* event, char* fmt );
-int inotifytools_snprintf( char * out, int size, struct inotify_event* event,
+int inotifytools_sprintf( struct nstring * out, struct inotify_event* event, 
char* fmt );
+int inotifytools_snprintf( struct nstring * out, int size, struct 
inotify_event* event,
                            char* fmt );
 void inotifytools_set_printf_timefmt( char * fmt );
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/inotify-tools-3.20.2.2/libinotifytools/src/inotifytools.c 
new/inotify-tools-3.20.11.0/libinotifytools/src/inotifytools.c
--- old/inotify-tools-3.20.2.2/libinotifytools/src/inotifytools.c       
2020-02-01 13:05:18.000000000 +0100
+++ new/inotify-tools-3.20.11.0/libinotifytools/src/inotifytools.c      
2020-11-13 11:52:25.000000000 +0100
@@ -121,7 +121,6 @@
  */
 
 #define MAX_EVENTS 4096
-#define MAX_STRLEN 4096
 #define INOTIFY_PROCDIR "/proc/sys/fs/inotify/"
 #define WATCHES_SIZE_PATH INOTIFY_PROCDIR "max_user_watches"
 #define QUEUE_SIZE_PATH   INOTIFY_PROCDIR "max_queued_watches"
@@ -1119,12 +1118,15 @@
        static int first_byte = 0;
        static ssize_t bytes;
        static jmp_buf jmp;
-       static char match_name[MAX_STRLEN];
+       static struct nstring match_name;
+       static char match_name_string[MAX_STRLEN+1];
 
 #define RETURN(A) {\
        if (regex) {\
-               inotifytools_snprintf(match_name, MAX_STRLEN, A, "%w%f");\
-               if (0 == regexec(regex, match_name, 0, 0, 0)) {\
+               inotifytools_snprintf(&match_name, MAX_STRLEN, A, "%w%f");\
+               memcpy(&match_name_string, &match_name.buf, match_name.len);\
+               match_name_string[match_name.len] = '\0';\
+               if (0 == regexec(regex, match_name_string, 0, 0, 0)) {\
                        if (!invert_regexp)\
                                longjmp(jmp,0);\
                } else {\
@@ -1655,6 +1657,8 @@
  * The following tokens will be replaced with the specified string:
  *  \li \c \%w - This will be replaced with the name of the Watched file on
  *               which an event occurred.
+ *  \li \c \%c - This will be replaced with the cookie of the Watched file on
+ *               which an event occurred.
  *  \li \c \%f - When an event occurs within a directory, this will be replaced
  *               with the name of the File which caused the event to occur.
  *               Otherwise, this will be replaced with an empty string.
@@ -1665,6 +1669,8 @@
  *               string previously passed to inotifytools_set_printf_timefmt(),
  *               or replaced with an empty string if that function has never
  *               been called.
+ *  \li \c \%0 - Replaced with the 'NUL' character
+ *  \li \c \%n - Replaced with the 'Line Feed' character
  *
  * @section example Example
  * @code
@@ -1700,6 +1706,8 @@
  * The following tokens will be replaced with the specified string:
  *  \li \c \%w - This will be replaced with the name of the Watched file on
  *               which an event occurred.
+ *  \li \c \%c - This will be replaced with the cookie of the Watched file on
+ *               which an event occurred.
  *  \li \c \%f - When an event occurs within a directory, this will be replaced
  *               with the name of the File which caused the event to occur.
  *               Otherwise, this will be replaced with an empty string.
@@ -1710,6 +1718,8 @@
  *               string previously passed to inotifytools_set_printf_timefmt(),
  *               or replaced with an empty string if that function has never
  *               been called.
+ *  \li \c \%0 - Replaced with the 'NUL' character
+ *  \li \c \%n - Replaced with the 'Line Feed' character
  *
  * @section example Example
  * @code
@@ -1726,10 +1736,10 @@
  * @endcode
  */
 int inotifytools_fprintf( FILE* file, struct inotify_event* event, char* fmt ) 
{
-       static char out[MAX_STRLEN+1];
+       static struct nstring out;
        static int ret;
-       ret = inotifytools_sprintf( out, event, fmt );
-       if ( -1 != ret ) fprintf( file, "%s", out );
+       ret = inotifytools_sprintf( &out, event, fmt );
+       if ( -1 != ret ) fwrite( out.buf, sizeof(char), out.len, file );
        return ret;
 }
 
@@ -1742,11 +1752,11 @@
  * may crash.
  * inotifytools_snprintf() is safer and you should use it where possible.
  *
- * @param out location in which to store string.
+ * @param out location in which to store nstring.
  *
- * @param event the event to use to construct a string.
+ * @param event the event to use to construct a nstring.
  *
- * @param fmt the format string used to construct a string.
+ * @param fmt the format string used to construct a nstring.
  *
  * @return number of characters written, or -1 if an error occurs.
  *
@@ -1754,6 +1764,8 @@
  * The following tokens will be replaced with the specified string:
  *  \li \c \%w - This will be replaced with the name of the Watched file on
  *               which an event occurred.
+ *  \li \c \%c - This will be replaced with the cookie of the Watched file on
+ *               which an event occurred.
  *  \li \c \%f - When an event occurs within a directory, this will be replaced
  *               with the name of the File which caused the event to occur.
  *               Otherwise, this will be replaced with an empty string.
@@ -1764,6 +1776,8 @@
  *               string previously passed to inotifytools_set_printf_timefmt(),
  *               or replaced with an empty string if that function has never
  *               been called.
+ *  \li \c \%0 - Replaced with the 'NUL' character
+ *  \li \c \%n - Replaced with the 'Line Feed' character
  *
  * @section example Example
  * @code
@@ -1773,17 +1787,15 @@
  * // wait until an event occurs
  * struct inotify_event * event = inotifytools_next_event( -1 );
  *
- * char mystring[1024];
- * // hope this doesn't crash - if filename is really long, might not fit into
- * // mystring!
- * inotifytools_sprintf(mystring, event, "in %w, file %f had event(s): %.e\n");
- * printf( mystring );
+ * nstring mynstring;
+ * inotifytools_sprintf(mynstring, event, "in %w, file %f had event(s): 
%.e\n");
+ * fwrite( mynstring.buf, sizeof(char), mynstring.len, stdout );
  * // suppose the file 'myfile' in mydir was written to and closed.  Then,
  * // this prints something like:
  * // "in mydir/, file myfile had event(s): CLOSE_WRITE.CLOSE.ISDIR\n"
  * @endcode
  */
-int inotifytools_sprintf( char * out, struct inotify_event* event, char* fmt ) 
{
+int inotifytools_sprintf( struct nstring * out, struct inotify_event* event, 
char* fmt ) {
        return inotifytools_snprintf( out, MAX_STRLEN, event, fmt );
 }
 
@@ -1792,13 +1804,13 @@
  * Construct a string using an inotify_event and a printf-like syntax.
  * The string can only ever be up to 4096 characters in length.
  *
- * @param out location in which to store string.
+ * @param out location in which to store nstring.
  *
  * @param size maximum amount of characters to write.
  *
- * @param event the event to use to construct a string.
+ * @param event the event to use to construct a nstring.
  *
- * @param fmt the format string used to construct a string.
+ * @param fmt the format string used to construct a nstring.
  *
  * @return number of characters written, or -1 if an error occurs.
  *
@@ -1806,6 +1818,8 @@
  * The following tokens will be replaced with the specified string:
  *  \li \c \%w - This will be replaced with the name of the Watched file on
  *               which an event occurred.
+ *  \li \c \%c - This will be replaced with cookie of the Watched file on
+ *               which an event occurred.
  *  \li \c \%f - When an event occurs within a directory, this will be replaced
  *               with the name of the File which caused the event to occur.
  *               Otherwise, this will be replaced with an empty string.
@@ -1816,6 +1830,8 @@
  *               string previously passed to inotifytools_set_printf_timefmt(),
  *               or replaced with an empty string if that function has never
  *               been called.
+ *  \li \c \%0 - Replaced with the 'NUL' character
+ *  \li \c \%n - Replaced with the 'Line Feed' character
  *
  * @section example Example
  * @code
@@ -1825,25 +1841,24 @@
  * // wait until an event occurs
  * struct inotify_event * event = inotifytools_next_event( -1 );
  *
- * char mystring[1024];
- * inotifytools_snprintf( mystring, 1024, event,
+ * struct nstring mynstring;
+ * inotifytools_snprintf( mynstring, MAX_STRLEN, event,
  *                        "in %w, file %f had event(s): %.e\n" );
- * printf( mystring );
+ * fwrite( mynstring.buf, sizeof(char), mynstring.len, stdout );
  * // suppose the file 'myfile' in mydir was written to and closed.  Then,
  * // this prints something like:
  * // "in mydir/, file myfile had event(s): CLOSE_WRITE.CLOSE.ISDIR\n"
  * @endcode
  */
-int inotifytools_snprintf( char * out, int size,
+int inotifytools_snprintf( struct nstring * out, int size,
                            struct inotify_event* event, char* fmt ) {
        static char * filename, * eventname, * eventstr;
        static unsigned int i, ind;
        static char ch1;
        static char timestr[MAX_STRLEN];
-       static time_t now;
-
+        static time_t now;
 
-       if ( event->len > 0 ) {
+        if ( event->len > 0 ) {
                eventname = event->name;
        }
        else {
@@ -1866,7 +1881,7 @@
        for ( i = 0; i < strlen(fmt) &&
                     (int)ind < size - 1; ++i ) {
                if ( fmt[i] != '%' ) {
-                       out[ind++] = fmt[i];
+                       out->buf[ind++] = fmt[i];
                        continue;
                }
 
@@ -1879,14 +1894,26 @@
                ch1 = fmt[i+1];
 
                if ( ch1 == '%' ) {
-                       out[ind++] = '%';
+                       out->buf[ind++] = '%';
+                       ++i;
+                       continue;
+               }
+
+               if ( ch1 == '0' ) {
+                       out->buf[ind++] = '\0';
+                       ++i;
+                       continue;
+               }
+
+               if ( ch1 == 'n' ) {
+                       out->buf[ind++] = '\n';
                        ++i;
                        continue;
                }
 
                if ( ch1 == 'w' ) {
                        if ( filename ) {
-                               strncpy( &out[ind], filename, size - ind );
+                               strncpy( &out->buf[ind], filename, size - ind );
                                ind += strlen(filename);
                        }
                        ++i;
@@ -1895,16 +1922,22 @@
 
                if ( ch1 == 'f' ) {
                        if ( eventname ) {
-                               strncpy( &out[ind], eventname, size - ind );
+                               strncpy( &out->buf[ind], eventname, size - ind 
);
                                ind += strlen(eventname);
                        }
                        ++i;
                        continue;
                }
 
+               if ( ch1 == 'c' ) {
+                       ind += snprintf( &out->buf[ind], size-ind, "%x", 
event->cookie);
+                       ++i;
+                       continue;
+               }
+
                if ( ch1 == 'e' ) {
                        eventstr = inotifytools_event_to_str( event->mask );
-                       strncpy( &out[ind], eventstr, size - ind );
+                       strncpy( &out->buf[ind], eventstr, size - ind );
                        ind += strlen(eventstr);
                        ++i;
                        continue;
@@ -1913,21 +1946,21 @@
                if ( ch1 == 'T' ) {
 
                        if ( timefmt ) {
-
                                now = time(0);
-                               if ( 0 >= strftime( timestr, MAX_STRLEN-1, 
timefmt,
-                                                   localtime( &now ) ) ) {
-
-                                       // time format probably invalid
-                                       error = EINVAL;
-                                       return ind;
+                                struct tm now_tm;
+                                if (0 >= strftime(timestr, MAX_STRLEN - 1,
+                                                  timefmt,
+                                                  localtime_r(&now, &now_tm))) 
{
+                                    // time format probably invalid
+                                    error = EINVAL;
+                                    return ind;
                                }
                        }
                        else {
                                timestr[0] = 0;
                        }
 
-                       strncpy( &out[ind], timestr, size - ind );
+                       strncpy( &out->buf[ind], timestr, size - ind );
                        ind += strlen(timestr);
                        ++i;
                        continue;
@@ -1936,18 +1969,18 @@
                // Check if next char in fmt is e
                if ( i < strlen(fmt) - 2 && fmt[i+2] == 'e' ) {
                        eventstr = inotifytools_event_to_str_sep( event->mask, 
ch1 );
-                       strncpy( &out[ind], eventstr, size - ind );
+                       strncpy( &out->buf[ind], eventstr, size - ind );
                        ind += strlen(eventstr);
                        i += 2;
                        continue;
                }
 
                // OK, this wasn't a special format character, just output it 
as normal
-               if ( ind < MAX_STRLEN ) out[ind++] = '%';
-               if ( ind < MAX_STRLEN ) out[ind++] = ch1;
+               if ( ind < MAX_STRLEN ) out->buf[ind++] = '%';
+               if ( ind < MAX_STRLEN ) out->buf[ind++] = ch1;
                ++i;
        }
-       out[ind] = 0;
+       out->len = ind;
 
        return ind - 1;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/inotify-tools-3.20.2.2/libinotifytools/src/redblack.c 
new/inotify-tools-3.20.11.0/libinotifytools/src/redblack.c
--- old/inotify-tools-3.20.2.2/libinotifytools/src/redblack.c   2020-02-01 
13:05:18.000000000 +0100
+++ new/inotify-tools-3.20.11.0/libinotifytools/src/redblack.c  2020-11-13 
11:52:25.000000000 +0100
@@ -292,7 +292,6 @@
        struct RB_ENTRY(node) *x,*y,*z;
        int cmp;
        int found=0;
-       int cmpmods();
 
        y=RBNULL; /* points to the parent of x */
        x=rbinfo->rb_root;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/inotify-tools-3.20.2.2/libinotifytools/src/redblack.h 
new/inotify-tools-3.20.11.0/libinotifytools/src/redblack.h
--- old/inotify-tools-3.20.2.2/libinotifytools/src/redblack.h   2020-02-01 
13:05:18.000000000 +0100
+++ new/inotify-tools-3.20.11.0/libinotifytools/src/redblack.h  2020-11-13 
11:52:25.000000000 +0100
@@ -27,6 +27,7 @@
  
 /* Stop multiple includes */
 #ifndef _REDBLACK_H
+#define _REDBLACK_H
 
 #ifndef RB_CUSTOMIZE
 /*
@@ -132,7 +133,6 @@
 #define rbmin(rbinfo) RB_ENTRY(lookup)(RB_LUFIRST, NULL, (rbinfo))
 #define rbmax(rbinfo) RB_ENTRY(lookup)(RB_LULAST, NULL, (rbinfo))
 
-#define _REDBLACK_H
 #endif /* _REDBLACK_H */
 
 /*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/inotify-tools-3.20.2.2/libinotifytools/src/test.c 
new/inotify-tools-3.20.11.0/libinotifytools/src/test.c
--- old/inotify-tools-3.20.2.2/libinotifytools/src/test.c       2020-02-01 
13:05:18.000000000 +0100
+++ new/inotify-tools-3.20.11.0/libinotifytools/src/test.c      2020-11-13 
11:52:25.000000000 +0100
@@ -199,63 +199,61 @@
     verify(inotifytools_initialize());
     verify(inotifytools_watch_file(TEST_DIR, IN_CLOSE));
 
-#define BUFSZ 2048
 #define RESET                                                                  
\
     do {                                                                       
\
-        memset(buf, 0, BUFSZ);                                                 
\
+        memset(out.buf, 0, MAX_STRLEN);                                        
    \
         memset(test_event, 0, sizeof(struct inotify_event));                   
\
         test_event->wd = inotifytools_wd_from_filename(TEST_DIR "/");          
\
         verify(test_event->wd >= 0);                                           
\
         inotifytools_set_printf_timefmt(0);                                    
\
     } while (0)
 
-    char buf[BUFSZ];
+    struct nstring out;
     char event_buf[4096];
     struct inotify_event *test_event = (struct inotify_event *)event_buf;
 
     RESET;
     test_event->mask = IN_ACCESS;
-    inotifytools_snprintf(buf, 1024, test_event, "Event %e %.e on %w %f %T");
-    verify2(!strcmp(buf, "Event ACCESS ACCESS on " TEST_DIR "/  "), buf);
+    inotifytools_snprintf(&out, MAX_STRLEN, test_event, "Event %e %.e on %w %f 
%T");
+    verify2(!strcmp(out.buf, "Event ACCESS ACCESS on " TEST_DIR "/  "), 
out.buf);
 
     RESET;
     test_event->mask = IN_ACCESS | IN_DELETE;
-    inotifytools_snprintf(buf, 1024, test_event, "Event %e %.e on %w %f %T");
+    inotifytools_snprintf(&out, MAX_STRLEN, test_event, "Event %e %.e on %w %f 
%T");
     verify2(
-        !strcmp(buf, "Event ACCESS,DELETE ACCESS.DELETE on " TEST_DIR "/  ") ||
-            !strcmp(buf,
+        !strcmp(out.buf, "Event ACCESS,DELETE ACCESS.DELETE on " TEST_DIR "/  
") ||
+            !strcmp(out.buf,
                     "Event DELETE,ACCESS DELETE.ACCESS on " TEST_DIR "/  "),
-        buf);
+        out.buf);
 
     RESET;
     test_event->mask = IN_MODIFY;
-    inotifytools_snprintf(buf, 10, test_event, "Event %e %.e on %w %f %T");
-    verify2(!strcmp(buf, "Event MODI"), buf);
+    inotifytools_snprintf(&out, 10, test_event, "Event %e %.e on %w %f %T");
+    verify2(!strcmp(out.buf, "Event MODI"), out.buf);
 
     RESET;
     test_event->mask = IN_ACCESS;
     strcpy(test_event->name, "my_great_file");
     test_event->len = strlen(test_event->name) + 1;
-    inotifytools_snprintf(buf, 1024, test_event, "Event %e %.e on %w %f %T");
-    verify2(!strcmp(buf, "Event ACCESS ACCESS on " TEST_DIR "/ my_great_file 
"),
-            buf);
+    inotifytools_snprintf(&out, MAX_STRLEN, test_event, "Event %e %.e on %w %f 
%T");
+    verify2(!strcmp(out.buf, "Event ACCESS ACCESS on " TEST_DIR "/ 
my_great_file "),
+            out.buf);
 
     RESET;
     test_event->mask = IN_ACCESS;
     inotifytools_set_printf_timefmt("%D%% %H:%M");
     {
-        char expected[1024];
+        char expected[MAX_STRLEN];
         char timestr[512];
         time_t now = time(0);
         strftime(timestr, 512, "%D%% %H:%M", localtime(&now));
-        snprintf(expected, 1024, "Event ACCESS ACCESS on %s/  %s", TEST_DIR,
+        snprintf(expected, MAX_STRLEN, "Event ACCESS ACCESS on %s/  %s", 
TEST_DIR,
                  timestr);
-        inotifytools_snprintf(buf, 1024, test_event,
+        inotifytools_snprintf(&out, MAX_STRLEN, test_event,
                               "Event %e %.e on %w %f %T");
-        verify2(!strcmp(buf, expected), buf);
+        verify2(!strcmp(out.buf, expected), out.buf);
     }
 
-#undef BUFSZ
     EXIT
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/inotify-tools-3.20.2.2/man/inotifywait.1.in 
new/inotify-tools-3.20.11.0/man/inotifywait.1.in
--- old/inotify-tools-3.20.2.2/man/inotifywait.1.in     2020-02-01 
13:05:18.000000000 +0100
+++ new/inotify-tools-3.20.11.0/man/inotifywait.1.in    2020-11-13 
11:52:25.000000000 +0100
@@ -5,7 +5,7 @@
 
 .SH SYNOPSIS
 .B inotifywait
-.RB [ \-hcmrq ]
+.RB [ \-hcmrPq ]
 .RB [ \-e
 <event> ]
 .RB [ \-t
@@ -90,6 +90,9 @@
 .BR syslog(3)
 system log module rather than stderr.
 .TP
+.B \-P, \-\-no\-dereference
+Do not follow symlinks.
+.TP
 .B \-r, \-\-recursive
 Watch all subdirectories of any directories passed as arguments.  Watches
 will be set up recursively to an unlimited depth.  Symbolic links are not
@@ -147,6 +150,10 @@
 in the \-\-format option.
 
 .TP
+.B \-\-no-newline
+Don't print newline symbol after user-specified format in the \-\-format 
option.
+
+.TP
 .B \-\-format <fmt>
 Output in a user-specified format, using printf-like syntax.  The event strings
 output are limited to around 4000 characters and will be truncated to this 
length.
@@ -176,6 +183,14 @@
 Replaced with the current Time in the format specified by the \-\-timefmt 
option,
 which should be a format string suitable for passing to strftime(3).
 
+.TP
+%0
+Replaced with NUL.
+
+.TP
+%n
+Replaced with Line Feed.
+
 
 
 .SH "EXIT STATUS"
@@ -332,6 +347,17 @@
 DELETE badfile
 .fi
 
+.SS Example 4
+Enforce file permissions in directory `~/test'
+
+.nf
+inotifywait -qmr -e 'moved_to,create' --format '%w%f%0' --no-newline ~/test |\\
+    while IFS= read -r -d '' file
+    do
+         chmod -v a+rX "$file"
+    done
+.fi
+
 
 .SH BUGS
 There are race conditions in the recursive directory watching code
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/inotify-tools-3.20.2.2/man/inotifywatch.1.in 
new/inotify-tools-3.20.11.0/man/inotifywatch.1.in
--- old/inotify-tools-3.20.2.2/man/inotifywatch.1.in    2020-02-01 
13:05:18.000000000 +0100
+++ new/inotify-tools-3.20.11.0/man/inotifywatch.1.in   2020-11-13 
11:52:25.000000000 +0100
@@ -5,7 +5,7 @@
 
 .SH SYNOPSIS
 .B inotifywatch
-.RB [ \-hvzrqf ]
+.RB [ \-hvzrPqf ]
 .RB [ \-e
 <event> ]
 .RB [ \-t
@@ -97,6 +97,10 @@
 .BR /proc/sys/fs/inotify/max_user_watches .
 
 .TP
+.B \-P, \-\-no\-dereference
+Do not follow symlinks.
+
+.TP
 .B \-t <seconds>, \-\-timeout <seconds>
 Listen only for the specified amount of seconds.  If not specified, 
inotifywatch
 will gather statistics until receiving an interrupt signal by (for example)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/inotify-tools-3.20.2.2/src/Makefile.am 
new/inotify-tools-3.20.11.0/src/Makefile.am
--- old/inotify-tools-3.20.2.2/src/Makefile.am  2020-02-01 13:05:18.000000000 
+0100
+++ new/inotify-tools-3.20.11.0/src/Makefile.am 2020-11-13 11:52:25.000000000 
+0100
@@ -2,7 +2,7 @@
 inotifywait_SOURCES = inotifywait.c common.c common.h
 inotifywatch_SOURCES = inotifywatch.c common.c common.h
 
-AM_CFLAGS = -Wall -Wextra -Wpointer-arith -Werror -std=c99 
-I../libinotifytools/src
+AM_CFLAGS = -Wall -Wextra -Wshadow -Wpointer-arith -Werror -std=c99 
-I../libinotifytools/src
 AM_CPPFLAGS = -I$(top_srcdir)/libinotifytools/src
 LDADD = ../libinotifytools/src/libinotifytools.la
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/inotify-tools-3.20.2.2/src/common.c 
new/inotify-tools-3.20.11.0/src/common.c
--- old/inotify-tools-3.20.2.2/src/common.c     2020-02-01 13:05:18.000000000 
+0100
+++ new/inotify-tools-3.20.11.0/src/common.c    2020-11-13 11:52:25.000000000 
+0100
@@ -62,11 +62,12 @@
     list.exclude_files = 0;
     FILE *file = 0;
 
-    if (!filename) {
-    } else if (!strcmp(filename, "-")) {
-        file = stdin;
-    } else {
-        file = fopen(filename, "r");
+    if (filename) {
+        if (!strcmp(filename, "-")) {
+            file = stdin;
+        } else {
+            file = fopen(filename, "r");
+        }
     }
 
     int watch_len = LIST_CHUNK;
@@ -136,8 +137,8 @@
     }
 }
 
-bool is_timeout_option_valid(long int *timeout, char *optarg) {
-    if ((optarg == NULL) || (*optarg == '\0')) {
+bool is_timeout_option_valid(long int *timeout, char *o) {
+    if ((o == NULL) || (*o == '\0')) {
         fprintf(stderr, "The provided value is not a valid timeout value.\n"
                         "Please specify a long int value.\n");
         return false;
@@ -145,7 +146,7 @@
 
     char *timeout_end = NULL;
     errno = 0;
-    *timeout = strtol(optarg, &timeout_end, 10);
+    *timeout = strtol(o, &timeout_end, 10);
 
     const int err = errno;
     if (err != 0) {
@@ -172,7 +173,7 @@
     if (*timeout_end != '\0') {
         fprintf(stderr, "'%s' is not a valid timeout value.\n"
                         "Please specify a long int value.\n",
-                optarg);
+                o);
         return false;
     }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/inotify-tools-3.20.2.2/src/inotifywait.c 
new/inotify-tools-3.20.11.0/src/inotifywait.c
--- old/inotify-tools-3.20.2.2/src/inotifywait.c        2020-02-01 
13:05:18.000000000 +0100
+++ new/inotify-tools-3.20.11.0/src/inotifywait.c       2020-11-13 
11:52:25.000000000 +0100
@@ -34,9 +34,10 @@
 // METHODS
 bool parse_opts(int *argc, char ***argv, int *events, bool *monitor, int 
*quiet,
                 long int *timeout, int *recursive, bool *csv, bool *daemon,
-                bool *syslog, char **format, char **timefmt, char **fromfile,
-                char **outfile, char **exc_regex, char **exc_iregex,
-                char **inc_regex, char **inc_iregex);
+                bool *syslog, bool *no_dereference, char **format,
+                char **timefmt, char **fromfile, char **outfile,
+                char **exc_regex, char **exc_iregex, char **inc_regex,
+                char **inc_iregex, bool *no_newline);
 
 void print_help();
 
@@ -136,6 +137,7 @@
     bool csv = false;
     bool dodaemon = false;
     bool syslog = false;
+    bool no_dereference = false;
     char *format = NULL;
     char *timefmt = NULL;
     char *fromfile = NULL;
@@ -144,13 +146,14 @@
     char *exc_iregex = NULL;
     char *inc_regex = NULL;
     char *inc_iregex = NULL;
+    bool no_newline = false;
     int fd;
 
     // Parse commandline options, aborting if something goes wrong
     if (!parse_opts(&argc, &argv, &events, &monitor, &quiet, &timeout,
-                    &recursive, &csv, &dodaemon, &syslog, &format, &timefmt,
-                    &fromfile, &outfile, &exc_regex, &exc_iregex, &inc_regex,
-                    &inc_iregex)) {
+                    &recursive, &csv, &dodaemon, &syslog, &no_dereference,
+                    &format, &timefmt, &fromfile, &outfile, &exc_regex,
+                    &exc_iregex, &inc_regex, &inc_iregex, &no_newline)) {
         return EXIT_FAILURE;
     }
 
@@ -190,6 +193,9 @@
     if (monitor && recursive) {
         events = events | IN_CREATE | IN_MOVED_TO | IN_MOVED_FROM;
     }
+    if (no_dereference) {
+        events = events | IN_DONT_FOLLOW;
+    }
 
     FileList list = construct_path_list(argc, argv, fromfile);
 
@@ -412,9 +418,10 @@
 
 bool parse_opts(int *argc, char ***argv, int *events, bool *monitor, int 
*quiet,
                 long int *timeout, int *recursive, bool *csv, bool *daemon,
-                bool *syslog, char **format, char **timefmt, char **fromfile,
-                char **outfile, char **exc_regex, char **exc_iregex,
-                char **inc_regex, char **inc_iregex) {
+                bool *syslog, bool *no_dereference, char **format,
+                char **timefmt, char **fromfile, char **outfile,
+                char **exc_regex, char **exc_iregex, char **inc_regex,
+                char **inc_iregex, bool *no_newline) {
     assert(argc);
     assert(argv);
     assert(events);
@@ -424,6 +431,7 @@
     assert(csv);
     assert(daemon);
     assert(syslog);
+    assert(no_dereference);
     assert(format);
     assert(timefmt);
     assert(fromfile);
@@ -445,11 +453,11 @@
     const char *regex_warning =
         "only the last option will be taken into consideration.\n";
 
-    // format with trailing newline
-    static char *newlineformat;
+    // format provided by the user
+    static char *customformat = NULL;
 
     // Short options
-    static const char opt_string[] = "mrhcdsqt:fo:e:";
+    static const char opt_string[] = "mrhcdsPqt:fo:e:";
 
     // Long options
     static const struct option long_opts[] = {
@@ -463,7 +471,9 @@
         {"csv", no_argument, NULL, 'c'},
         {"daemon", no_argument, NULL, 'd'},
         {"syslog", no_argument, NULL, 's'},
+        {"no-dereference", no_argument, NULL, 'P'},
         {"format", required_argument, NULL, 'n'},
+        {"no-newline", no_argument, NULL, '0'},
         {"timefmt", required_argument, NULL, 'i'},
         {"fromfile", required_argument, NULL, 'z'},
         {"outfile", required_argument, NULL, 'o'},
@@ -519,6 +529,11 @@
             (*syslog) = true;
             break;
 
+        // --no-dereference or -P
+        case 'P':
+            (*no_dereference) = true;
+            break;
+
         // --filename or -f
         case 'f':
             fprintf(stderr, "The '--filename' option no longer exists.  "
@@ -529,10 +544,13 @@
 
         // --format
         case 'n':
-            newlineformat = (char *)malloc(strlen(optarg) + 2);
-            strcpy(newlineformat, optarg);
-            strcat(newlineformat, "\n");
-            (*format) = newlineformat;
+            customformat = (char *)malloc(strlen(optarg) + 2);
+            strcpy(customformat, optarg);
+            break;
+
+        // --no-newline
+        case '0':
+            (*no_newline) = true;
             break;
 
         // --timefmt
@@ -610,6 +628,13 @@
         curr_opt = getopt_long(*argc, *argv, opt_string, long_opts, NULL);
     }
 
+    if (customformat) {
+        if(!(*no_newline)) {
+            strcat(customformat, "\n");
+        }
+        (*format) = customformat;
+    }
+
     if (*exc_regex && *exc_iregex) {
         fprintf(stderr, "--exclude and --excludei cannot both be 
specified.\n");
         return false;
@@ -632,6 +657,11 @@
         return false;
     }
 
+    if (!*format && *no_newline) {
+        fprintf(stderr, "--no-newline cannot be specified without 
--format.\n");
+        return false;
+    }
+
     if (!*format && *timefmt) {
         fprintf(stderr, "--timefmt cannot be specified without --format.\n");
         return false;
@@ -693,6 +723,8 @@
         "\t-d|--daemon   \tSame as --monitor, except run in the background\n"
         "\t              \tlogging events to a file specified by --outfile.\n"
         "\t              \tImplies --syslog.\n");
+    printf("\t-P|--no-dereference\n"
+           "\t              \tDo not follow symlinks.\n");
     printf("\t-r|--recursive\tWatch directories recursively.\n");
     printf("\t--fromfile <file>\n"
            "\t              \tRead files to watch from <file> or `-' for "
@@ -704,6 +736,8 @@
     printf("\t-qq           \tPrint nothing (not even events).\n");
     printf("\t--format <fmt>\tPrint using a specified printf-like format\n"
            "\t              \tstring; read the man page for more details.\n");
+    printf("\t--no-newline  \tDon't print newline symbol after\n"
+           "\t              \t--format string.\n");
     printf("\t--timefmt <fmt>\tstrftime-compatible format string for use 
with\n"
            "\t              \t%%T in --format string.\n");
     printf("\t-c|--csv      \tPrint events in CSV format.\n");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/inotify-tools-3.20.2.2/src/inotifywatch.c 
new/inotify-tools-3.20.11.0/src/inotifywatch.c
--- old/inotify-tools-3.20.2.2/src/inotifywatch.c       2020-02-01 
13:05:18.000000000 +0100
+++ new/inotify-tools-3.20.11.0/src/inotifywatch.c      2020-11-13 
11:52:25.000000000 +0100
@@ -1,4 +1,3 @@
-// FIXME this is cheating!  Make this use only the public API.
 #include "../config.h"
 #include "../libinotifytools/src/inotifytools_p.h"
 #include "common.h"
@@ -31,8 +30,8 @@
 // METHODS
 bool parse_opts(int *argc, char ***argv, int *events, long int *timeout,
                 int *verbose, int *zero, int *sort, int *recursive,
-                char **fromfile, char **exc_regex, char **exc_iregex,
-                char **inc_regex, char **inc_iregex);
+                int *no_dereference, char **fromfile, char **exc_regex,
+                char **exc_iregex, char **inc_regex, char **inc_iregex);
 
 void print_help();
 
@@ -74,6 +73,7 @@
     int verbose = 0;
     zero = 0;
     int recursive = 0;
+    int no_dereference = 0;
     char *fromfile = 0;
     sort = -1;
     done = false;
@@ -86,8 +86,8 @@
 
     // Parse commandline options, aborting if something goes wrong
     if (!parse_opts(&argc, &argv, &events, &timeout, &verbose, &zero, &sort,
-                    &recursive, &fromfile, &exc_regex, &exc_iregex, &inc_regex,
-                    &inc_iregex)) {
+                    &recursive, &no_dereference, &fromfile, &exc_regex,
+                    &exc_iregex, &inc_regex, &inc_iregex)) {
         return EXIT_FAILURE;
     }
 
@@ -119,6 +119,8 @@
     // If events is still 0, make it all events.
     if (!events)
         events = IN_ALL_EVENTS;
+    if (no_dereference)
+        events = events | IN_DONT_FOLLOW;
 
     FileList list = construct_path_list(argc, argv, fromfile);
 
@@ -362,18 +364,19 @@
     return EXIT_SUCCESS;
 }
 
-bool parse_opts(int *argc, char ***argv, int *events, long int *timeout,
-                int *verbose, int *zero, int *sort, int *recursive,
-                char **fromfile, char **exc_regex, char **exc_iregex,
-                char **inc_regex, char **inc_iregex) {
+bool parse_opts(int *argc, char ***argv, int *e, long int *timeout,
+                int *verbose, int *z, int *s, int *recursive,
+                int *no_dereference, char **fromfile, char **exc_regex,
+                char **exc_iregex, char **inc_regex, char **inc_iregex) {
     assert(argc);
     assert(argv);
-    assert(events);
+    assert(e);
     assert(timeout);
     assert(verbose);
-    assert(zero);
-    assert(sort);
+    assert(z);
+    assert(s);
     assert(recursive);
+    assert(no_dereference);
     assert(fromfile);
     assert(exc_regex);
     assert(exc_iregex);
@@ -385,7 +388,7 @@
     bool sort_set = false;
 
     // Short options
-    static const char opt_string[] = "hra:d:zve:t:";
+    static const char opt_string[] = "hrPa:d:zve:t:";
 
     // Construct array
     static const struct option long_opts[] = {
@@ -397,6 +400,7 @@
         {"ascending", required_argument, NULL, 'a'},
         {"descending", required_argument, NULL, 'd'},
         {"recursive", no_argument, NULL, 'r'},
+        {"no-dereference", no_argument, NULL, 'P'},
         {"fromfile", required_argument, NULL, 'o'},
         {"exclude", required_argument, NULL, 'c'},
         {"excludei", required_argument, NULL, 'b'},
@@ -427,10 +431,13 @@
         case 'r':
             ++(*recursive);
             break;
+        case 'P':
+            ++(*no_dereference);
+            break;
 
         // --zero or -z
         case 'z':
-            ++(*zero);
+            ++(*z);
             break;
 
         // --exclude
@@ -484,7 +491,7 @@
             }
 
             // Add the new event to the event mask
-            (*events) = ((*events) | new_event);
+            (*e) = ((*e) | new_event);
 
             break;
 
@@ -495,7 +502,7 @@
                 return false;
             }
             if (0 == strcasecmp(optarg, "total")) {
-                (*sort) = 0;
+                (*s) = 0;
             } else if (0 == strcasecmp(optarg, "move")) {
                 fprintf(stderr, "Cannot sort by `move' event; please use "
                                 "`moved_from' or `moved_to'.\n");
@@ -515,7 +522,7 @@
                     return false;
                 }
 
-                (*sort) = event;
+                (*s) = event;
             }
             sort_set = true;
             break;
@@ -527,7 +534,7 @@
                 return false;
             }
             if (0 == strcasecmp(optarg, "total")) {
-                (*sort) = -1;
+                (*s) = -1;
             } else {
                 int event = inotifytools_str_to_event(optarg);
 
@@ -539,7 +546,7 @@
                     return false;
                 }
 
-                (*sort) = -event;
+                (*s) = -event;
             }
             break;
         }
@@ -550,8 +557,8 @@
     (*argc) -= optind;
     *argv = &(*argv)[optind];
 
-    if ((*sort) != 0 && (*sort) != -1 &&
-        !(abs(*sort) & ((*events) ? (*events) : IN_ALL_EVENTS))) {
+    if ((*s) != 0 && (*s) != -1 &&
+        !(abs(*s) & ((*e) ? (*e) : IN_ALL_EVENTS))) {
         fprintf(stderr, "Can't sort by an event which isn't being watched "
                         "for!\n");
         return false;
@@ -603,6 +610,8 @@
            "\t\tif they consist only of zeros (the default is to not output\n"
            "\t\tthese rows and columns).\n");
     printf("\t-r|--recursive\tWatch directories recursively.\n");
+    printf("\t-P|--no-dereference\n"
+           "\t\tDo not follow symlinks.\n");
     printf("\t-t|--timeout <seconds>\n"
            "\t\tListen only for specified amount of time in seconds; if\n"
            "\t\tomitted or negative, inotifywatch will execute until receiving 
"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/inotify-tools-3.20.2.2/t/Makefile 
new/inotify-tools-3.20.11.0/t/Makefile
--- old/inotify-tools-3.20.2.2/t/Makefile       2020-02-01 13:05:18.000000000 
+0100
+++ new/inotify-tools-3.20.11.0/t/Makefile      2020-11-13 11:52:25.000000000 
+0100
@@ -17,8 +17,7 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see http://www.gnu.org/licenses/ .
 
-SHELL_PATH ?= $(SHELL)
-SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
+SHELL_PATH ?= /bin/bash
 RM ?= rm -f
 PROVE ?= prove
 AGGREGATE_SCRIPT ?= aggregate-results.sh
@@ -32,11 +31,11 @@
        $(MAKE) aggregate-results-and-cleanup
 
 prove: pre-clean
-       @echo "*** prove ***"; $(PROVE) --exec '$(SHELL_PATH_SQ)' $(PROVE_OPTS) 
$(T) :: $(TEST_OPTS)
+       @echo "*** prove ***"; $(PROVE) --exec '$(SHELL_PATH)' $(PROVE_OPTS) 
$(T) :: $(TEST_OPTS)
        $(MAKE) clean-except-prove-cache
 
 $(T):
-       @echo "*** $@ ***"; '$(SHELL_PATH_SQ)' $@ $(TEST_OPTS)
+       @echo "*** $@ ***"; '$(SHELL_PATH)' $@ $(TEST_OPTS)
 
 pre-clean:
        $(RM) -r test-results
@@ -54,7 +53,7 @@
 aggregate-results:
        for f in test-results/*.counts; do \
                echo "$$f"; \
-       done | '$(SHELL_PATH_SQ)' '$(AGGREGATE_SCRIPT)'
+       done | '$(SHELL_PATH)' '$(AGGREGATE_SCRIPT)'
 
 .PHONY: all test prove $(T) pre-clean clean
 .PHONY: aggregate-results-and-cleanup aggregate-results
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/inotify-tools-3.20.2.2/t/inotifywait-daemon-logs-chown.t 
new/inotify-tools-3.20.11.0/t/inotifywait-daemon-logs-chown.t
--- old/inotify-tools-3.20.2.2/t/inotifywait-daemon-logs-chown.t        
1970-01-01 01:00:00.000000000 +0100
+++ new/inotify-tools-3.20.11.0/t/inotifywait-daemon-logs-chown.t       
2020-11-13 11:52:25.000000000 +0100
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+test_description='Issue #62
+
+When --daemon is used, events are logged correctly to --outfile
+even if that is a relative path
+'
+
+. ./sharness.sh
+
+logfile="log"
+
+run_() {
+    # Setup code, defer an ATTRIB event for after
+    # inotifywait has been set up.
+    timeout=2 &&
+    touch $logfile test-file &&
+    {(sleep 1 && chown $(id -u) test-file)&} &&
+
+    export LD_LIBRARY_PATH="../../libinotifytools/src/.libs/"
+    ../../src/.libs/inotifywait \
+        --quiet \
+        --daemon \
+        --outfile $logfile \
+        --event ATTRIB \
+        --timeout $timeout \
+        $(realpath test-file) &&
+    # No way to use 'wait' for a process that is not a child of this one,
+    # sleep instead until inotifywait's timeout is reached.
+    sleep $timeout
+}
+
+test_expect_success 'event logged' '
+    run_ &&
+    grep ATTRIB $logfile
+'
+
+test_done
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/inotify-tools-3.20.2.2/t/inotifywait-format-option-cookie.t 
new/inotify-tools-3.20.11.0/t/inotifywait-format-option-cookie.t
--- old/inotify-tools-3.20.2.2/t/inotifywait-format-option-cookie.t     
1970-01-01 01:00:00.000000000 +0100
+++ new/inotify-tools-3.20.11.0/t/inotifywait-format-option-cookie.t    
2020-11-13 11:52:25.000000000 +0100
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+test_description='Resolves Issue #72
+
+Make transaction id (cookie) available as part of the format string using %c'
+
+. ./sharness.sh
+
+logfile="log"
+
+run_() {
+  # Setup code, defer an ATTRIB event for after
+  # inotifywait has been set up.
+  touch $logfile
+
+  export LD_LIBRARY_PATH="../../libinotifytools/src/.libs/"
+
+  ../../src/.libs/inotifywait \
+    --monitor \
+    --daemon \
+    --quiet \
+    --outfile $logfile \
+    --format '%c %e %w%f' \
+    --event create \
+    --event moved_to \
+    --event moved_from \
+    $(realpath ./)
+
+  PID="$!"
+
+  touch test-file-src
+
+  mv test-file-src test-file-dst
+
+  kill ${PID}
+}
+
+test_expect_success \
+       'event logged' \
+       '
+       set -e
+       trap "set +e" RETURN
+       run_
+       local NONCOOKIE="$(cat "${logfile}" | sed -n 1p | grep -Eo "^[^ ]+")"
+       #Make sure cookie is 0 for single events
+       [[ "${NONCOOKIE}" == "0" ]] || return 1
+       local COOKIE_A="$(cat "${logfile}" | sed -n 2p | grep -Eo "^[^ ]+")"
+       [[ -n "${COOKIE_A}" ]] || return 1
+       local COOKIE_B="$(cat "${logfile}" | sed -n 3p | grep -Eo "^[^ ]+")"
+       [[ "${COOKIE_A}" == "${COOKIE_B}" ]] || return 1
+       return 0
+       '
+
+test_done
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/inotify-tools-3.20.2.2/t/inotifywait-format-option-null.t 
new/inotify-tools-3.20.11.0/t/inotifywait-format-option-null.t
--- old/inotify-tools-3.20.2.2/t/inotifywait-format-option-null.t       
1970-01-01 01:00:00.000000000 +0100
+++ new/inotify-tools-3.20.11.0/t/inotifywait-format-option-null.t      
2020-11-13 11:52:25.000000000 +0100
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+test_description='Check producing NUL-delimited output'
+
+. ./sharness.sh
+
+logfile="log"
+
+run_() {
+  touch $logfile
+
+  export LD_LIBRARY_PATH="../../libinotifytools/src/.libs/"
+
+  ../../src/.libs/inotifywait \
+    --monitor \
+    --quiet \
+    --outfile $logfile \
+    --format '%w%f%0' \
+    --no-newline \
+    --event create \
+    --event moved_to \
+    --event moved_from \
+    $(realpath ./) &
+
+  PID="$!"
+  sleep 1
+
+  touch test-file-src
+
+  mv test-file-src test-file-dst
+
+  sleep 1
+
+  kill ${PID}
+}
+
+test_expect_success 'the output is delimited by NUL' \
+       '
+       set -e
+       trap "set +e" RETURN
+       run_
+       srcfile="${PWD}/test-file-src"
+       dstfile="${PWD}/test-file-dst"
+
+       return $(printf "${srcfile}\0${srcfile}\0${dstfile}\0" | cmp -s 
"${logfile}")
+       '
+
+test_done
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/inotify-tools-3.20.2.2/t/inotifywait-no-dereference-ignore-symlinked-file.t 
new/inotify-tools-3.20.11.0/t/inotifywait-no-dereference-ignore-symlinked-file.t
--- 
old/inotify-tools-3.20.2.2/t/inotifywait-no-dereference-ignore-symlinked-file.t 
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/inotify-tools-3.20.11.0/t/inotifywait-no-dereference-ignore-symlinked-file.t
    2020-11-13 11:52:25.000000000 +0100
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+test_description='--no-dereference causes inotifywait to ignore events on 
symlink target'
+
+. ./sharness.sh
+
+run_() {
+    export LD_LIBRARY_PATH="../../libinotifytools/src/.libs/"
+    touch test &&
+       ln -s test test-symlink &&
+       {(sleep 1 && touch test)&} &&
+    ../../src/.libs/inotifywait --quiet --no-dereference --timeout 2 
test-symlink
+}
+
+test_expect_success 'Exit code 2 is returned' '
+    test_expect_code 2 run_
+'
+
+test_done
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/inotify-tools-3.20.2.2/t/inotifywait-no-dereference-respond-to-symlink-event.t
 
new/inotify-tools-3.20.11.0/t/inotifywait-no-dereference-respond-to-symlink-event.t
--- 
old/inotify-tools-3.20.2.2/t/inotifywait-no-dereference-respond-to-symlink-event.t
  1970-01-01 01:00:00.000000000 +0100
+++ 
new/inotify-tools-3.20.11.0/t/inotifywait-no-dereference-respond-to-symlink-event.t
 2020-11-13 11:52:25.000000000 +0100
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+test_description='--no-dereference causes inotifywait to respond to events on 
symlink'
+
+. ./sharness.sh
+
+run_() {
+    export LD_LIBRARY_PATH="../../libinotifytools/src/.libs/"
+    touch test &&
+       ln -s test test-symlink &&
+       {(sleep 1 && touch -h test-symlink)&} &&
+    ../../src/.libs/inotifywait --quiet --no-dereference --timeout 2 
test-symlink
+}
+
+test_expect_success 'Exit code 0 is returned' '
+    run_
+'
+
+test_done
_______________________________________________
openSUSE Commits mailing list -- [email protected]
To unsubscribe, email [email protected]
List Netiquette: https://en.opensuse.org/openSUSE:Mailing_list_netiquette
List Archives: 
https://lists.opensuse.org/archives/list/[email protected]

Reply via email to