Compare commits
10 commits
7fd6727a6e
...
45f455831c
Author | SHA1 | Date | |
---|---|---|---|
45f455831c | |||
7e7766d82f | |||
41096516d1 | |||
e1bdbe22a9 | |||
cb2e838cdf | |||
5a3ffa62e4 | |||
78f6df128a | |||
e0b768a929 | |||
cf2ff376d6 | |||
cadd0aacb5 |
18 changed files with 825 additions and 887 deletions
2
.dockerignore
Normal file
2
.dockerignore
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
_release
|
||||||
|
_debug
|
24
.github/workflows/ci.yaml
vendored
24
.github/workflows/ci.yaml
vendored
|
@ -9,6 +9,14 @@ concurrency:
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- run: sudo apt-get install -y make clang-format
|
||||||
|
- run: make lint
|
||||||
|
- run: git diff --exit-code
|
||||||
|
|
||||||
build-with-gcc:
|
build-with-gcc:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
@ -16,29 +24,35 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with: {fetch-depth: 0}
|
||||||
- run: sudo apt-get install -y build-essential
|
- run: sudo apt-get install -y build-essential
|
||||||
- run: make CFG=${{ matrix.cfg}} -j$(nproc)
|
- run: make VERBOSE=1 CFG=${{ matrix.cfg}} -j$(nproc)
|
||||||
- run: _${{ matrix.cfg }}/inotify-info
|
- run: |
|
||||||
|
_${{ matrix.cfg }}/inotify-info --version
|
||||||
|
_${{ matrix.cfg }}/inotify-info
|
||||||
|
|
||||||
build-with-zig:
|
build-with-zig:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with: {fetch-depth: 0}
|
||||||
- uses: actions/cache@v4
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
key: zig-sdk-and-cache-${{ hashFiles('.github/workflows/ci.yaml') }}
|
key: zig-sdk-and-cache-${{ hashFiles('.github/workflows/ci.yaml') }}
|
||||||
path: ~/.cache/zig
|
path: ~/.cache/zig
|
||||||
- run: |
|
- run: |
|
||||||
wget --progress=dot:mega \
|
wget --progress=dot:mega \
|
||||||
https://ziglang.org/download/0.11.0/zig-linux-$(uname -m)-0.11.0.tar.xz
|
https://ziglang.org/download/0.13.0/zig-linux-$(uname -m)-0.13.0.tar.xz
|
||||||
tar -xJf zig-linux-*.tar.xz
|
tar -xJf zig-linux-*.tar.xz
|
||||||
rm zig-linux-*.xz
|
rm zig-linux-*.xz
|
||||||
mv zig-linux-* zig-sdk
|
mv zig-linux-* zig-sdk
|
||||||
- run: |
|
- run: |
|
||||||
make -j$(nproc) \
|
make VERBOSE=1 -j$(nproc) \
|
||||||
CC="zig-sdk/zig cc -target $(uname -m)-linux-musl" \
|
CC="zig-sdk/zig cc -target $(uname -m)-linux-musl" \
|
||||||
CXX="zig-sdk/zig c++ -target $(uname -m)-linux-musl"
|
CXX="zig-sdk/zig c++ -target $(uname -m)-linux-musl"
|
||||||
- run: _release/inotify-info
|
- run: |
|
||||||
|
_release/inotify-info --version
|
||||||
|
_release/inotify-info
|
||||||
|
|
||||||
build-with-docker:
|
build-with-docker:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
5
.github/workflows/release.yaml
vendored
5
.github/workflows/release.yaml
vendored
|
@ -8,15 +8,10 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Archive
|
|
||||||
run: make inotify-info-${{ github.ref_name }}.tar.gz
|
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2
|
||||||
if: startsWith(github.ref, 'refs/tags/v')
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
with:
|
with:
|
||||||
files: inotify-info-${{ github.ref_name }}.tar.gz
|
|
||||||
generate_release_notes: true
|
generate_release_notes: true
|
||||||
draft: true
|
draft: true
|
||||||
prerelease: true
|
prerelease: true
|
||||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,4 +1,4 @@
|
||||||
_debug/
|
_debug/
|
||||||
_release/
|
_release/
|
||||||
|
|
||||||
/inotify-info-v*.tar.gz
|
/inotify-info-*.tar.gz
|
||||||
|
|
19
Dockerfile
19
Dockerfile
|
@ -1,23 +1,14 @@
|
||||||
FROM alpine
|
FROM alpine:edge
|
||||||
|
|
||||||
# zig is installed from the upstream tarball, because:
|
RUN apk add make zig git
|
||||||
# - as of writing, alpine has zig only in testing (which is cumbersome to use)
|
|
||||||
# - apk get zig pulls in libllvm, which is huge.
|
|
||||||
#
|
|
||||||
# Upstream tarball is statically linked, making it small and convenient to use.
|
|
||||||
RUN apk add make \
|
|
||||||
&& wget https://ziglang.org/download/0.11.0/zig-linux-$(uname -m)-0.11.0.tar.xz \
|
|
||||||
&& tar -xJf zig-linux-*.tar.xz \
|
|
||||||
&& rm zig-linux-*.xz \
|
|
||||||
&& mv zig-linux-* zig
|
|
||||||
|
|
||||||
WORKDIR inotify-info
|
WORKDIR inotify-info
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
RUN CC="/zig/zig cc -target $(uname -m)-linux-musl" \
|
RUN CC="zig cc -target $(uname -m)-linux-musl" \
|
||||||
CXX="/zig/zig c++ -target $(uname -m)-linux-musl" \
|
CXX="zig c++ -target $(uname -m)-linux-musl" \
|
||||||
make
|
make VERBOSE=1
|
||||||
|
|
||||||
FROM scratch
|
FROM scratch
|
||||||
COPY --from=0 /inotify-info/_release/inotify-info /inotify-info
|
COPY --from=0 /inotify-info/_release/inotify-info /inotify-info
|
||||||
|
|
42
Makefile
42
Makefile
|
@ -20,11 +20,16 @@ ifeq ($(CFG), debug)
|
||||||
ASAN ?= 1
|
ASAN ?= 1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
PREFIX ?= /usr/local
|
||||||
|
BINDIR := $(PREFIX)/bin
|
||||||
|
|
||||||
LD = $(CC)
|
LD = $(CC)
|
||||||
RM = rm -f
|
RM = rm -f
|
||||||
MKDIR = mkdir -p
|
MKDIR = mkdir -p
|
||||||
VERBOSE ?= 0
|
VERBOSE ?= 0
|
||||||
|
|
||||||
|
INOTIFYINFO_VERSION ?= $(shell git describe --tags --dirty 2>/dev/null || echo unknown)
|
||||||
|
|
||||||
COMPILER = $(shell $(CC) -v 2>&1 | grep -q "clang version" && echo clang || echo gcc)
|
COMPILER = $(shell $(CC) -v 2>&1 | grep -q "clang version" && echo clang || echo gcc)
|
||||||
|
|
||||||
WARNINGS = -Wall -Wextra -Wpedantic -Wmissing-include-dirs -Wformat=2 -Wshadow
|
WARNINGS = -Wall -Wextra -Wpedantic -Wmissing-include-dirs -Wformat=2 -Wshadow
|
||||||
|
@ -33,10 +38,15 @@ ifneq ($(COMPILER),clang)
|
||||||
WARNINGS += -Wsuggest-attribute=format -Wall
|
WARNINGS += -Wsuggest-attribute=format -Wall
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CFLAGS = $(WARNINGS) -march=native -fno-exceptions -gdwarf-4 -g2 -ggnu-pubnames -gsplit-dwarf
|
DEFINES = -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64
|
||||||
CFLAGS += -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64
|
DEFINES += -DINOTIFYINFO_VERSION=\"$(INOTIFYINFO_VERSION)\"
|
||||||
CXXFLAGS = -fno-rtti -Woverloaded-virtual
|
|
||||||
LDFLAGS = -march=native -gdwarf-4 -g2 -Wl,--build-id=sha1
|
CFLAGS += $(WARNINGS) $(DEFINES)
|
||||||
|
CFLAGS += -std=gnu99 -fno-exceptions
|
||||||
|
|
||||||
|
CXXFLAGS += $(WARNINGS) $(DEFINES)
|
||||||
|
CXXFLAGS += -std=c++11 -fno-exceptions -fno-rtti -Woverloaded-virtual
|
||||||
|
|
||||||
LIBS = -Wl,--no-as-needed -lm -ldl -lpthread -lstdc++
|
LIBS = -Wl,--no-as-needed -lm -ldl -lpthread -lstdc++
|
||||||
|
|
||||||
CFILES = \
|
CFILES = \
|
||||||
|
@ -59,6 +69,7 @@ ifeq ($(ASAN), 1)
|
||||||
ASAN_FLAGS += -fsanitize=object-size # enable object size checking, detect various out-of-bounds accesses.
|
ASAN_FLAGS += -fsanitize=object-size # enable object size checking, detect various out-of-bounds accesses.
|
||||||
ASAN_FLAGS += -fsanitize=alignment # enable alignment checking, detect various misaligned objects;
|
ASAN_FLAGS += -fsanitize=alignment # enable alignment checking, detect various misaligned objects;
|
||||||
CFLAGS += $(ASAN_FLAGS)
|
CFLAGS += $(ASAN_FLAGS)
|
||||||
|
CXXFLAGS += $(ASAN_FLAGS)
|
||||||
LDFLAGS += $(ASAN_FLAGS)
|
LDFLAGS += $(ASAN_FLAGS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -72,7 +83,6 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
PROJ = $(ODIR)/$(NAME)
|
PROJ = $(ODIR)/$(NAME)
|
||||||
$(info Building $(ODIR)/$(NAME)...)
|
|
||||||
|
|
||||||
ifeq ($(VERBOSE), 1)
|
ifeq ($(VERBOSE), 1)
|
||||||
VERBOSE_PREFIX=
|
VERBOSE_PREFIX=
|
||||||
|
@ -94,12 +104,16 @@ $(ODIR)/$(NAME): $(OBJS)
|
||||||
$(ODIR)/%.o: %.c Makefile
|
$(ODIR)/%.o: %.c Makefile
|
||||||
$(VERBOSE_PREFIX)echo "---- $< ----";
|
$(VERBOSE_PREFIX)echo "---- $< ----";
|
||||||
@$(MKDIR) $(dir $@)
|
@$(MKDIR) $(dir $@)
|
||||||
$(VERBOSE_PREFIX)$(CC) -MMD -MP -std=gnu99 $(CFLAGS) -o $@ -c $<
|
$(VERBOSE_PREFIX)$(CC) -MMD -MP $(CFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
$(ODIR)/%.o: %.cpp Makefile
|
$(ODIR)/%.o: %.cpp Makefile
|
||||||
$(VERBOSE_PREFIX)echo "---- $< ----";
|
$(VERBOSE_PREFIX)echo "---- $< ----";
|
||||||
@$(MKDIR) $(dir $@)
|
@$(MKDIR) $(dir $@)
|
||||||
$(VERBOSE_PREFIX)$(CXX) -MMD -MP -std=c++11 $(CFLAGS) $(CXXFLAGS) -o $@ -c $<
|
$(VERBOSE_PREFIX)$(CXX) -MMD -MP $(CXXFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
|
.PHONY: lint
|
||||||
|
lint:
|
||||||
|
find . -name '*.h' -o -name '*.c' -o -name '*.cpp' | xargs clang-format -i --style=webkit
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
|
||||||
|
@ -110,8 +124,18 @@ clean:
|
||||||
$(VERBOSE_PREFIX)$(RM) $(OBJS:.o=.d)
|
$(VERBOSE_PREFIX)$(RM) $(OBJS:.o=.d)
|
||||||
$(VERBOSE_PREFIX)$(RM) $(OBJS:.o=.dwo)
|
$(VERBOSE_PREFIX)$(RM) $(OBJS:.o=.dwo)
|
||||||
|
|
||||||
|
.PHONY: install
|
||||||
|
|
||||||
|
install: all
|
||||||
|
install -D $(PROJ) $(BINDIR)/$(NAME)
|
||||||
|
|
||||||
|
.PHONY: uninstall
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
$(RM) $(BINDIR)/$(NAME)
|
||||||
|
|
||||||
define RELEASE_RULES
|
define RELEASE_RULES
|
||||||
inotify-info-$(TAG).tar.gz:
|
inotify-info-$(TAG).tar.gz:
|
||||||
git archive --prefix=inotify-info-$(TAG)/ $(TAG) | gzip -n > $$@
|
git archive --prefix=inotify-info-$(TAG)/ v$(TAG) | gzip -n > $$@
|
||||||
endef
|
endef
|
||||||
$(foreach TAG,$(shell git tag 2>/dev/null),$(eval $(RELEASE_RULES)))
|
$(foreach TAG,$(shell git tag 2>/dev/null | sed -n '/^v/ s/^v//p'),$(eval $(RELEASE_RULES)))
|
||||||
|
|
21
README.md
21
README.md
|
@ -22,17 +22,11 @@ Building _debug/inotify-info...
|
||||||
Linking _debug/inotify-info...
|
Linking _debug/inotify-info...
|
||||||
```
|
```
|
||||||
|
|
||||||
Or you can build Docker image.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
docker build . -t inotify-info
|
|
||||||
```
|
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
You are free to copy the resulting executable to any suitable location in your `$PATH`.
|
|
||||||
```
|
The resulting executable will be at `_release/inotify-info`. You are free to
|
||||||
cp _release/inotify-info /usr/local/bin/
|
copy the resulting executable to any suitable location in your `$PATH` or run
|
||||||
```
|
`make install` to install to `/usr/local/bin`.
|
||||||
|
|
||||||
## Run (Prints Summary)
|
## Run (Prints Summary)
|
||||||
```
|
```
|
||||||
|
@ -160,12 +154,16 @@ Searching '/' for listed inodes... (8 threads)
|
||||||
94111468 [10304h] /home/mikesart/.cache/xfce4/xfce4-appfinder/
|
94111468 [10304h] /home/mikesart/.cache/xfce4/xfce4-appfinder/
|
||||||
```
|
```
|
||||||
|
|
||||||
## Run on Docker
|
## Run on Docker/podman
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
docker build . -t inotify-info
|
||||||
docker run --rm --privileged -v /proc:/proc inotify-info
|
docker run --rm --privileged -v /proc:/proc inotify-info
|
||||||
```
|
```
|
||||||
|
|
||||||
|
When running under [podman][podman] non-root mode, append `--ulimit
|
||||||
|
nofile=65535:65535` to the `podman build` command.
|
||||||
|
|
||||||
## Run on Nix(OS)
|
## Run on Nix(OS)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -181,3 +179,4 @@ nix run nixpkgs#inotify-info
|
||||||
[problem2]: https://unix.stackexchange.com/questions/15509/whos-consuming-my-inotify-resources
|
[problem2]: https://unix.stackexchange.com/questions/15509/whos-consuming-my-inotify-resources
|
||||||
[lfqueue]: https://github.com/Taymindis/lfqueue
|
[lfqueue]: https://github.com/Taymindis/lfqueue
|
||||||
[bsd]: https://github.com/Taymindis/lfqueue/blob/master/LICENSE
|
[bsd]: https://github.com/Taymindis/lfqueue/blob/master/LICENSE
|
||||||
|
[podman]: https://podman.io/
|
||||||
|
|
20
debian/changelog
vendored
20
debian/changelog
vendored
|
@ -1,3 +1,23 @@
|
||||||
|
inotify-info (0.0.3-1) sid; urgency=medium
|
||||||
|
|
||||||
|
* Uploading to sid.
|
||||||
|
* Merging upstream version 0.0.3.
|
||||||
|
* Removing manual debhelper install file, not needed anymore with new
|
||||||
|
upstream version.
|
||||||
|
* Enabling non-silent output during build.
|
||||||
|
|
||||||
|
-- Daniel Baumann <daniel.baumann@progress-linux.org> Sat, 13 Jul 2024 13:02:30 +0200
|
||||||
|
|
||||||
|
inotify-info (0.0.2-1) sid; urgency=medium
|
||||||
|
|
||||||
|
* Uploading to sid.
|
||||||
|
* Merging upstream version 0.0.2.
|
||||||
|
* Removing march.patch, not needed anymore.
|
||||||
|
* Removing dwz.patch, not needed anymore.
|
||||||
|
* Setting INOTIFYINFO_VERSION to debian package version.
|
||||||
|
|
||||||
|
-- Daniel Baumann <daniel.baumann@progress-linux.org> Mon, 03 Jun 2024 22:01:31 +0200
|
||||||
|
|
||||||
inotify-info (0.0.1-2) sid; urgency=medium
|
inotify-info (0.0.1-2) sid; urgency=medium
|
||||||
|
|
||||||
* Uploading to sid.
|
* Uploading to sid.
|
||||||
|
|
2
debian/copyright
vendored
2
debian/copyright
vendored
|
@ -1,7 +1,7 @@
|
||||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
Upstream-Name: inotify-info
|
Upstream-Name: inotify-info
|
||||||
Upstream-Contact: https://github.com/mikesart/inotify-info/issues
|
Upstream-Contact: https://github.com/mikesart/inotify-info/issues
|
||||||
Source: https://github.com/mikesart/inotify-info/releases
|
Source: https://github.com/mikesart/inotify-info/tags
|
||||||
|
|
||||||
Files: *
|
Files: *
|
||||||
Copyright: 2021 Michael Sartain <mikesart@fastmail.com>
|
Copyright: 2021 Michael Sartain <mikesart@fastmail.com>
|
||||||
|
|
1
debian/inotify-info.install
vendored
1
debian/inotify-info.install
vendored
|
@ -1 +0,0 @@
|
||||||
_release/inotify-info /usr/bin
|
|
19
debian/patches/debian/0001-march.patch
vendored
19
debian/patches/debian/0001-march.patch
vendored
|
@ -1,19 +0,0 @@
|
||||||
Author: Daniel Baumann <daniel.baumann@progress-linux.org>
|
|
||||||
Description: Building without -march=native (Closes: #1071076).
|
|
||||||
|
|
||||||
diff -Naurp inotify-info.orig/Makefile inotify-info/Makefile
|
|
||||||
--- inotify-info.orig/Makefile
|
|
||||||
+++ inotify-info/Makefile
|
|
||||||
@@ -33,10 +33,10 @@ ifneq ($(COMPILER),clang)
|
|
||||||
WARNINGS += -Wsuggest-attribute=format -Wall
|
|
||||||
endif
|
|
||||||
|
|
||||||
-CFLAGS = $(WARNINGS) -march=native -fno-exceptions -gdwarf-4 -g2 -ggnu-pubnames -gsplit-dwarf
|
|
||||||
+CFLAGS = $(WARNINGS) -fno-exceptions -gdwarf-4 -g2 -ggnu-pubnames -gsplit-dwarf
|
|
||||||
CFLAGS += -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64
|
|
||||||
CXXFLAGS = -fno-rtti -Woverloaded-virtual
|
|
||||||
-LDFLAGS = -march=native -gdwarf-4 -g2 -Wl,--build-id=sha1
|
|
||||||
+LDFLAGS = -gdwarf-4 -g2 -Wl,--build-id=sha1
|
|
||||||
LIBS = -Wl,--no-as-needed -lm -ldl -lpthread -lstdc++
|
|
||||||
|
|
||||||
CFILES = \
|
|
15
debian/patches/debian/0002-dwz.patch
vendored
15
debian/patches/debian/0002-dwz.patch
vendored
|
@ -1,15 +0,0 @@
|
||||||
Author: Daniel Baumann <daniel.baumann@progress-linux.org>
|
|
||||||
Description: Building without -gsplit-dwarf to workaround bug in dwz causing FTBFS (#1016936).
|
|
||||||
|
|
||||||
diff -Naurp inotify-info.orig/Makefile inotify-info/Makefile
|
|
||||||
--- inotify-info.orig/Makefile
|
|
||||||
+++ inotify-info/Makefile
|
|
||||||
@@ -33,7 +33,7 @@ ifneq ($(COMPILER),clang)
|
|
||||||
WARNINGS += -Wsuggest-attribute=format -Wall
|
|
||||||
endif
|
|
||||||
|
|
||||||
-CFLAGS = $(WARNINGS) -fno-exceptions -gdwarf-4 -g2 -ggnu-pubnames -gsplit-dwarf
|
|
||||||
+CFLAGS = $(WARNINGS) -fno-exceptions -gdwarf-4 -g2 -ggnu-pubnames
|
|
||||||
CFLAGS += -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64
|
|
||||||
CXXFLAGS = -fno-rtti -Woverloaded-virtual
|
|
||||||
LDFLAGS = -gdwarf-4 -g2 -Wl,--build-id=sha1
|
|
2
debian/patches/series
vendored
2
debian/patches/series
vendored
|
@ -1,2 +0,0 @@
|
||||||
debian/0001-march.patch
|
|
||||||
debian/0002-dwz.patch
|
|
8
debian/rules
vendored
8
debian/rules
vendored
|
@ -1,7 +1,15 @@
|
||||||
#!/usr/bin/make -f
|
#!/usr/bin/make -f
|
||||||
|
|
||||||
|
export INOTIFYINFO_VERSION = $(shell dpkg-parsechangelog -SVersion)
|
||||||
|
|
||||||
%:
|
%:
|
||||||
dh ${@}
|
dh ${@}
|
||||||
|
|
||||||
execute_after_dh_auto_clean:
|
execute_after_dh_auto_clean:
|
||||||
rm -rf _release
|
rm -rf _release
|
||||||
|
|
||||||
|
override_dh_auto_build:
|
||||||
|
dh_auto_build -- VERBOSE=1
|
||||||
|
|
||||||
|
override_dh_auto_install:
|
||||||
|
dh_auto_install -- PREFIX=$(CURDIR)/debian/inotify-info/usr
|
||||||
|
|
359
inotify-info.cpp
359
inotify-info.cpp
|
@ -24,34 +24,38 @@
|
||||||
|
|
||||||
#define _GNU_SOURCE 1
|
#define _GNU_SOURCE 1
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <locale.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <libgen.h>
|
|
||||||
#include <locale.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/statfs.h>
|
||||||
|
#include <sys/sysmacros.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <syscall.h>
|
#include <syscall.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/sysmacros.h>
|
|
||||||
#include <sys/statfs.h>
|
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <unordered_set>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "inotify-info.h"
|
#include "inotify-info.h"
|
||||||
#include "lfqueue/lfqueue.h"
|
#include "lfqueue/lfqueue.h"
|
||||||
|
|
||||||
|
#ifndef INOTIFYINFO_VERSION
|
||||||
|
#error INOTIFYINFO_VERSION must be set
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO
|
* TODO
|
||||||
* - Comments
|
* - Comments
|
||||||
|
@ -77,8 +81,7 @@ static std::vector< std::string > ignore_dirs;
|
||||||
/*
|
/*
|
||||||
* filename info
|
* filename info
|
||||||
*/
|
*/
|
||||||
struct filename_info_t
|
struct filename_info_t {
|
||||||
{
|
|
||||||
ino64_t inode; // Inode number
|
ino64_t inode; // Inode number
|
||||||
dev_t dev; // Device ID containing file
|
dev_t dev; // Device ID containing file
|
||||||
std::string filename;
|
std::string filename;
|
||||||
|
@ -87,8 +90,7 @@ struct filename_info_t
|
||||||
/*
|
/*
|
||||||
* inotify process info
|
* inotify process info
|
||||||
*/
|
*/
|
||||||
struct procinfo_t
|
struct procinfo_t {
|
||||||
{
|
|
||||||
pid_t pid = 0;
|
pid_t pid = 0;
|
||||||
|
|
||||||
// uid
|
// uid
|
||||||
|
@ -114,8 +116,7 @@ struct procinfo_t
|
||||||
std::unordered_map<dev_t, std::unordered_set<ino64_t>> dev_map;
|
std::unordered_map<dev_t, std::unordered_set<ino64_t>> dev_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
class lfqueue_wrapper_t
|
class lfqueue_wrapper_t {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
lfqueue_wrapper_t() { lfqueue_init(&queue); }
|
lfqueue_wrapper_t() { lfqueue_init(&queue); }
|
||||||
~lfqueue_wrapper_t() { lfqueue_destroy(&queue); }
|
~lfqueue_wrapper_t() { lfqueue_destroy(&queue); }
|
||||||
|
@ -126,8 +127,7 @@ public:
|
||||||
public:
|
public:
|
||||||
typedef long long my_m256i __attribute__((__vector_size__(32), __aligned__(32)));
|
typedef long long my_m256i __attribute__((__vector_size__(32), __aligned__(32)));
|
||||||
|
|
||||||
union
|
union {
|
||||||
{
|
|
||||||
lfqueue_t queue;
|
lfqueue_t queue;
|
||||||
my_m256i align_buf[4]; // Align to 128 bytes
|
my_m256i align_buf[4]; // Align to 128 bytes
|
||||||
};
|
};
|
||||||
|
@ -136,8 +136,7 @@ public:
|
||||||
/*
|
/*
|
||||||
* shared thread data
|
* shared thread data
|
||||||
*/
|
*/
|
||||||
class thread_shared_data_t
|
class thread_shared_data_t {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
bool init(uint32_t numthreads, const std::vector<procinfo_t>& inotify_proclist);
|
bool init(uint32_t numthreads, const std::vector<procinfo_t>& inotify_proclist);
|
||||||
|
|
||||||
|
@ -151,10 +150,12 @@ public:
|
||||||
/*
|
/*
|
||||||
* thread info
|
* thread info
|
||||||
*/
|
*/
|
||||||
class thread_info_t
|
class thread_info_t {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
thread_info_t( thread_shared_data_t &tdata_in ) : tdata( tdata_in ) {}
|
thread_info_t(thread_shared_data_t& tdata_in)
|
||||||
|
: tdata(tdata_in)
|
||||||
|
{
|
||||||
|
}
|
||||||
~thread_info_t() { }
|
~thread_info_t() { }
|
||||||
|
|
||||||
void queue_directory(char* path);
|
void queue_directory(char* path);
|
||||||
|
@ -181,8 +182,7 @@ public:
|
||||||
* getdents64 syscall
|
* getdents64 syscall
|
||||||
*/
|
*/
|
||||||
GCC_DIAG_PUSH_OFF(pedantic)
|
GCC_DIAG_PUSH_OFF(pedantic)
|
||||||
struct linux_dirent64
|
struct linux_dirent64 {
|
||||||
{
|
|
||||||
uint64_t d_ino; // Inode number
|
uint64_t d_ino; // Inode number
|
||||||
int64_t d_off; // Offset to next linux_dirent
|
int64_t d_off; // Offset to next linux_dirent
|
||||||
unsigned short d_reclen; // Length of this linux_dirent
|
unsigned short d_reclen; // Length of this linux_dirent
|
||||||
|
@ -209,13 +209,11 @@ std::string string_formatv( const char *fmt, va_list ap )
|
||||||
std::string str;
|
std::string str;
|
||||||
int size = 512;
|
int size = 512;
|
||||||
|
|
||||||
for ( ;; )
|
for (;;) {
|
||||||
{
|
|
||||||
str.resize(size);
|
str.resize(size);
|
||||||
int n = vsnprintf((char*)str.c_str(), size, fmt, ap);
|
int n = vsnprintf((char*)str.c_str(), size, fmt, ap);
|
||||||
|
|
||||||
if ( ( n > -1 ) && ( n < size ) )
|
if ((n > -1) && (n < size)) {
|
||||||
{
|
|
||||||
str.resize(n);
|
str.resize(n);
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
@ -242,8 +240,7 @@ static std::string get_link_name( const char *pathname )
|
||||||
char filename[PATH_MAX + 1];
|
char filename[PATH_MAX + 1];
|
||||||
|
|
||||||
ssize_t ret = readlink(pathname, filename, sizeof(filename));
|
ssize_t ret = readlink(pathname, filename, sizeof(filename));
|
||||||
if ( ( ret > 0 ) && ( ret < ( ssize_t )sizeof( filename ) ) )
|
if ((ret > 0) && (ret < (ssize_t)sizeof(filename))) {
|
||||||
{
|
|
||||||
filename[ret] = 0;
|
filename[ret] = 0;
|
||||||
Result = filename;
|
Result = filename;
|
||||||
}
|
}
|
||||||
|
@ -254,8 +251,7 @@ static uid_t get_uid(const char *pathname)
|
||||||
{
|
{
|
||||||
int fd = open(pathname, O_RDONLY, 0);
|
int fd = open(pathname, O_RDONLY, 0);
|
||||||
|
|
||||||
if ( fd >= 0 )
|
if (fd >= 0) {
|
||||||
{
|
|
||||||
char buf[16 * 1024];
|
char buf[16 * 1024];
|
||||||
|
|
||||||
ssize_t len = read(fd, buf, sizeof(buf));
|
ssize_t len = read(fd, buf, sizeof(buf));
|
||||||
|
@ -263,13 +259,11 @@ static uid_t get_uid(const char *pathname)
|
||||||
close(fd);
|
close(fd);
|
||||||
fd = -1;
|
fd = -1;
|
||||||
|
|
||||||
if ( len > 0 )
|
if (len > 0) {
|
||||||
{
|
|
||||||
buf[len - 1] = 0;
|
buf[len - 1] = 0;
|
||||||
|
|
||||||
const char* uidstr = strstr(buf, "\nUid:");
|
const char* uidstr = strstr(buf, "\nUid:");
|
||||||
if ( uidstr )
|
if (uidstr) {
|
||||||
{
|
|
||||||
return atoll(uidstr + 5);
|
return atoll(uidstr + 5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -290,14 +284,12 @@ static uint32_t inotify_parse_fdinfo_file( procinfo_t &procinfo, const char *fds
|
||||||
uint32_t watch_count = 0;
|
uint32_t watch_count = 0;
|
||||||
|
|
||||||
FILE* fp = fopen(fdset_name, "r");
|
FILE* fp = fopen(fdset_name, "r");
|
||||||
if ( fp )
|
if (fp) {
|
||||||
{
|
|
||||||
char line_buf[256];
|
char line_buf[256];
|
||||||
|
|
||||||
procinfo.fdset_filenames.push_back(fdset_name);
|
procinfo.fdset_filenames.push_back(fdset_name);
|
||||||
|
|
||||||
for ( ;; )
|
for (;;) {
|
||||||
{
|
|
||||||
if (!fgets(line_buf, sizeof(line_buf), fp))
|
if (!fgets(line_buf, sizeof(line_buf), fp))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -309,15 +301,13 @@ static uint32_t inotify_parse_fdinfo_file( procinfo_t &procinfo, const char *fds
|
||||||
* ino: 5865
|
* ino: 5865
|
||||||
* inotify wd:1 ino:80001 sdev:800011 mask:100 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:01000800bc1b8c7c
|
* inotify wd:1 ino:80001 sdev:800011 mask:100 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:01000800bc1b8c7c
|
||||||
*/
|
*/
|
||||||
if ( !strncmp( line_buf, "inotify ", 8 ) )
|
if (!strncmp(line_buf, "inotify ", 8)) {
|
||||||
{
|
|
||||||
watch_count++;
|
watch_count++;
|
||||||
|
|
||||||
uint64_t inode_val = get_token_val(line_buf, "ino:");
|
uint64_t inode_val = get_token_val(line_buf, "ino:");
|
||||||
uint64_t sdev_val = get_token_val(line_buf, "sdev:");
|
uint64_t sdev_val = get_token_val(line_buf, "sdev:");
|
||||||
|
|
||||||
if ( inode_val )
|
if (inode_val) {
|
||||||
{
|
|
||||||
// https://unix.stackexchange.com/questions/645937/listing-the-files-that-are-being-watched-by-inotify-instances
|
// https://unix.stackexchange.com/questions/645937/listing-the-files-that-are-being-watched-by-inotify-instances
|
||||||
// Assuming that the sdev field is encoded according to Linux's so-called "huge
|
// Assuming that the sdev field is encoded according to Linux's so-called "huge
|
||||||
// encoding", which uses 20 bits (instead of 8) for minor numbers, in bitwise
|
// encoding", which uses 20 bits (instead of 8) for minor numbers, in bitwise
|
||||||
|
@ -345,19 +335,16 @@ static void inotify_parse_fddir( procinfo_t &procinfo )
|
||||||
if (!dir_fd)
|
if (!dir_fd)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for ( ;; )
|
for (;;) {
|
||||||
{
|
|
||||||
struct dirent* dp_fd = readdir(dir_fd);
|
struct dirent* dp_fd = readdir(dir_fd);
|
||||||
if (!dp_fd)
|
if (!dp_fd)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if ( ( dp_fd->d_type == DT_LNK ) && isdigit( dp_fd->d_name[ 0 ] ) )
|
if ((dp_fd->d_type == DT_LNK) && isdigit(dp_fd->d_name[0])) {
|
||||||
{
|
|
||||||
filename = string_format("/proc/%d/fd/%s", procinfo.pid, dp_fd->d_name);
|
filename = string_format("/proc/%d/fd/%s", procinfo.pid, dp_fd->d_name);
|
||||||
filename = get_link_name(filename.c_str());
|
filename = get_link_name(filename.c_str());
|
||||||
|
|
||||||
if ( filename == "anon_inode:inotify" || filename == "inotify" )
|
if (filename == "anon_inode:inotify" || filename == "inotify") {
|
||||||
{
|
|
||||||
filename = string_format("/proc/%d/fdinfo/%s", procinfo.pid, dp_fd->d_name);
|
filename = string_format("/proc/%d/fdinfo/%s", procinfo.pid, dp_fd->d_name);
|
||||||
|
|
||||||
procinfo.instances++;
|
procinfo.instances++;
|
||||||
|
@ -381,11 +368,9 @@ char *thread_info_t::dequeue_directory()
|
||||||
{
|
{
|
||||||
char* path = tdata.dirqueues[idx].dequeue_directory();
|
char* path = tdata.dirqueues[idx].dequeue_directory();
|
||||||
|
|
||||||
if ( !path )
|
if (!path) {
|
||||||
{
|
|
||||||
// Nothing on our queue, check queues on other threads
|
// Nothing on our queue, check queues on other threads
|
||||||
for ( lfqueue_wrapper_t &dirq : tdata.dirqueues )
|
for (lfqueue_wrapper_t& dirq : tdata.dirqueues) {
|
||||||
{
|
|
||||||
path = dirq.dequeue_directory();
|
path = dirq.dequeue_directory();
|
||||||
if (path)
|
if (path)
|
||||||
break;
|
break;
|
||||||
|
@ -403,9 +388,8 @@ struct statx mystatx( const char *filename, unsigned int mask = 0 )
|
||||||
struct statx statxbuf;
|
struct statx statxbuf;
|
||||||
int flags = AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | AT_STATX_DONT_SYNC;
|
int flags = AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | AT_STATX_DONT_SYNC;
|
||||||
|
|
||||||
if ( statx( 0, filename, flags, mask, &statxbuf ) == -1 )
|
if (statx(0, filename, flags, mask, &statxbuf) == -1) {
|
||||||
{
|
printf("ERROR: statx-ino( %s ) failed. Errno: %d (%s)\n", filename, errno, strerror(errno));
|
||||||
printf( "ERROR: statx-ino( %s ) failed. Errno: %d\n", filename, errno );
|
|
||||||
memset(&statxbuf, 0, sizeof(statxbuf));
|
memset(&statxbuf, 0, sizeof(statxbuf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,9 +417,8 @@ static dev_t stat_get_dev_t( const char *filename )
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
|
|
||||||
int ret = stat(filename, &statbuf);
|
int ret = stat(filename, &statbuf);
|
||||||
if ( ret == -1 )
|
if (ret == -1) {
|
||||||
{
|
printf("ERROR: stat-dev_t( %s ) failed. Errno: %d (%s)\n", filename, errno, strerror(errno));
|
||||||
printf( "ERROR: stat-dev_t( %s ) failed. Errno: %d\n", filename, errno );
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return statbuf.st_dev;
|
return statbuf.st_dev;
|
||||||
|
@ -446,9 +429,8 @@ static uint64_t stat_get_ino( const char *filename )
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
|
|
||||||
int ret = stat(filename, &statbuf);
|
int ret = stat(filename, &statbuf);
|
||||||
if ( ret == -1 )
|
if (ret == -1) {
|
||||||
{
|
printf("ERROR: stat-ino( %s ) failed. Errno: %d (%s)\n", filename, errno, strerror(errno));
|
||||||
printf( "ERROR: stat-ino( %s ) failed. Errno: %d\n", filename, errno );
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,16 +443,14 @@ void thread_info_t::add_filename( ino64_t inode, const char *path, const char *d
|
||||||
{
|
{
|
||||||
auto it = tdata.inode_set.find(inode);
|
auto it = tdata.inode_set.find(inode);
|
||||||
|
|
||||||
if ( it != tdata.inode_set.end() )
|
if (it != tdata.inode_set.end()) {
|
||||||
{
|
|
||||||
const std::unordered_set<dev_t>& dev_set = it->second;
|
const std::unordered_set<dev_t>& dev_set = it->second;
|
||||||
|
|
||||||
std::string filename = std::string(path) + d_name;
|
std::string filename = std::string(path) + d_name;
|
||||||
dev_t dev = stat_get_dev_t(filename.c_str());
|
dev_t dev = stat_get_dev_t(filename.c_str());
|
||||||
|
|
||||||
// Make sure the inode AND device ID match before adding.
|
// Make sure the inode AND device ID match before adding.
|
||||||
if ( dev_set.find( dev ) != dev_set.end() )
|
if (dev_set.find(dev) != dev_set.end()) {
|
||||||
{
|
|
||||||
filename_info_t fname;
|
filename_info_t fname;
|
||||||
|
|
||||||
fname.filename = is_dir ? filename + "/" : filename;
|
fname.filename = is_dir ? filename + "/" : filename;
|
||||||
|
@ -484,8 +464,7 @@ void thread_info_t::add_filename( ino64_t inode, const char *path, const char *d
|
||||||
|
|
||||||
static bool is_dot_dir(const char* dname)
|
static bool is_dot_dir(const char* dname)
|
||||||
{
|
{
|
||||||
if ( dname[ 0 ] == '.' )
|
if (dname[0] == '.') {
|
||||||
{
|
|
||||||
if (!dname[1])
|
if (!dname[1])
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -511,10 +490,8 @@ static bool is_proc_dir( const char *path, const char *d_name )
|
||||||
struct statfs s;
|
struct statfs s;
|
||||||
std::string filename = std::string(path) + d_name;
|
std::string filename = std::string(path) + d_name;
|
||||||
|
|
||||||
if ( statfs(filename.c_str(), &s ) == 0 )
|
if (statfs(filename.c_str(), &s) == 0) {
|
||||||
{
|
switch (s.f_type) {
|
||||||
switch ( s.f_type )
|
|
||||||
{
|
|
||||||
case PROC_SUPER_MAGIC:
|
case PROC_SUPER_MAGIC:
|
||||||
case FUSE_SUPER_MAGIC:
|
case FUSE_SUPER_MAGIC:
|
||||||
return true;
|
return true;
|
||||||
|
@ -530,17 +507,13 @@ int thread_info_t::parse_dirqueue_entry()
|
||||||
char __attribute__((aligned(16))) buf[1024];
|
char __attribute__((aligned(16))) buf[1024];
|
||||||
|
|
||||||
char* path = dequeue_directory();
|
char* path = dequeue_directory();
|
||||||
if ( !path )
|
if (!path) {
|
||||||
{
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( std::string &dname : ignore_dirs )
|
for (std::string& dname : ignore_dirs) {
|
||||||
{
|
if (dname == path) {
|
||||||
if ( dname == path )
|
if (g_verbose > 1) {
|
||||||
{
|
|
||||||
if ( g_verbose > 1 )
|
|
||||||
{
|
|
||||||
printf("Ignoring '%s'\n", path);
|
printf("Ignoring '%s'\n", path);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -548,8 +521,7 @@ int thread_info_t::parse_dirqueue_entry()
|
||||||
}
|
}
|
||||||
|
|
||||||
int fd = open(path, O_RDONLY | O_DIRECTORY, 0);
|
int fd = open(path, O_RDONLY | O_DIRECTORY, 0);
|
||||||
if ( fd < 0 )
|
if (fd < 0) {
|
||||||
{
|
|
||||||
free(path);
|
free(path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -558,32 +530,27 @@ int thread_info_t::parse_dirqueue_entry()
|
||||||
|
|
||||||
size_t pathlen = strlen(path);
|
size_t pathlen = strlen(path);
|
||||||
|
|
||||||
for ( ;; )
|
for (;;) {
|
||||||
{
|
|
||||||
int ret = sys_getdents64(fd, buf, sizeof(buf));
|
int ret = sys_getdents64(fd, buf, sizeof(buf));
|
||||||
|
|
||||||
if ( ret < 0 )
|
if (ret < 0) {
|
||||||
{
|
|
||||||
bool spew_error = true;
|
bool spew_error = true;
|
||||||
|
|
||||||
if ( ( errno == 5 ) && !strncmp( path, "/sys/kernel/", 12 ) )
|
if ((errno == 5) && !strncmp(path, "/sys/kernel/", 12)) {
|
||||||
{
|
|
||||||
// In docker container we can get permission denied errors in /sys/kernel. Ignore them.
|
// In docker container we can get permission denied errors in /sys/kernel. Ignore them.
|
||||||
// https://github.com/mikesart/inotify-info/issues/16
|
// https://github.com/mikesart/inotify-info/issues/16
|
||||||
spew_error = false;
|
spew_error = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( spew_error )
|
if (spew_error) {
|
||||||
{
|
printf("ERROR: sys_getdents64 failed on '%s': %d errno: %d (%s)\n", path, ret, errno, strerror(errno));
|
||||||
printf( "ERROR: sys_getdents64 failed on '%s': %d errno:%d\n", path, ret, errno );
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
for ( int bpos = 0; bpos < ret; )
|
for (int bpos = 0; bpos < ret;) {
|
||||||
{
|
|
||||||
struct linux_dirent64* dirp = (struct linux_dirent64*)(buf + bpos);
|
struct linux_dirent64* dirp = (struct linux_dirent64*)(buf + bpos);
|
||||||
const char* d_name = dirp->d_name;
|
const char* d_name = dirp->d_name;
|
||||||
|
|
||||||
|
@ -595,22 +562,18 @@ int thread_info_t::parse_dirqueue_entry()
|
||||||
|
|
||||||
// DT_REG This is a regular file.
|
// DT_REG This is a regular file.
|
||||||
// DT_LNK This is a symbolic link.
|
// DT_LNK This is a symbolic link.
|
||||||
if ( dirp->d_type == DT_REG || dirp->d_type == DT_LNK )
|
if (dirp->d_type == DT_REG || dirp->d_type == DT_LNK) {
|
||||||
{
|
|
||||||
add_filename(dirp->d_ino, path, d_name, false);
|
add_filename(dirp->d_ino, path, d_name, false);
|
||||||
}
|
}
|
||||||
// DT_DIR This is a directory.
|
// DT_DIR This is a directory.
|
||||||
else if ( dirp->d_type == DT_DIR )
|
else if (dirp->d_type == DT_DIR) {
|
||||||
{
|
if (!is_dot_dir(d_name) && !is_proc_dir(path, d_name)) {
|
||||||
if ( !is_dot_dir( d_name ) && !is_proc_dir( path, d_name ) )
|
|
||||||
{
|
|
||||||
add_filename(dirp->d_ino, path, d_name, true);
|
add_filename(dirp->d_ino, path, d_name, true);
|
||||||
|
|
||||||
size_t len = strlen(d_name);
|
size_t len = strlen(d_name);
|
||||||
char* newpath = (char*)malloc(pathlen + len + 2);
|
char* newpath = (char*)malloc(pathlen + len + 2);
|
||||||
|
|
||||||
if ( newpath )
|
if (newpath) {
|
||||||
{
|
|
||||||
strcpy(newpath, path);
|
strcpy(newpath, path);
|
||||||
strcpy(newpath + pathlen, d_name);
|
strcpy(newpath + pathlen, d_name);
|
||||||
newpath[pathlen + len] = '/';
|
newpath[pathlen + len] = '/';
|
||||||
|
@ -634,8 +597,7 @@ static void *parse_dirqueue_threadproc( void *arg )
|
||||||
{
|
{
|
||||||
thread_info_t* pthread_info = (thread_info_t*)arg;
|
thread_info_t* pthread_info = (thread_info_t*)arg;
|
||||||
|
|
||||||
for ( ;; )
|
for (;;) {
|
||||||
{
|
|
||||||
// Loop until all the dequeue(s) fail
|
// Loop until all the dequeue(s) fail
|
||||||
if (pthread_info->parse_dirqueue_entry() == -1)
|
if (pthread_info->parse_dirqueue_entry() == -1)
|
||||||
break;
|
break;
|
||||||
|
@ -646,8 +608,7 @@ static void *parse_dirqueue_threadproc( void *arg )
|
||||||
|
|
||||||
static bool is_proc_in_cmdline_applist(const procinfo_t& procinfo, std::vector<std::string>& cmdline_applist)
|
static bool is_proc_in_cmdline_applist(const procinfo_t& procinfo, std::vector<std::string>& cmdline_applist)
|
||||||
{
|
{
|
||||||
for ( const std::string &str : cmdline_applist )
|
for (const std::string& str : cmdline_applist) {
|
||||||
{
|
|
||||||
// Check if our command line string is a subset of this appname
|
// Check if our command line string is a subset of this appname
|
||||||
if (strstr(procinfo.appname.c_str(), str.c_str()))
|
if (strstr(procinfo.appname.c_str(), str.c_str()))
|
||||||
return true;
|
return true;
|
||||||
|
@ -665,25 +626,21 @@ static bool watch_count_is_greater ( procinfo_t elem1, procinfo_t elem2 )
|
||||||
return elem1.watches > elem2.watches;
|
return elem1.watches > elem2.watches;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool init_inotify_proclist(std::vector<procinfo_t>& inotify_proclist)
|
static bool init_inotify_proclist(std::vector<procinfo_t>& inotify_proclist)
|
||||||
{
|
{
|
||||||
DIR* dir_proc = opendir("/proc");
|
DIR* dir_proc = opendir("/proc");
|
||||||
|
|
||||||
if ( !dir_proc )
|
if (!dir_proc) {
|
||||||
{
|
printf("ERROR: opendir /proc failed: %d (%s)\n", errno, strerror(errno));
|
||||||
printf( "ERROR: opendir /proc failed: %d\n", errno );
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( ;; )
|
for (;;) {
|
||||||
{
|
|
||||||
struct dirent* dp_proc = readdir(dir_proc);
|
struct dirent* dp_proc = readdir(dir_proc);
|
||||||
if (!dp_proc)
|
if (!dp_proc)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if ( ( dp_proc->d_type == DT_DIR ) && isdigit( dp_proc->d_name[ 0 ] ) )
|
if ((dp_proc->d_type == DT_DIR) && isdigit(dp_proc->d_name[0])) {
|
||||||
{
|
|
||||||
procinfo_t procinfo;
|
procinfo_t procinfo;
|
||||||
|
|
||||||
procinfo.pid = atoll(dp_proc->d_name);
|
procinfo.pid = atoll(dp_proc->d_name);
|
||||||
|
@ -692,14 +649,12 @@ static bool init_inotify_proclist( std::vector< procinfo_t > &inotify_proclist )
|
||||||
std::string status = string_format("/proc/%d/status", procinfo.pid);
|
std::string status = string_format("/proc/%d/status", procinfo.pid);
|
||||||
procinfo.uid = get_uid(status.c_str());
|
procinfo.uid = get_uid(status.c_str());
|
||||||
procinfo.executable = get_link_name(executable.c_str());
|
procinfo.executable = get_link_name(executable.c_str());
|
||||||
if ( !procinfo.executable.empty() )
|
if (!procinfo.executable.empty()) {
|
||||||
{
|
|
||||||
procinfo.appname = basename((char*)procinfo.executable.c_str());
|
procinfo.appname = basename((char*)procinfo.executable.c_str());
|
||||||
|
|
||||||
inotify_parse_fddir(procinfo);
|
inotify_parse_fddir(procinfo);
|
||||||
|
|
||||||
if ( procinfo.instances )
|
if (procinfo.instances) {
|
||||||
{
|
|
||||||
inotify_proclist.push_back(procinfo);
|
inotify_proclist.push_back(procinfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -715,8 +670,7 @@ static bool init_inotify_proclist( std::vector< procinfo_t > &inotify_proclist )
|
||||||
// https://stackoverflow.com/questions/1449805/how-to-format-a-number-using-comma-as-thousands-separator-in-c
|
// https://stackoverflow.com/questions/1449805/how-to-format-a-number-using-comma-as-thousands-separator-in-c
|
||||||
size_t str_format_uint32(char dst[16], uint32_t num)
|
size_t str_format_uint32(char dst[16], uint32_t num)
|
||||||
{
|
{
|
||||||
if ( thousands_sep )
|
if (thousands_sep) {
|
||||||
{
|
|
||||||
char src[16];
|
char src[16];
|
||||||
char* p_src = src;
|
char* p_src = src;
|
||||||
char* p_dst = dst;
|
char* p_dst = dst;
|
||||||
|
@ -724,8 +678,7 @@ size_t str_format_uint32( char dst[16], uint32_t num )
|
||||||
|
|
||||||
num_len = sprintf(src, "%u", num);
|
num_len = sprintf(src, "%u", num);
|
||||||
|
|
||||||
for (commas = 2 - num_len % 3; *p_src; commas = (commas + 1) % 3)
|
for (commas = 2 - num_len % 3; *p_src; commas = (commas + 1) % 3) {
|
||||||
{
|
|
||||||
*p_dst++ = *p_src++;
|
*p_dst++ = *p_src++;
|
||||||
if (commas == 1) {
|
if (commas == 1) {
|
||||||
*p_dst++ = thousands_sep;
|
*p_dst++ = thousands_sep;
|
||||||
|
@ -786,9 +739,7 @@ static void print_inotify_proclist( std::vector< procinfo_t > &inotify_proclist
|
||||||
printf("%s%*s %-*s %*s %*s%s\n",
|
printf("%s%*s %-*s %*s %*s%s\n",
|
||||||
BCYAN, lenPid, "Pid", lenUid, "Uid", lenApp, "App", lenInstances, "Instances", RESET);
|
BCYAN, lenPid, "Pid", lenUid, "Uid", lenApp, "App", lenInstances, "Instances", RESET);
|
||||||
|
|
||||||
|
for (procinfo_t& procinfo : inotify_proclist) {
|
||||||
for ( procinfo_t &procinfo : inotify_proclist )
|
|
||||||
{
|
|
||||||
char watches_str[16];
|
char watches_str[16];
|
||||||
|
|
||||||
str_format_uint32(watches_str, procinfo.watches);
|
str_format_uint32(watches_str, procinfo.watches);
|
||||||
|
@ -807,23 +758,18 @@ static void print_inotify_proclist( std::vector< procinfo_t > &inotify_proclist
|
||||||
BYELLOW, lenApp, procinfo.appname.c_str(), RESET,
|
BYELLOW, lenApp, procinfo.appname.c_str(), RESET,
|
||||||
lenInstances, procinfo.instances);
|
lenInstances, procinfo.instances);
|
||||||
|
|
||||||
if ( g_verbose > 1 )
|
if (g_verbose > 1) {
|
||||||
{
|
for (std::string& fname : procinfo.fdset_filenames) {
|
||||||
for ( std::string &fname : procinfo.fdset_filenames )
|
|
||||||
{
|
|
||||||
printf(" %s%s%s\n", CYAN, fname.c_str(), RESET);
|
printf(" %s%s%s\n", CYAN, fname.c_str(), RESET);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( procinfo.in_cmd_line )
|
if (procinfo.in_cmd_line) {
|
||||||
{
|
for (const auto& it1 : procinfo.dev_map) {
|
||||||
for ( const auto &it1 : procinfo.dev_map )
|
|
||||||
{
|
|
||||||
dev_t dev = it1.first;
|
dev_t dev = it1.first;
|
||||||
|
|
||||||
printf("%s[%u.%u]:%s", BGRAY, major(dev), minor(dev), RESET);
|
printf("%s[%u.%u]:%s", BGRAY, major(dev), minor(dev), RESET);
|
||||||
for ( const auto &it2 : it1.second )
|
for (const auto& it2 : it1.second) {
|
||||||
{
|
|
||||||
std::string inode_device_str = string_format("%lu", it2);
|
std::string inode_device_str = string_format("%lu", it2);
|
||||||
|
|
||||||
printf(" %s%s%s", BGRAY, inode_device_str.c_str(), RESET);
|
printf(" %s%s%s", BGRAY, inode_device_str.c_str(), RESET);
|
||||||
|
@ -836,24 +782,20 @@ static void print_inotify_proclist( std::vector< procinfo_t > &inotify_proclist
|
||||||
|
|
||||||
bool thread_shared_data_t::init(uint32_t numthreads, const std::vector<procinfo_t>& inotify_proclist)
|
bool thread_shared_data_t::init(uint32_t numthreads, const std::vector<procinfo_t>& inotify_proclist)
|
||||||
{
|
{
|
||||||
for ( const procinfo_t &procinfo : inotify_proclist )
|
for (const procinfo_t& procinfo : inotify_proclist) {
|
||||||
{
|
|
||||||
if (!procinfo.in_cmd_line)
|
if (!procinfo.in_cmd_line)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for ( const auto &it1 : procinfo.dev_map )
|
for (const auto& it1 : procinfo.dev_map) {
|
||||||
{
|
|
||||||
dev_t dev = it1.first;
|
dev_t dev = it1.first;
|
||||||
|
|
||||||
for ( const auto &inode : it1.second )
|
for (const auto& inode : it1.second) {
|
||||||
{
|
|
||||||
inode_set[inode].insert(dev);
|
inode_set[inode].insert(dev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !inode_set.empty() )
|
if (!inode_set.empty()) {
|
||||||
{
|
|
||||||
dirqueues.resize(numthreads);
|
dirqueues.resize(numthreads);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -875,22 +817,18 @@ static uint32_t find_files_in_inode_set( const std::vector< procinfo_t > &inotif
|
||||||
// Initialize thread_info_t array
|
// Initialize thread_info_t array
|
||||||
std::vector<class thread_info_t> thread_array(g_numthreads, thread_info_t(tdata));
|
std::vector<class thread_info_t> thread_array(g_numthreads, thread_info_t(tdata));
|
||||||
|
|
||||||
for ( uint32_t idx = 0; idx < thread_array.size(); idx++ )
|
for (uint32_t idx = 0; idx < thread_array.size(); idx++) {
|
||||||
{
|
|
||||||
thread_info_t& thread_info = thread_array[idx];
|
thread_info_t& thread_info = thread_array[idx];
|
||||||
|
|
||||||
thread_info.idx = idx;
|
thread_info.idx = idx;
|
||||||
|
|
||||||
if ( idx == 0 )
|
if (idx == 0) {
|
||||||
{
|
|
||||||
// Add root dir in case someone is watching it
|
// Add root dir in case someone is watching it
|
||||||
thread_info.add_filename(stat_get_ino("/"), "/", "", false);
|
thread_info.add_filename(stat_get_ino("/"), "/", "", false);
|
||||||
// Add and parse root
|
// Add and parse root
|
||||||
thread_info.queue_directory(strdup("/"));
|
thread_info.queue_directory(strdup("/"));
|
||||||
thread_info.parse_dirqueue_entry();
|
thread_info.parse_dirqueue_entry();
|
||||||
}
|
} else if (pthread_create(&thread_info.pthread_id, NULL, &parse_dirqueue_threadproc, &thread_info)) {
|
||||||
else if ( pthread_create( &thread_info.pthread_id, NULL, &parse_dirqueue_threadproc, &thread_info ) )
|
|
||||||
{
|
|
||||||
printf("Warning: pthread_create failed. errno: %d\n", errno);
|
printf("Warning: pthread_create failed. errno: %d\n", errno);
|
||||||
thread_info.pthread_id = 0;
|
thread_info.pthread_id = 0;
|
||||||
}
|
}
|
||||||
|
@ -900,20 +838,16 @@ static uint32_t find_files_in_inode_set( const std::vector< procinfo_t > &inotif
|
||||||
parse_dirqueue_threadproc(&thread_array[0]);
|
parse_dirqueue_threadproc(&thread_array[0]);
|
||||||
|
|
||||||
uint32_t total_scanned_dirs = 0;
|
uint32_t total_scanned_dirs = 0;
|
||||||
for ( const thread_info_t &thread_info : thread_array )
|
for (const thread_info_t& thread_info : thread_array) {
|
||||||
{
|
if (thread_info.pthread_id) {
|
||||||
if ( thread_info.pthread_id )
|
if (g_verbose > 1) {
|
||||||
{
|
|
||||||
if ( g_verbose > 1 )
|
|
||||||
{
|
|
||||||
printf("Waiting for thread #%zu\n", thread_info.pthread_id);
|
printf("Waiting for thread #%zu\n", thread_info.pthread_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* status = NULL;
|
void* status = NULL;
|
||||||
int rc = pthread_join(thread_info.pthread_id, &status);
|
int rc = pthread_join(thread_info.pthread_id, &status);
|
||||||
|
|
||||||
if ( g_verbose > 1 )
|
if (g_verbose > 1) {
|
||||||
{
|
|
||||||
printf("Thread #%zu rc=%d status=%d\n", thread_info.pthread_id, rc, (int)(intptr_t)status);
|
printf("Thread #%zu rc=%d status=%d\n", thread_info.pthread_id, rc, (int)(intptr_t)status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -924,8 +858,7 @@ static uint32_t find_files_in_inode_set( const std::vector< procinfo_t > &inotif
|
||||||
all_found_files.insert(all_found_files.end(),
|
all_found_files.insert(all_found_files.end(),
|
||||||
thread_info.found_files.begin(), thread_info.found_files.end());
|
thread_info.found_files.begin(), thread_info.found_files.end());
|
||||||
|
|
||||||
if ( g_verbose > 1 )
|
if (g_verbose > 1) {
|
||||||
{
|
|
||||||
printf("Thread #%zu: %u dirs, %zu files found\n",
|
printf("Thread #%zu: %u dirs, %zu files found\n",
|
||||||
thread_info.pthread_id, thread_info.scanned_dirs, thread_info.found_files.size());
|
thread_info.pthread_id, thread_info.scanned_dirs, thread_info.found_files.size());
|
||||||
}
|
}
|
||||||
|
@ -953,10 +886,8 @@ static uint32_t get_inotify_procfs_value( const std::string &fname )
|
||||||
std::string filename = "/proc/sys/fs/inotify/" + fname;
|
std::string filename = "/proc/sys/fs/inotify/" + fname;
|
||||||
|
|
||||||
int fd = open(filename.c_str(), O_RDONLY);
|
int fd = open(filename.c_str(), O_RDONLY);
|
||||||
if ( fd >= 0 )
|
if (fd >= 0) {
|
||||||
{
|
if (read(fd, buf, sizeof(buf)) > 0) {
|
||||||
if ( read( fd, buf, sizeof( buf ) ) > 0 )
|
|
||||||
{
|
|
||||||
val = strtoul(buf, nullptr, 10);
|
val = strtoul(buf, nullptr, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -968,16 +899,14 @@ static uint32_t get_inotify_procfs_value( const std::string &fname )
|
||||||
|
|
||||||
static void print_inotify_limits()
|
static void print_inotify_limits()
|
||||||
{
|
{
|
||||||
const std::vector< std::string > filenames =
|
const std::vector<std::string> filenames = {
|
||||||
{
|
|
||||||
"max_queued_events",
|
"max_queued_events",
|
||||||
"max_user_instances",
|
"max_user_instances",
|
||||||
"max_user_watches"
|
"max_user_watches"
|
||||||
};
|
};
|
||||||
|
|
||||||
printf("%sINotify Limits:%s\n", BCYAN, RESET);
|
printf("%sINotify Limits:%s\n", BCYAN, RESET);
|
||||||
for ( const std::string &fname : filenames )
|
for (const std::string& fname : filenames) {
|
||||||
{
|
|
||||||
char str[16];
|
char str[16];
|
||||||
uint32_t val = get_inotify_procfs_value(fname);
|
uint32_t val = get_inotify_procfs_value(fname);
|
||||||
|
|
||||||
|
@ -992,42 +921,30 @@ static uint32_t parse_config_file( const char *config_file )
|
||||||
uint32_t dir_count = 0;
|
uint32_t dir_count = 0;
|
||||||
|
|
||||||
FILE* fp = fopen(config_file, "r");
|
FILE* fp = fopen(config_file, "r");
|
||||||
if ( fp )
|
if (fp) {
|
||||||
{
|
|
||||||
char line_buf[8192];
|
char line_buf[8192];
|
||||||
bool in_ignore_dirs_section = false;
|
bool in_ignore_dirs_section = false;
|
||||||
|
|
||||||
for ( ;; )
|
for (;;) {
|
||||||
{
|
|
||||||
if (!fgets(line_buf, sizeof(line_buf) - 1, fp))
|
if (!fgets(line_buf, sizeof(line_buf) - 1, fp))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if ( line_buf[0] == '#' )
|
if (line_buf[0] == '#') {
|
||||||
{
|
|
||||||
// comment
|
// comment
|
||||||
}
|
} else if (!in_ignore_dirs_section) {
|
||||||
else if ( !in_ignore_dirs_section )
|
|
||||||
{
|
|
||||||
size_t len = strcspn(line_buf, "\r\n");
|
size_t len = strcspn(line_buf, "\r\n");
|
||||||
|
|
||||||
if ( ( len == 12 ) && !strncmp( "[ignoredirs]", line_buf, 12 ) )
|
if ((len == 12) && !strncmp("[ignoredirs]", line_buf, 12)) {
|
||||||
{
|
|
||||||
in_ignore_dirs_section = true;
|
in_ignore_dirs_section = true;
|
||||||
}
|
}
|
||||||
}
|
} else if (line_buf[0] == '[') {
|
||||||
else if ( line_buf[ 0 ] == '[' )
|
|
||||||
{
|
|
||||||
in_ignore_dirs_section = false;
|
in_ignore_dirs_section = false;
|
||||||
}
|
} else if (in_ignore_dirs_section && (line_buf[0] == '/')) {
|
||||||
else if ( in_ignore_dirs_section && ( line_buf[ 0 ] == '/' ) )
|
|
||||||
{
|
|
||||||
size_t len = strcspn(line_buf, "\r\n");
|
size_t len = strcspn(line_buf, "\r\n");
|
||||||
|
|
||||||
if ( len > 1 )
|
if (len > 1) {
|
||||||
{
|
|
||||||
line_buf[len] = 0;
|
line_buf[len] = 0;
|
||||||
if ( line_buf[ len - 1 ] != '/' )
|
if (line_buf[len - 1] != '/') {
|
||||||
{
|
|
||||||
line_buf[len] = '/';
|
line_buf[len] = '/';
|
||||||
line_buf[len + 1] = '\0';
|
line_buf[len + 1] = '\0';
|
||||||
}
|
}
|
||||||
|
@ -1049,8 +966,7 @@ static bool parse_ignore_dirs_file()
|
||||||
const std::string filename = "inotify-info.config";
|
const std::string filename = "inotify-info.config";
|
||||||
|
|
||||||
const char* xdg_config_dir = getenv("XDG_CONFIG_HOME");
|
const char* xdg_config_dir = getenv("XDG_CONFIG_HOME");
|
||||||
if ( xdg_config_dir )
|
if (xdg_config_dir) {
|
||||||
{
|
|
||||||
std::string config_file = std::string(xdg_config_dir) + "/" + filename;
|
std::string config_file = std::string(xdg_config_dir) + "/" + filename;
|
||||||
if (parse_config_file(config_file.c_str()))
|
if (parse_config_file(config_file.c_str()))
|
||||||
return true;
|
return true;
|
||||||
|
@ -1061,8 +977,7 @@ static bool parse_ignore_dirs_file()
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* home_dir = getenv("HOME");
|
const char* home_dir = getenv("HOME");
|
||||||
if ( home_dir )
|
if (home_dir) {
|
||||||
{
|
|
||||||
std::string config_file = std::string(home_dir) + "/" + filename;
|
std::string config_file = std::string(home_dir) + "/" + filename;
|
||||||
if (parse_config_file(config_file.c_str()))
|
if (parse_config_file(config_file.c_str()))
|
||||||
return true;
|
return true;
|
||||||
|
@ -1075,22 +990,27 @@ static bool parse_ignore_dirs_file()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_version()
|
||||||
|
{
|
||||||
|
printf("%s\n", INOTIFYINFO_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
static void print_usage(const char* appname)
|
static void print_usage(const char* appname)
|
||||||
{
|
{
|
||||||
printf("Usage: %s [--threads=##] [appname | pid...]\n", appname);
|
printf("Usage: %s [--threads=##] [appname | pid...]\n", appname);
|
||||||
printf(" [-vv]\n");
|
printf(" [-vv]\n");
|
||||||
|
printf(" [--version]\n");
|
||||||
printf(" [-?|-h|--help]\n");
|
printf(" [-?|-h|--help]\n");
|
||||||
|
|
||||||
exit( -1 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_cmdline(int argc, char** argv, std::vector<std::string>& cmdline_applist)
|
static void parse_cmdline(int argc, char** argv, std::vector<std::string>& cmdline_applist)
|
||||||
{
|
{
|
||||||
static struct option long_opts[] =
|
static struct option long_opts[] = {
|
||||||
{
|
|
||||||
{ "verbose", no_argument, 0, 0 },
|
{ "verbose", no_argument, 0, 0 },
|
||||||
{ "threads", required_argument, 0, 0 },
|
{ "threads", required_argument, 0, 0 },
|
||||||
{ "ignoredir", required_argument, 0, 0 },
|
{ "ignoredir", required_argument, 0, 0 },
|
||||||
|
{ "version", no_argument, 0, 0 },
|
||||||
|
{ "help", no_argument, 0, 0 },
|
||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1099,20 +1019,24 @@ static void parse_cmdline( int argc, char **argv, std::vector< std::string > &cm
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
int opt_ind = 0;
|
int opt_ind = 0;
|
||||||
while ( ( c = getopt_long( argc, argv, "m:s:?hv", long_opts, &opt_ind ) ) != -1 )
|
while ((c = getopt_long(argc, argv, "m:s:?hv", long_opts, &opt_ind)) != -1) {
|
||||||
{
|
switch (c) {
|
||||||
switch ( c )
|
|
||||||
{
|
|
||||||
case 0:
|
case 0:
|
||||||
|
if (!strcasecmp("help", long_opts[opt_ind].name)) {
|
||||||
|
print_usage(argv[0]);
|
||||||
|
exit(0);
|
||||||
|
};
|
||||||
|
if (!strcasecmp("version", long_opts[opt_ind].name)) {
|
||||||
|
print_version();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
if (!strcasecmp("verbose", long_opts[opt_ind].name))
|
if (!strcasecmp("verbose", long_opts[opt_ind].name))
|
||||||
g_verbose++;
|
g_verbose++;
|
||||||
else if (!strcasecmp("threads", long_opts[opt_ind].name))
|
else if (!strcasecmp("threads", long_opts[opt_ind].name))
|
||||||
g_numthreads = atoi(optarg);
|
g_numthreads = atoi(optarg);
|
||||||
else if ( !strcasecmp( "ignoredir", long_opts[ opt_ind ].name ) )
|
else if (!strcasecmp("ignoredir", long_opts[opt_ind].name)) {
|
||||||
{
|
|
||||||
std::string dirname = optarg;
|
std::string dirname = optarg;
|
||||||
if ( dirname.size() > 1 )
|
if (dirname.size() > 1) {
|
||||||
{
|
|
||||||
if (optarg[dirname.size() - 1] != '/')
|
if (optarg[dirname.size() - 1] != '/')
|
||||||
dirname += "/";
|
dirname += "/";
|
||||||
ignore_dirs.push_back(dirname);
|
ignore_dirs.push_back(dirname);
|
||||||
|
@ -1124,25 +1048,25 @@ static void parse_cmdline( int argc, char **argv, std::vector< std::string > &cm
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
case '?':
|
case '?':
|
||||||
|
print_usage(argv[0]);
|
||||||
|
exit(0);
|
||||||
default:
|
default:
|
||||||
print_usage(argv[0]);
|
print_usage(argv[0]);
|
||||||
|
exit(-1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( ; optind < argc; optind++ )
|
for (; optind < argc; optind++) {
|
||||||
{
|
|
||||||
cmdline_applist.push_back(argv[optind]);
|
cmdline_applist.push_back(argv[optind]);
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_ignore_dirs_file();
|
parse_ignore_dirs_file();
|
||||||
|
|
||||||
if ( g_verbose > 1 )
|
if (g_verbose > 1) {
|
||||||
{
|
|
||||||
printf("%lu ignore_dirs:\n", ignore_dirs.size());
|
printf("%lu ignore_dirs:\n", ignore_dirs.size());
|
||||||
|
|
||||||
for ( std::string &dname : ignore_dirs )
|
for (std::string& dname : ignore_dirs) {
|
||||||
{
|
|
||||||
printf(" '%s'\n", dname.c_str());
|
printf(" '%s'\n", dname.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1159,8 +1083,7 @@ int main( int argc, char *argv[] )
|
||||||
std::vector<procinfo_t> inotify_proclist;
|
std::vector<procinfo_t> inotify_proclist;
|
||||||
|
|
||||||
struct lconv* env = localeconv();
|
struct lconv* env = localeconv();
|
||||||
if (env && env->thousands_sep && env->thousands_sep[0])
|
if (env && env->thousands_sep && env->thousands_sep[0]) {
|
||||||
{
|
|
||||||
thousands_sep = env->thousands_sep[0];
|
thousands_sep = env->thousands_sep[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1170,14 +1093,12 @@ int main( int argc, char *argv[] )
|
||||||
print_inotify_limits();
|
print_inotify_limits();
|
||||||
print_separator();
|
print_separator();
|
||||||
|
|
||||||
if ( init_inotify_proclist( inotify_proclist ) )
|
if (init_inotify_proclist(inotify_proclist)) {
|
||||||
{
|
|
||||||
uint32_t total_watches = 0;
|
uint32_t total_watches = 0;
|
||||||
uint32_t total_instances = 0;
|
uint32_t total_instances = 0;
|
||||||
std::vector<filename_info_t> all_found_files;
|
std::vector<filename_info_t> all_found_files;
|
||||||
|
|
||||||
for ( procinfo_t &procinfo : inotify_proclist )
|
for (procinfo_t& procinfo : inotify_proclist) {
|
||||||
{
|
|
||||||
procinfo.in_cmd_line = is_proc_in_cmdline_applist(procinfo, cmdline_applist);
|
procinfo.in_cmd_line = is_proc_in_cmdline_applist(procinfo, cmdline_applist);
|
||||||
|
|
||||||
total_watches += procinfo.watches;
|
total_watches += procinfo.watches;
|
||||||
|
@ -1196,12 +1117,10 @@ int main( int argc, char *argv[] )
|
||||||
|
|
||||||
double search_time = gettime();
|
double search_time = gettime();
|
||||||
uint32_t total_scanned_dirs = find_files_in_inode_set(inotify_proclist, all_found_files);
|
uint32_t total_scanned_dirs = find_files_in_inode_set(inotify_proclist, all_found_files);
|
||||||
if ( total_scanned_dirs )
|
if (total_scanned_dirs) {
|
||||||
{
|
|
||||||
search_time = gettime() - search_time;
|
search_time = gettime() - search_time;
|
||||||
|
|
||||||
for ( const filename_info_t &fname_info : all_found_files )
|
for (const filename_info_t& fname_info : all_found_files) {
|
||||||
{
|
|
||||||
printf("%s%9lu%s [%u:%u] %s\n", BGREEN, fname_info.inode, RESET,
|
printf("%s%9lu%s [%u:%u] %s\n", BGREEN, fname_info.inode, RESET,
|
||||||
major(fname_info.dev), minor(fname_info.dev),
|
major(fname_info.dev), minor(fname_info.dev),
|
||||||
fname_info.filename.c_str());
|
fname_info.filename.c_str());
|
||||||
|
|
|
@ -57,4 +57,3 @@
|
||||||
|
|
||||||
std::string string_formatv(const char* fmt, va_list ap) ATTRIBUTE_PRINTF(1, 0);
|
std::string string_formatv(const char* fmt, va_list ap) ATTRIBUTE_PRINTF(1, 0);
|
||||||
std::string string_format(const char* fmt, ...) ATTRIBUTE_PRINTF(1, 2);
|
std::string string_format(const char* fmt, ...) ATTRIBUTE_PRINTF(1, 2);
|
||||||
|
|
||||||
|
|
|
@ -27,14 +27,14 @@
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
|
||||||
#if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__
|
#if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__
|
||||||
|
|
||||||
|
#include <sched.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <unistd.h> // for usleep
|
#include <unistd.h> // for usleep
|
||||||
#include <sched.h>
|
|
||||||
|
|
||||||
#define __LFQ_VAL_COMPARE_AND_SWAP __sync_val_compare_and_swap
|
#define __LFQ_VAL_COMPARE_AND_SWAP __sync_val_compare_and_swap
|
||||||
#define __LFQ_BOOL_COMPARE_AND_SWAP __sync_bool_compare_and_swap
|
#define __LFQ_BOOL_COMPARE_AND_SWAP __sync_bool_compare_and_swap
|
||||||
|
@ -48,7 +48,8 @@
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
inline BOOL __SYNC_BOOL_CAS(LONG64 volatile *dest, LONG64 input, LONG64 comparand) {
|
inline BOOL __SYNC_BOOL_CAS(LONG64 volatile* dest, LONG64 input, LONG64 comparand)
|
||||||
|
{
|
||||||
return InterlockedCompareExchangeNoFence64(dest, input, comparand) == comparand;
|
return InterlockedCompareExchangeNoFence64(dest, input, comparand) == comparand;
|
||||||
}
|
}
|
||||||
#define __LFQ_VAL_COMPARE_AND_SWAP(dest, comparand, input) \
|
#define __LFQ_VAL_COMPARE_AND_SWAP(dest, comparand, input) \
|
||||||
|
@ -63,7 +64,8 @@ inline BOOL __SYNC_BOOL_CAS(LONG64 volatile *dest, LONG64 input, LONG64 comparan
|
||||||
#ifndef asm
|
#ifndef asm
|
||||||
#define asm __asm
|
#define asm __asm
|
||||||
#endif
|
#endif
|
||||||
inline BOOL __SYNC_BOOL_CAS(LONG volatile *dest, LONG input, LONG comparand) {
|
inline BOOL __SYNC_BOOL_CAS(LONG volatile* dest, LONG input, LONG comparand)
|
||||||
|
{
|
||||||
return InterlockedCompareExchangeNoFence(dest, input, comparand) == comparand;
|
return InterlockedCompareExchangeNoFence(dest, input, comparand) == comparand;
|
||||||
}
|
}
|
||||||
#define __LFQ_VAL_COMPARE_AND_SWAP(dest, comparand, input) \
|
#define __LFQ_VAL_COMPARE_AND_SWAP(dest, comparand, input) \
|
||||||
|
@ -107,15 +109,18 @@ static void __lfq_check_free(lfqueue_t *);
|
||||||
static void* _dequeue(lfqueue_t*);
|
static void* _dequeue(lfqueue_t*);
|
||||||
static void* _single_dequeue(lfqueue_t*);
|
static void* _single_dequeue(lfqueue_t*);
|
||||||
static int _enqueue(lfqueue_t*, void*);
|
static int _enqueue(lfqueue_t*, void*);
|
||||||
static inline void* _lfqueue_malloc(__attribute__ ((unused)) void* pl, size_t sz) {
|
static inline void* _lfqueue_malloc(__attribute__((unused)) void* pl, size_t sz)
|
||||||
|
{
|
||||||
return malloc(sz);
|
return malloc(sz);
|
||||||
}
|
}
|
||||||
static inline void _lfqueue_free(__attribute__ ((unused)) void* pl, void* ptr) {
|
static inline void _lfqueue_free(__attribute__((unused)) void* pl, void* ptr)
|
||||||
|
{
|
||||||
free(ptr);
|
free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void*
|
static void*
|
||||||
_dequeue(lfqueue_t *lfqueue) {
|
_dequeue(lfqueue_t* lfqueue)
|
||||||
|
{
|
||||||
lfqueue_cas_node_t *head, *next;
|
lfqueue_cas_node_t *head, *next;
|
||||||
void* val;
|
void* val;
|
||||||
|
|
||||||
|
@ -128,8 +133,7 @@ _dequeue(lfqueue_t *lfqueue) {
|
||||||
val = NULL;
|
val = NULL;
|
||||||
goto _done;
|
goto _done;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (next) {
|
if (next) {
|
||||||
val = next->value;
|
val = next->value;
|
||||||
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->head, head, next)) {
|
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->head, head, next)) {
|
||||||
|
@ -152,7 +156,8 @@ _done:
|
||||||
}
|
}
|
||||||
|
|
||||||
static void*
|
static void*
|
||||||
_single_dequeue(lfqueue_t *lfqueue) {
|
_single_dequeue(lfqueue_t* lfqueue)
|
||||||
|
{
|
||||||
lfqueue_cas_node_t *head, *next;
|
lfqueue_cas_node_t *head, *next;
|
||||||
void* val;
|
void* val;
|
||||||
|
|
||||||
|
@ -164,8 +169,7 @@ _single_dequeue(lfqueue_t *lfqueue) {
|
||||||
if (next == NULL) {
|
if (next == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (next) {
|
if (next) {
|
||||||
val = next->value;
|
val = next->value;
|
||||||
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->head, head, next)) {
|
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->head, head, next)) {
|
||||||
|
@ -182,7 +186,8 @@ _single_dequeue(lfqueue_t *lfqueue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_enqueue(lfqueue_t *lfqueue, void* value) {
|
_enqueue(lfqueue_t* lfqueue, void* value)
|
||||||
|
{
|
||||||
lfqueue_cas_node_t *tail, *node;
|
lfqueue_cas_node_t *tail, *node;
|
||||||
node = (lfqueue_cas_node_t*)lfqueue->_malloc(lfqueue->pl, sizeof(lfqueue_cas_node_t));
|
node = (lfqueue_cas_node_t*)lfqueue->_malloc(lfqueue->pl, sizeof(lfqueue_cas_node_t));
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
|
@ -208,7 +213,8 @@ _enqueue(lfqueue_t *lfqueue, void* value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
__lfq_recycle_free(lfqueue_t *lfqueue, lfqueue_cas_node_t* freenode) {
|
__lfq_recycle_free(lfqueue_t* lfqueue, lfqueue_cas_node_t* freenode)
|
||||||
|
{
|
||||||
lfqueue_cas_node_t* freed;
|
lfqueue_cas_node_t* freed;
|
||||||
do {
|
do {
|
||||||
freed = lfqueue->move_free;
|
freed = lfqueue->move_free;
|
||||||
|
@ -220,7 +226,8 @@ __lfq_recycle_free(lfqueue_t *lfqueue, lfqueue_cas_node_t* freenode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
__lfq_check_free(lfqueue_t *lfqueue) {
|
__lfq_check_free(lfqueue_t* lfqueue)
|
||||||
|
{
|
||||||
lfq_time_t curr_time;
|
lfq_time_t curr_time;
|
||||||
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->in_free_mode, 0, 1)) {
|
if (__LFQ_BOOL_COMPARE_AND_SWAP(&lfqueue->in_free_mode, 0, 1)) {
|
||||||
lfq_get_curr_time(&curr_time);
|
lfq_get_curr_time(&curr_time);
|
||||||
|
@ -241,13 +248,13 @@ __lfq_check_free(lfqueue_t *lfqueue) {
|
||||||
__LFQ_SYNC_MEMORY();
|
__LFQ_SYNC_MEMORY();
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int lfqueue_init(lfqueue_t* lfqueue)
|
||||||
lfqueue_init(lfqueue_t *lfqueue) {
|
{
|
||||||
return lfqueue_init_mf(lfqueue, NULL, _lfqueue_malloc, _lfqueue_free);
|
return lfqueue_init_mf(lfqueue, NULL, _lfqueue_malloc, _lfqueue_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int lfqueue_init_mf(lfqueue_t* lfqueue, void* pl, lfqueue_malloc_fn lfqueue_malloc, lfqueue_free_fn lfqueue_free)
|
||||||
lfqueue_init_mf(lfqueue_t *lfqueue, void* pl, lfqueue_malloc_fn lfqueue_malloc, lfqueue_free_fn lfqueue_free) {
|
{
|
||||||
lfqueue->_malloc = lfqueue_malloc;
|
lfqueue->_malloc = lfqueue_malloc;
|
||||||
lfqueue->_free = lfqueue_free;
|
lfqueue->_free = lfqueue_free;
|
||||||
lfqueue->pl = pl;
|
lfqueue->pl = pl;
|
||||||
|
@ -276,8 +283,8 @@ lfqueue_init_mf(lfqueue_t *lfqueue, void* pl, lfqueue_malloc_fn lfqueue_malloc,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void lfqueue_destroy(lfqueue_t* lfqueue)
|
||||||
lfqueue_destroy(lfqueue_t *lfqueue) {
|
{
|
||||||
void* p;
|
void* p;
|
||||||
while ((p = lfqueue_deq(lfqueue))) {
|
while ((p = lfqueue_deq(lfqueue))) {
|
||||||
lfqueue->_free(lfqueue->pl, p);
|
lfqueue->_free(lfqueue->pl, p);
|
||||||
|
@ -298,8 +305,8 @@ lfqueue_destroy(lfqueue_t *lfqueue) {
|
||||||
lfqueue->size = 0;
|
lfqueue->size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int lfqueue_enq(lfqueue_t* lfqueue, void* value)
|
||||||
lfqueue_enq(lfqueue_t *lfqueue, void *value) {
|
{
|
||||||
if (_enqueue(lfqueue, value)) {
|
if (_enqueue(lfqueue, value)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -307,12 +314,11 @@ lfqueue_enq(lfqueue_t *lfqueue, void *value) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void* lfqueue_deq(lfqueue_t* lfqueue)
|
||||||
lfqueue_deq(lfqueue_t *lfqueue) {
|
{
|
||||||
void* v;
|
void* v;
|
||||||
if ( //__LFQ_ADD_AND_FETCH(&lfqueue->size, 0) &&
|
if ( //__LFQ_ADD_AND_FETCH(&lfqueue->size, 0) &&
|
||||||
(v = _dequeue(lfqueue))
|
(v = _dequeue(lfqueue))) {
|
||||||
) {
|
|
||||||
|
|
||||||
__LFQ_FETCH_AND_ADD(&lfqueue->size, -1);
|
__LFQ_FETCH_AND_ADD(&lfqueue->size, -1);
|
||||||
return v;
|
return v;
|
||||||
|
@ -320,8 +326,8 @@ lfqueue_deq(lfqueue_t *lfqueue) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void* lfqueue_deq_must(lfqueue_t* lfqueue)
|
||||||
lfqueue_deq_must(lfqueue_t *lfqueue) {
|
{
|
||||||
void* v;
|
void* v;
|
||||||
while (!(v = _dequeue(lfqueue))) {
|
while (!(v = _dequeue(lfqueue))) {
|
||||||
// Rest the thread for other thread, to avoid keep looping force
|
// Rest the thread for other thread, to avoid keep looping force
|
||||||
|
@ -332,12 +338,11 @@ lfqueue_deq_must(lfqueue_t *lfqueue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**This is only applicable when only single thread consume only**/
|
/**This is only applicable when only single thread consume only**/
|
||||||
void*
|
void* lfqueue_single_deq(lfqueue_t* lfqueue)
|
||||||
lfqueue_single_deq(lfqueue_t *lfqueue) {
|
{
|
||||||
void* v;
|
void* v;
|
||||||
if ( //__LFQ_ADD_AND_FETCH(&lfqueue->size, 0) &&
|
if ( //__LFQ_ADD_AND_FETCH(&lfqueue->size, 0) &&
|
||||||
(v = _single_dequeue(lfqueue))
|
(v = _single_dequeue(lfqueue))) {
|
||||||
) {
|
|
||||||
|
|
||||||
__LFQ_FETCH_AND_ADD(&lfqueue->size, -1);
|
__LFQ_FETCH_AND_ADD(&lfqueue->size, -1);
|
||||||
return v;
|
return v;
|
||||||
|
@ -346,8 +351,8 @@ lfqueue_single_deq(lfqueue_t *lfqueue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**This is only applicable when only single thread consume only**/
|
/**This is only applicable when only single thread consume only**/
|
||||||
void*
|
void* lfqueue_single_deq_must(lfqueue_t* lfqueue)
|
||||||
lfqueue_single_deq_must(lfqueue_t *lfqueue) {
|
{
|
||||||
void* v;
|
void* v;
|
||||||
while (!(v = _single_dequeue(lfqueue))) {
|
while (!(v = _single_dequeue(lfqueue))) {
|
||||||
// Rest the thread for other thread, to avoid keep looping force
|
// Rest the thread for other thread, to avoid keep looping force
|
||||||
|
@ -358,12 +363,13 @@ lfqueue_single_deq_must(lfqueue_t *lfqueue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
lfqueue_size(lfqueue_t *lfqueue) {
|
lfqueue_size(lfqueue_t* lfqueue)
|
||||||
|
{
|
||||||
return __LFQ_ADD_AND_FETCH(&lfqueue->size, 0);
|
return __LFQ_ADD_AND_FETCH(&lfqueue->size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void lfqueue_sleep(unsigned int milisec)
|
||||||
lfqueue_sleep(unsigned int milisec) {
|
{
|
||||||
#if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__
|
#if defined __GNUC__ || defined __CYGWIN__ || defined __MINGW32__ || defined __APPLE__
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
|
#pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
|
||||||
|
|
|
@ -31,8 +31,8 @@
|
||||||
#ifndef LFQUEUE_H
|
#ifndef LFQUEUE_H
|
||||||
#define LFQUEUE_H
|
#define LFQUEUE_H
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -75,10 +75,8 @@ extern void lfqueue_destroy(lfqueue_t *lfqueue);
|
||||||
extern size_t lfqueue_size(lfqueue_t* lfqueue);
|
extern size_t lfqueue_size(lfqueue_t* lfqueue);
|
||||||
extern void lfqueue_sleep(unsigned int milisec);
|
extern void lfqueue_sleep(unsigned int milisec);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue