Compare commits

..
139 Commits
Author SHA1 Message Date
Joachim Nilsson 7cf2a3786c Bump version and ABI for v1.8.0 release
- Change from v1.7.1 to v1.8.0 due to amount of changes
  including ABI bump
- Update ChangeLog
- Bump library ABI version due to change in API semantics

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 19:05:26 +02:00
Joachim Nilsson 1c1d5c94e3 Clarify ABI versioning and encourage more unit tests
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 19:00:14 +02:00
Joachim Nilsson 23703c75da tests/dir.c: Remove nested checker function
Move nested check function is_startup_config() outside main().

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 18:15:47 +02:00
Joachim Nilsson efae15416c Bump version to -rc1, many changes since last release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 18:11:03 +02:00
Joachim Nilsson 661b4b4d0b Remove last remnants of old build/unit test framework
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 18:09:59 +02:00
Joachim Nilsson 682b662bd5 Add unit test for chomp()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 18:09:29 +02:00
Joachim Nilsson 75d4edb424 check.h: Add stdlib.h for exit()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 18:08:54 +02:00
Joachim Nilsson 141d4f6936 Add unit test for copyfile()/fcopyfile()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 17:59:52 +02:00
Joachim Nilsson 63aa6c5d07 Add unit test for dir()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 17:56:13 +02:00
Joachim Nilsson 1d698418c7 dir(): Do not assert(), return -1 and errno
The dir() function, although useless compared to glob(), called assert()
and perror() instead of returning an error code.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 17:56:13 +02:00
Joachim Nilsson 92d81280a9 Add unit test for fexist()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 17:45:19 +02:00
Joachim Nilsson 267465f3d2 Add unit test for fisdir()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 17:42:31 +02:00
Joachim Nilsson c22a6e64d9 Add unit test for progress bars
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 17:39:31 +02:00
Joachim Nilsson 16ae343df2 Add missing progress bar API's
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 17:39:31 +02:00
Joachim Nilsson 6e558e98f0 Add unit test for rsync
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 17:28:41 +02:00
Joachim Nilsson 69291d3e74 Add unit test for fsendfile()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 17:20:58 +02:00
Joachim Nilsson 6fdffeb355 fsendfile(): Change return type size_t --> ssize_t
Most send/recv/read/write API's return -1 on error and today use the
agreed upon type ssize_t for this purpose.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 17:19:54 +02:00
Joachim Nilsson b2f6721813 Clarify LITE file API in README
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 17:12:42 +02:00
Joachim Nilsson 3c350b8862 Add unit test for LITE file API
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 17:11:22 +02:00
Joachim Nilsson 5b786ce221 Add unit test for tempfile()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 17:07:14 +02:00
Joachim Nilsson 86b883e2af strdupa.h: Unify header guards with other headers
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 15:32:35 +02:00
Joachim Nilsson 2d6e8850a2 Add unit test for tree
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 15:32:35 +02:00
Joachim Nilsson d8cb477861 Ignore *.log and *.trs files in unit test dir
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 15:31:24 +02:00
Joachim Nilsson 27644677dd Clean *.trs and *.log files from unit test dir
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 15:31:24 +02:00
Joachim Nilsson 3588c9b01f Rename unit tests, drop _func suffix
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 15:31:24 +02:00
Joachim Nilsson ca3ea5ae92 Add unit test for mkpath() and makepath() funcs
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 15:31:23 +02:00
Joachim Nilsson 188d968f89 Remove previous pidfilefn() unit test makefile
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 15:03:56 +02:00
Joachim Nilsson 8e2c58501c Build all unit tests with -W -Wall -Wextra
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 14:02:36 +02:00
Joachim Nilsson 1da317ce1e Add missing signal.h include
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 14:02:27 +02:00
Joachim Nilsson fe39284d50 Travis-CI: Verify installation and run unit tests
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 12:42:33 +02:00
Joachim Nilsson c3c23b9aef Update ChangeLog for upcoming v1.7.1 fix release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 12:39:50 +02:00
Joachim Nilsson d45f2bad5b Update pidfile() description with hidden features
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 12:35:01 +02:00
Joachim Nilsson 61fb7aeca2 New unit test framework, first test pidfile funcs
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 12:30:35 +02:00
Joachim Nilsson dedcaf92d5 Minor style fix, to keep with pidfile.c style
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 12:16:14 +02:00
Joachim Nilsson c009c49a92 Expose __pidfile_path to override _PATH_VARRUN
This patch makes it possible to override the default pidfile() path used
for PID files, _PATH_VARRUN, with a custom path, e.g. _PATH_TMP.

This change does not affect the ABI of pidfile()

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 12:14:26 +02:00
Joachim Nilsson 12f619a320 Fix minor build error in new strndupa() header
Wrong path to local strnlen.h file.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-06 11:04:17 +02:00
Joachim Nilsson c1b3b76ea3 Update ChangeLog and bump version for v1.7.0 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-05 00:36:43 +02:00
Joachim Nilsson 8108b8ec14 Add HACKING.md for release policy ABI versioning etc.
Most of the text shamelessly stolen from the libConfuse project :)

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-04 19:01:18 +02:00
Joachim Nilsson 0e2d365eb9 Update ChangeLog with fixes and new features
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-04 18:56:07 +02:00
Joachim Nilsson 8b499aa9cd Add compat strnlen() implementation for non-GLIBC systems
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-04 18:51:25 +02:00
Joachim Nilsson f4fa44fe60 Add strndupa.h to distribution and update README
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-04 15:13:16 +02:00
Joachim Nilsson be08bcd09d strndupa.h: #error if building with non-GCC on non-GNU systems
At the moment only GCC is supported on non-GNU systems, unfortunately.
GNU systems usually have GLIBC, or another library with strndupa().
This strndupa() implementation requires GCC for the builtin alloca API.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-04 15:12:02 +02:00
Joachim Nilsson 1495a3f858 Add compat strndupa() implementation from libnostd
This patch adds compat support, to *BSD and other UNIX, for the GLIBC
strndupa() function.  The implementation is taken from libnostd written
by William Ahern.

http://www.25thandclement.com/~william/projects/libnostd.html

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-04 15:07:17 +02:00
Joachim Nilsson 5eb816b4c0 Update ChangeLog and README with new strdupa()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-03 23:12:50 +02:00
Valery Frolov 456c58d52d Add new headers, for strdupa(), to distribution
Signed-off-by: Valery Frolov <fvgenn@gmail.com>
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-03 23:08:08 +02:00
Joachim Nilsson 59869b876e strdupa.h: #error if building with non-GCC on non-GNU systems
At the moment only GCC is supported on non-GNU systems, unfortunately.
GNU systems usually have GLIBC, or another library with strdupa().  This
strdupa() implementation requires GCC for the builtin alloca API.

Followup to pull-request #4

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-02 19:51:43 +02:00
Joachim Nilsson 113c3487bd Add info on building directly from GIT
Followup to pullrequest #4

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-06-02 19:44:49 +02:00
Joachim Nilsson de73e268d3 Merge branch 'abs0-master'
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-05-30 22:32:43 +02:00
Joachim Nilsson b57c257f09 Cleanup of old shared rules.mk file, now only used by unit tests.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-05-30 22:31:59 +02:00
Joachim Nilsson 94d42b3df7 Add compat strdupa() implementation from libnostd
This patch adds compat support, to *BSD and other UNIX, for GLIBC
strdupa() function, used in mkpath().  The implementation is taken
from http://www.25thandclement.com/~william/projects/libnostd.html
by William Ahern.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-05-30 22:29:30 +02:00
Joachim Nilsson 94ad65a121 Factor out string functions to lite/strlite.h
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-05-30 22:27:41 +02:00
David Brownlee f3f6947604 Handle old Linux/(G)LIBC and UNIX systems the same
Linux systems pre Linux 3.11, and UNIX do not have the O_TMPFILE flag,
so let's treat them the same, by wrapping tmpfile().

Signed-off-by: David Brownlee <abs@absd.org>
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-05-30 21:05:21 +02:00
Joachim Nilsson 613d397161 Fix mkpath() to handle relative dirs
After input from both StackOverflow and Valery Frolov.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-05-23 09:15:50 +02:00
Joachim Nilsson 7df1b75fa0 Bump version for v1.6.0 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-05-13 07:22:25 +02:00
Joachim Nilsson 9b1b7ca4cf ChangeLog: Fix Markdown links in v1.6.0 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-05-13 07:21:45 +02:00
Joachim Nilsson 1e064b8b4d Update ChangeLog for v1.6.0 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-05-12 21:13:10 +02:00
Joachim Nilsson 18dde87f0a Add NetBSD fparseln(3) v1.10
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-05-09 19:14:05 +02:00
Joachim Nilsson fcb38c9cc5 Constify fisdir() argument
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-05-09 19:10:05 +02:00
Joachim Nilsson ab69ae8374 Add OpenBSD reallocarray(3) v1.2
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-05-09 00:37:05 +02:00
Joachim Nilsson 95f7a91a8a Bump version for v1.6.0 release cycle
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-05-09 00:33:16 +02:00
Joachim Nilsson aab5a1145c Remove Emacs version-control handling
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-05-07 22:35:49 +02:00
Joachim Nilsson fe1a3a731d Update ChangeLog and bump version for v1.5.1 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-17 16:27:02 +02:00
Joachim Nilsson cd073f5221 fcopyfile: Westermo fixes and code simplification
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-17 16:17:00 +02:00
Joachim Nilsson 1a9d3bd91b Spellcheck
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-17 01:25:46 +02:00
Joachim Nilsson 8cc267f259 Markdown formatting
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-17 01:03:53 +02:00
Joachim Nilsson 35d396ec27 Is --> Are, a --> an ...
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-17 01:02:09 +02:00
Joachim Nilsson 7e91307138 Add Table of Contents
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-17 00:54:22 +02:00
Joachim Nilsson 2b8f54fbc7 Update build & install instructions
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-17 00:53:57 +02:00
Joachim Nilsson 2e58dd3203 Simplify configure script
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-17 00:47:21 +02:00
Joachim Nilsson 41392f7e85 Remove bogus autoconf version requirement
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-17 00:46:58 +02:00
Joachim Nilsson e4329d6c25 Add some integration tips when using GNU autotools
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-17 00:46:14 +02:00
Joachim Nilsson 7113b3d1d8 Add basic TODO file to keep track of stuff
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-11 01:24:53 +02:00
Joachim Nilsson 9b6ef1f053 pidfile(): Activate use of utimensat() to update atime+mtime
Due to problems with the unit tests the use of utimensat() in pidfile()
was disabled, and forgotten.  This patch enables it, but beware, this
thing is QUICK on any system with a L2 cache or better.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-04-11 01:18:57 +02:00
Joachim Nilsson efc70e3a75 Update ChangeLog and bump version for v1.5.0 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-20 02:24:26 +01:00
Joachim Nilsson 147df0c6da ABI revision bump
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-20 02:21:33 +01:00
Joachim Nilsson 7f89000c6c pidfilefn.c: Update unittests, add mtime test and prettyfy output
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-20 02:15:35 +01:00
Joachim Nilsson 7607148d46 Build unit tests with -g -O0 for debugging
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-20 02:14:55 +01:00
Joachim Nilsson 979f76aea7 pidfile(): Use utimensat() to update atime+mtime
This patch update the `-lite` patch to OpenBSD `pidfile()` by changing
the update atime+mtime patch from writing the PID again to instead use
utimensat(). Less overhead and nanosecond resolution.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-20 02:14:30 +01:00
Joachim Nilsson ac41fa70aa Update ChangeLog and bump version to v1.5.0-dev
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-13 01:59:41 +01:00
Joachim Nilsson 5f820b17b6 Change namespace for header files libite/lite.h --> lite/lite.h
The `libite/` namespace for header files has been the same since the
first public release in v1.0.0.  This patch surprisingly changes it to
the less surprising `lite/`.  Hopefully there aren't that many users of
this library out there yet, apart from myself.

Apologies if you are affected!

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-13 01:58:56 +01:00
Joachim Nilsson 53b715c094 Remove surprise from pkg-config output
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-03-13 00:38:53 +01:00
Joachim Nilsson 1b4cd7b20b Update ChangeLog and bump version for v1.4.4 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-23 14:23:12 +01:00
Joachim Nilsson 8e379ca358 Update ChangeLog
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-22 19:11:29 +01:00
Joachim Nilsson 12241dcdfe libite.pc.in: Remove spurious @LTLIBINTL@ after copy-paste from libConfuse
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-20 22:26:24 +01:00
Joachim Nilsson 0ce1b3bf44 Add pkg-config support
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-20 22:03:25 +01:00
Joachim Nilsson 38ff0af61a Update ChangeLog with details on issue #3
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-15 18:20:25 +01:00
Joachim Nilsson 00737a5b74 Merge pull request #3 from askerin/tempfile-archfix
Tempfile() is dependent on $ARCH

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-12 16:15:53 +01:00
Joachim Nilsson 1b8b164ed4 Test build with both GCC and Clang (LLVM)
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-12 16:15:15 +01:00
Joachim Nilsson 9f279c0fec Disable sudo for build while auto-tests are reintegrated
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-12 16:14:59 +01:00
Johan Askerin 4d7e6d4f78 In tempfile(): O_DIRECTORY is dependent on $ARCH, don't hardcore O_TMPFILE
Signed-off-by: Johan Askerin <johan.askerin@gmail.com>
2016-02-12 15:17:25 +01:00
Joachim Nilsson 0a57f2128f Update ChangeLog and bump version for v1.4.3 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-02 09:37:40 +01:00
Joachim Nilsson e254db48a8 Remove AUTHORS file from distribution, doesn't exist
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-02 08:40:14 +01:00
Joachim Nilsson 0fe429dcbe Update ChangeLog in preparation for v1.4.3 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-02 08:25:16 +01:00
Joachim Nilsson f1a2e01775 Makefile.am: Update to install and distribute README.md, LICENSE, etc.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-02 08:24:15 +01:00
Joachim Nilsson e5eef2ae59 Remove confusing symlinks, it's a brave Markdown world
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-02-02 08:22:13 +01:00
Joachim Nilsson f9caffc9b7 Update ChangeLog and bump version for v1.4.2 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-23 11:29:50 +01:00
Joachim Nilsson 604b503b84 Fix issue #2: GCC6 -Wmisleading-indentation causing FTBFS in pimd
- Add function comment
- Fix misleading indentaion
- Fix coding sttle

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-23 11:16:53 +01:00
Joachim Nilsson 5fc248522c Update ChangeLog and bump version for v1.4.1 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-22 01:07:35 +01:00
Joachim Nilsson c0b8bab164 Use pkginclude_HEADERS for libite include files
The v1.4.0 release installs the header files in $(prefix)/include, this
patch installs them in the proper $(prefix)/include/$(PACKAGE) dir.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-22 01:03:19 +01:00
Joachim Nilsson c0e9c0431a Bump version for 1.4.1-dev cycle
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-22 01:01:22 +01:00
Joachim Nilsson efdd61648a Update ChangeLog and bump version for release v1.4.0
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-22 00:05:01 +01:00
Joachim Nilsson 2e8e64fd2a Step ABI version 2:0:0 --> 2:1:0
Slight change in how `pidfile()` behaves, now exporting __pidfile_name.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-22 00:01:19 +01:00
Joachim Nilsson c4109e7e74 Add Niels Provos' famous splay and red-black tree implementation
This is the OpenBSD sys/tree.h r1.14

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-21 23:51:40 +01:00
Joachim Nilsson 5d07594709 Update pidfile() documentation and add unit test for __pidfile_name
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-21 23:30:08 +01:00
Joachim Nilsson 253460b4b8 Make pidfile() name accessible (read-only) to daemon as __pidfile_name
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-21 23:28:59 +01:00
Joachim Nilsson acc59e0c1f Remove AM_MAINTAINER_MODE from configure script, not recommended anymore
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-21 22:32:23 +01:00
Joachim Nilsson 90374fc237 README: Add a Build & Install section
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-18 20:11:19 +01:00
Joachim Nilsson 7f375b6e9d Remove -Werror due to O_TMPFILE is missing on older kernels
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-14 21:49:49 +01:00
Joachim Nilsson e4236db2bd Ignore all generated files from build system
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-14 21:43:02 +01:00
Joachim Nilsson 42a5a906fc ChangeLog: Prepare for upcoming v1.4.0 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-14 21:28:08 +01:00
Joachim Nilsson 10b28127f5 Update .gitignore, add bogus m4/.gitignore to make Travis-CI happy
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-14 21:27:04 +01:00
Joachim Nilsson d265a05422 Update build script for Travis-CI with GNU configure and build system
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-14 18:56:01 +01:00
Joachim Nilsson f07c05138d Initial conversion to the GNU configure and build system
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-14 17:40:26 +01:00
Joachim Nilsson e1f8224666 Update ChangeLog and bump version for release v1.3.0
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-07 02:58:06 +01:00
Joachim Nilsson 84650d8836 Update include file boiler plate
We're not in Kansas anymore, Toto.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-07 02:58:06 +01:00
Joachim Nilsson b4fbd54a8c Update copyright years
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-07 02:58:06 +01:00
Joachim Nilsson c14c6a1e62 pidfile.c: Add LITE #ifdef pidfile and comment LITE mtime extension
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-07 02:58:06 +01:00
Joachim Nilsson 8aecba2b7a strtonum.c: Update to OpenBSD v1.7, style tweaks
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-07 02:58:06 +01:00
Joachim Nilsson 74dcaddc55 strlcat.c: Update to OpenBSD v1.14, readability fixes
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-07 02:57:59 +01:00
Joachim Nilsson c5a36ff7bd strlcpy.c: Update to OpenBSD v1.12, readability fixes
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-07 02:57:51 +01:00
Joachim Nilsson 3371e42035 queue.h: Update to OpenBSD v1.43 -- NOTE: Removes CIRCLEQ support!
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-07 02:03:10 +01:00
Joachim Nilsson 4e57a78255 README: Update section on OpenBSD Functions as well
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-06 13:35:35 +01:00
Joachim Nilsson ce3bd4ec8a README: Update documentation for pidfile() fn
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-06 13:31:32 +01:00
Joachim Nilsson 805571a7ef ChangeLog: Fix missing README link
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-05 13:34:41 +01:00
Joachim Nilsson 36435997bf ChangeLog: Fix Markdown links
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-05 13:33:34 +01:00
Joachim Nilsson f961889724 Add documentation for new macros and prepare ChangeLog for v1.3.0
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-05 13:27:40 +01:00
Tobias Waldekranz 6605fb9771 Makefile: Make sure queue.h and conio.h also are installed
This patch adds the BSD queue.h and the Borland inspired conio.h to the
install-dev Makefile target.

Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-05 13:17:16 +01:00
Tobias Waldekranz 61254279b9 lite.h: Add min() and max() macros
These macros take care to avoid double evaluation.

Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-05 13:16:34 +01:00
Joachim Nilsson e42aca8856 Makefile: Split install-dev taget into install-dev and install-data
This makes it possible to skip installing any unnecessary cruft.
Useful for embedded targets.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-05 13:14:37 +01:00
Joachim Nilsson 16611f3e5f Add ChangeLog to project and bump version for new release cycle
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2016-01-05 13:13:26 +01:00
Joachim Nilsson 975df87d6b Update unit test for pidfile()
Add ocular verification step for mtime update when pidfile() is
called more than once.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-12-17 00:15:18 +01:00
Joachim Nilsson 148027674a pidfile: Only update mtime i called multiple times
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-12-16 18:40:34 +01:00
Joachim Nilsson 12ed342d55 Bump version for v1.2.0 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-11-23 00:32:56 +01:00
Joachim Nilsson 23badc990d lfile: Improve unittest/example with /etc/group + passwd
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-26 00:50:18 +01:00
Joachim Nilsson ca53e097c3 lfile: Initialize strtok_r() save pointer
Must initialize the save pointer in the parser context, otherwise
strtok_r() will fail on statically built embedded targets.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-26 00:16:36 +01:00
Joachim Nilsson a7b5c240c1 Add UNIX lfile_t parser API to lite.h
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-25 23:25:17 +01:00
Joachim Nilsson c4eb5cb124 Add simple parser for UNIX configuration files.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-25 22:50:10 +01:00
Joachim Nilsson db08b20f23 Make sure we don't inherit LDFLAGS from environment.
To pass custom LDFLAGS to libite, use EXTRA_LDFLAGS.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-22 18:35:35 +02:00
Joachim Nilsson 8779f54125 Do not allow VERSION to be overloaded by build system.
When integrating libite as a component in another piece of software,
that build system may set VERSION as an environment variable.  We do
not want that version to be set as the version of libite.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2015-10-03 09:13:37 +02:00
72 changed files with 2959 additions and 1174 deletions

No files matched your search

+19
View File
@@ -1,5 +1,24 @@
*~
*.d
*.o
*.so
*.so.*
*.a
.deps
.libs
tmp/
compile
config.*
configure
depcomp
install-sh
libtool
ltmain.sh
missing
stamp-h1
Makefile
Makefile.in
aclocal.m4
ar-lib
autom4te.cache
libite*
+15 -6
View File
@@ -1,11 +1,20 @@
# Travis CI integration -- https://travis-ci.org/troglobit/libuev
# Travis CI integration -- https://travis-ci.org/troglobit/libite
# Defaults to GNU GCC and autotools: ./configure && make && make test
language: c
# Some of the autotests may use sudo, so use non-dockerized build atm.
# http://stackoverflow.com/questions/26299552/travis-sudo-is-disabled
sudo: true
# Use docker for quicker builds, it now allows https://docs.travis-ci.com/user/apt/
sudo: false
# Test build with both GCC and Clang (LLVM)
compiler:
- gcc
- clang
script:
- make
- make test
- ./autogen.sh
- ./configure --prefix=/tmp --disable-silent-rules
- make clean
- make -j5
- make install-strip
- ls -lR /tmp
- make check
+223
View File
@@ -0,0 +1,223 @@
Change Log
==========
All notable changes to the project are documented in this file.
[v1.8.0][] - 2016-06-06
-----------------------
### Changes
- Change return type of `fsendfile()` from `size_t` to `ssize_t`
- Change `dir()` semantics: do not assert and always return error
without calling `perror()` or similar.
- The OpenBSD `pidfile()` function's prefix path `_PATH_VARRUN`
can now be overridden by setting the hidden `__pidfile_path`
variable. E.g., to `_PATH_TMP`. Make sure read the docs!
- Add new unit test framework `make check`.
### Fixes
- Fix bad path in new `strndupa()` header file.
- Add missing progress bar API's to `lite.h`
[v1.7.0][] - 2016-06-05
-----------------------
### Changes
- Add support for GNU `strdupa()`, for [Inadyn][] on NetBSD.
- Add support for GNU `strndupa()` and `strnlen()`
### Fixes
- Fix `mkpath()` to handle creating relative directories.
[v1.6.0][] - 2016-05-13
-----------------------
### Changes
- Add support for NetBSD `fparaseln()` for the benefit of [Mg][]
- Add support for OpenBSD `reallocarray()` for the benefit of [Mg][]
- Constify `fisdir()` argument
[v1.5.1][] - 2016-04-17
-----------------------
Minor fix release.
### Changes
- Update README.md, add help when libite is used in autotools projects.
Spell checking and minor cleanup.
### Fixes
- Activate use of `utimensat()` when `pidfile()` is called multiple
times. This reduces the overhead of calling open+write+close to
simply updating the mtime of the PID file.
- Westermo fixes for `fcopyfile()`: nothing copied on embedded PPC
system when using `tmpfile()` as source.
[v1.5.0][] - 2016-03-20
-----------------------
This release changes the header file namespace. Apologies for any
problems this may cause!
### Changes
- Change namespace for header files: `libite/` to `lite/`, e.g. using
`pkg-config` your C program must now `#include <lite/lite.h>`
- Update `pidfile()` to use `utimensat()` to update atime+mtime instead
of opening and writing PID again. Less overhead and nanonsecond res.
[v1.4.4][] - 2016-02-23
-----------------------
### Changes
- Add `ibite.pc.in` for `pkg-config` support.
### Fixes
- Fix issue #3: `tempfile()` fails with bad `O_TMPFILE` on some embedded
targets, in particular PowerPC. On systems with older GLIBC but with
a sufficiently new kernel `O_TMPFILE` is missing and the local libite
definition was wrong, hard coded for x86. Fixed by Johan Askerin.
[v1.4.3][] - 2016-02-02
-----------------------
### Fixes
- Remove symlinks to Markdown files from GIT
- Distribute and install Markdown files: README.md, etc.
[v1.4.2][] - 2016-01-23
-----------------------
### Fixes
- Fix issue #2: GCC6 `-Wmisleading-indentation` causing FTBFS in pimd,
which enables `-Werror`
[v1.4.1][] - 2016-01-22
-----------------------
### Fixes
- Fix install path for include files, regression in v1.4.0 With the
introduction of GNU autotools include file namespace was unfortunately
lost. All include files were therefore installed in $(prefix)/include
instead of $(prefix)/include/libite.
[v1.4.0][] - 2016-01-22
-----------------------
### Changes
- Change to GNU configure and build system
- Add Niels Provos' splay and red-black tree implementation from OpenBSD
`sys/tree.h`, r1.14
- Make `pidfile()` file name accessible as `__pidfile_name`
- Step ABI revision to 2.1, with help from http://250bpm.com/blog:41
[v1.3.0][] - 2016-01-07
-----------------------
### Changes
- Add highly useful typeless `min()`/`max()` macros to `lite.h`,
courtesy of Tobias Waldekranz
- Add BSD `queue.h` and Borland inspired `conio.h` to `install-dev`
target. Needed by [Finit][].
- Note, this release update `queue.h` to OpenBSD v1.43, which removes
support for circular queues (CIRCLEQ).
- Update `strlcpy.c` to OpenBSD v1.12, readability fixes.
- Update `strlcat.c` to OpenBSD v1.14, readability fixes.
- Update `strtonum.c` to OpenBSD v1.7, tiniest of style tweaks.
### Fixes
- Only update mtime if `pidfile()` is called more than once, do not
install multiple `atexit()` handlers.
- Add `#ifndef pidfile`, as for other BSD functions, in case the user
already have a local copy, or a C library with one.
[v1.2.0][] - 2015-11-23
-----------------------
### Changes
- Add simple parser for UNIX configuration files, e.g. `/etc/group`,
`/etc/passwd`, and `/etc/protocols`:
- `lfopen()`
- `lfclose()`
- `lftok()`
- `lfgetkey()`
- `lfgetint()`
- `fgetint()`
### Fixes
- Do not allow `VERSION` to be overloaded by build system.
- Make sure we don't inherit `LDFLAGS` from environment.
[v1.1.1][] - 2015-09-27
-----------------------
### Fixes
* Silence annoying warnings from GNU ar
* Fix macro definitions for compat APIs
[v1.1.0][] - 2015-09-16
-----------------------
### Changes
- Support for `make distdir` used by automake based projects
- `lite.h` move from `error.h` to more BSD friendly `err.h`
- Add highly useful `NELEMS()` and bitmanip macros
- Lots of autotests added
- Add support for running autotests from Travis
- Add `progress()` simple progress bar
- Add `tree()` simple command line tree replacement
- Bump `SONAME` to `libite.so.2` on behalf of [Finit][]
### Fixes
- `pidfile()` upgrade to OpenBSD r1.11
- Lots of README updates, fixes and additions
[v1.0.0][] - 2015-07-12
-----------------------
Initial extraction of frog DNA from [Finit][]. See [README][] for API details.
[UNRELEASED]: https://github.com/troglobit/libite/compare/v1.8.0...HEAD
[v1.8.0]: https://github.com/troglobit/libite/compare/v1.7.0...v1.8.0
[v1.7.0]: https://github.com/troglobit/libite/compare/v1.6.0...v1.7.0
[v1.6.0]: https://github.com/troglobit/libite/compare/v1.5.1...v1.6.0
[v1.5.1]: https://github.com/troglobit/libite/compare/v1.5.0...v1.5.1
[v1.5.0]: https://github.com/troglobit/libite/compare/v1.4.4...v1.5.0
[v1.4.4]: https://github.com/troglobit/libite/compare/v1.4.3...v1.4.4
[v1.4.3]: https://github.com/troglobit/libite/compare/v1.4.2...v1.4.3
[v1.4.2]: https://github.com/troglobit/libite/compare/v1.4.1...v1.4.2
[v1.4.1]: https://github.com/troglobit/libite/compare/v1.4.0...v1.4.1
[v1.4.0]: https://github.com/troglobit/libite/compare/v1.3.0...v1.4.0
[v1.3.0]: https://github.com/troglobit/libite/compare/v1.2.0...v1.3.0
[v1.2.0]: https://github.com/troglobit/libite/compare/v1.1.1...v1.2.0
[v1.1.1]: https://github.com/troglobit/libite/compare/v1.1.0...v1.1.1
[v1.1.0]: https://github.com/troglobit/libite/compare/v1.0.0...v1.1.0
[v1.0.0]: https://github.com/troglobit/libite/compare/TAIL...v1.0.0
[Finit]: https://github.com/troglobit/finit/
[Inadyn]: https://github.com/troglobit/inadyn/
[Mg]: https://github.com/troglobit/mg
[README]: https://github.com/troglobit/libite/blob/v1.0.0/README.md
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->
+85
View File
@@ -0,0 +1,85 @@
Maintenance and Release Checklist
=================================
Maintenance
-----------
* Leverage GitHub issues for milestone planning
* Reference issues from GitHub pull requests to alert issue subscribers
* Encourage contributors to write unit tests
* Bump library ABI version just before release!
Release Checklist
-----------------
* Update ChangeLog, follow http://keepachangelog.com/ loosely
- Inform users in a plain language of changes and bug fixes
- Do *not* copy-paste GIT commit logs!
- Order entrys according to importance, most relevant first
* Do we need to bump the ABI version? (Probably, see below)
* Tag
* Push last commit(s) *and* tags to GitHub
* Make release
make distclean
./autogen.sh
./configure
make release
* Create new release in GitHub releases page
* Copy and paste ChangeLog entry, check any stale links!
* Upload release tarball and MD5 files
Library Versioning
------------------
Libite (-lite) relies on GNU Libtool for building the library. For a
user of the library it is important to maintain a clear ABI versioning
scheme. This is not the same as the library version, but rather the
library "compatibility level".
The ABI version is specified in `src/Makefile.am` and looks like this:
libite_la_LDFLAGS = -version-info 0:0:0
\ \ `-- age
\ `--- revision
`---- current
It must be updated according to the [GNU Libtool recommendations][1]:
1. Start with version information of `0:0:0` for each libtool library.
2. Update the version information only immediately before a public
release of your software. More frequent updates are unnecessary, and
only guarantee that the current interface number gets larger faster.
3. If the library *source code has changed at all* since the last update,
then increment revision (`c:r:a` --> `c:r+1:a`)
4. If any *interfaces have been added, removed, or changed* since last
update, increment current, and zero revision (`c:r:a` --> `c+1:0:0`)
5. If any *interfaces have been added* since the last public release,
then increment age.
6. If any *interfaces have been removed or changed* since the last
public release, then set age to 0.
Usually, non-developers have no interest in running development versions
(releases are frequent enough), and developers are expected to know how
to juggle versions. In such an ideal world, it is good enough to bump
the library version just prior to a release, point 2.
However, if releases are few and far between, distributors may start to
use snapshots. When a distributor uses a snapshot, the distributor has
to handle the library version manually. Things can get ugly when the
distributor has released an intermediate version with a bumped library
version, and when the official release is bumped to that version, the
distributor will then have to bump the library version for the official
release, and it can be confusing if someone reports bugs on versions
that you didn't even know existed.
The problem with bumping the version with every change is that if your
interface is not finished, the version number might run away, and it
looks pretty bad if a library is at version 262. It kind of tells the
user that the library interface is volatile, which is not good for
business.
[1]: https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
+1 -1
View File
@@ -4,7 +4,7 @@ the Finit code base and included pieces of software released under the ISC
and BSD licenses. See each respective file for license details.
Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
Copyright (c) 2008-2015 Joachim Nilsson <troglobit@gmail.com>
Copyright (c) 2008-2016 Joachim Nilsson <troglobit@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
-125
View File
@@ -1,125 +0,0 @@
# libite -- Light-weight utility functions and C-library extensions
#
# Copyright (c) 2008-2015 Joachim Nilsson <troglobit@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
.PHONY: install test
#VERSION = $(shell git tag -l | tail -1)
VERSION ?= 1.1.1
NAME = libite
PKG = $(NAME)-$(VERSION)
ARCHIVE = $(PKG).tar.xz
CFLAGS += -fPIC
CPPFLAGS += -W -Wall
DISTFILES = README LICENSE
HEADERS = lite.h
OBJS := chomp.o copyfile.o dir.o fexist.o fisdir.o fmode.o fsendfile.o
OBJS += ifconfig.o makepath.o pidfile.o pidfilefn.o progress.o rsync.o
OBJS += strlcpy.o strlcat.o strtonum.o tempfile.o tree.o
DEPS := $(OBJS:.o=.d)
JUNK = *~ *.bak *.map .*.d *.d DEADJOE semantic.cache *.gdb *.elf core core.*
VER = 2
LIBNAME = $(NAME)
SOLIB = $(LIBNAME).so.$(VER)
SYMLIB = $(LIBNAME).so
STATICLIB = $(LIBNAME).a
TARGET = $(STATICLIB) $(SOLIB)
# This magic trick looks like a comment, but works on BSD PMake
#include <rules.mk>
include rules.mk
test: clean
$(MAKE) -f chomp.mk
$(MAKE) -f copyfile.mk
$(MAKE) -f dir.mk
$(MAKE) -f fexist.mk
$(MAKE) -f fisdir.mk
$(MAKE) -f fsendfile.mk
$(MAKE) -f makepath.mk
$(MAKE) -f pidfilefn.mk
$(MAKE) -f progress.mk
$(MAKE) -f rsync.mk
$(MAKE) -f tempfile.mk
$(MAKE) -f tree.mk
$(OBJS): Makefile
$(SOLIB): Makefile $(OBJS)
$(PRINT) " LINK %s\n" $@
$(Q)$(CC) $(LDFLAGS) -shared -Wl,-soname,$@ -o $@ $(OBJS)
$(STATICLIB): Makefile $(OBJS)
$(Q)$(PRINT) " ARCHIVE $@\n"
$(Q)$(AR) $(ARFLAGS) $@ $(OBJS) 2>/dev/null
install-exec: all
$(PRINT) " INSTALL $(DESTDIR)$(libdir)/$(SOLIB)\n"
$(Q)install -d $(DESTDIR)$(libdir)
$(Q)$(STRIPINST) $(SOLIB) $(DESTDIR)$(libdir)/$(SOLIB)
$(Q)ln -sf $(SOLIB) $(DESTDIR)$(libdir)/$(SYMLIB)
install-dev:
$(Q)install -d $(DESTDIR)$(incdir)/$(LIBNAME)
$(Q)for file in $(HEADERS); do \
printf " INSTALL $(DESTDIR)$(incdir)/$(LIBNAME)/$$file\n"; \
$(INSTALL) -m 0644 $$file $(DESTDIR)$(incdir)/$(LIBNAME)/$$file; \
done
$(PRINT) " INSTALL $(DESTDIR)$(libdir)/$(STATICLIB)\n"
$(Q)install -d $(DESTDIR)$(libdir)
$(Q)$(INSTALL) $(STATICLIB) $(DESTDIR)$(libdir)/$(STATICLIB)
$(Q)install -d $(DESTDIR)$(datadir)
$(Q)for file in $(DISTFILES); do \
printf " INSTALL $(DESTDIR)$(datadir)/$$file\n"; \
install -m 0644 $$file $(DESTDIR)$(datadir)/$$file; \
done
install: install-exec install-dev
uninstall:
-$(Q)$(RM) -r $(DESTDIR)$(datadir)
-$(Q)$(RM) -r $(DESTDIR)$(incdir)/$(LIBNAME)
-$(Q)$(RM) $(DESTDIR)$(libdir)/$(SOLIB)
-$(Q)$(RM) $(DESTDIR)$(libdir)/$(SYMLIB)
-$(Q)$(RM) $(DESTDIR)$(libdir)/$(STATICLIB)
strip: $(TARGET)
$(Q)$(PRINT) " STRIP %s\n" $(TARGET)
$(Q)$(STRIP) --strip-unneeded $(TARGET)
$(Q)size $(TARGET)
# Runs Clang scan-build on the whole tree
check: clean
$(Q)scan-build $(MAKE) all
# When called from GNU configure and build system
distdir:
@git archive --format=tar HEAD | (cd $(distdir); tar xf -)
dist:
$(Q)echo "Building .xz tarball of $(PKG) in parent dir..."
git archive --format=tar --prefix=$(PKG)/ v$(VERSION) | xz >../$(ARCHIVE)
$(Q)(cd ..; md5sum $(ARCHIVE) | tee $(ARCHIVE).md5)
# Include automatically generated rules
-include $(DEPS)
+52
View File
@@ -0,0 +1,52 @@
ACLOCAL_AMFLAGS = -I m4
lib_LTLIBRARIES = libite.la
pkgincludedir = $(includedir)/lite
pkginclude_HEADERS = lite.h queue.h conio.h tree.h strlite.h strdupa.h strndupa.h strnlen.h
libite_la_SOURCES = chomp.c copyfile.c dir.c fexist.c fisdir.c fmode.c fparseln.c \
fsendfile.c ifconfig.c lfile.c makepath.c pidfile.c pidfilefn.c \
progress.c reallocarray.c rsync.c strlcpy.c strlcat.c strtonum.c \
tempfile.c tree.c
libite_la_CPPFLAGS = -D_GNU_SOURCE
libite_la_CFLAGS = -W -Wall -Wextra
libite_la_LDFLAGS = $(AM_LDFLAGS) -version-info 3:0:0
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libite.pc
doc_DATA = README.md LICENSE
EXTRA_DIST = README.md LICENSE ChangeLog.md
SUBDIRS = tests
## Generate MD5 checksum file
MD5 = md5sum
md5-dist:
@for file in $(DIST_ARCHIVES); do \
$(MD5) $$file > $$file.md5; \
done
## Check if tagged in git
release-hook:
if [ ! `git tag | grep $(PACKAGE_VERSION)` ]; then \
echo; \
printf "\e[1m\e[41mCannot find release tag $(PACKAGE_VERSION)\e[0m\n"; \
printf "\e[1m\e[5mDo release anyway?\e[0m "; read yorn; \
if [ "$$yorn" != "y" -a "$$yorn" != "Y" ]; then \
printf "OK, aborting release.\n"; \
exit 1; \
fi; \
echo; \
else \
echo; \
printf "\e[1m\e[42mFound GIT release tag $(PACKAGE_VERSION)\e[0m\n"; \
printf "\e[1m\e[44m>>Remember to push tags!\e[0m\n"; \
echo; \
fi
## Target to run when building a release
release: dist release-hook md5-dist
@for file in $(DIST_ARCHIVES); do \
printf "$$file \tDistribution tarball\n"; \
printf "$$file.md5\t"; cat $$file.md5 | cut -f1 -d' '; \
mv $$file* ../; \
done
-1
View File
@@ -1 +0,0 @@
README.md
+166 -23
View File
@@ -2,16 +2,32 @@
===========================
[![Travis Status][]][Travis]
Table of Contents
-----------------
* [Introduction](#introduction)
* [Using -lite](#using--lite)
* [Helper Macros](#helper-macros)
* [Generic Functions](#generic-functions)
* [OpenBSD Functions](#openbsd-functions)
* [Build & Install](#origin--references)
* [TODO](#todo)
Introduction
------------
Libite is a lightweight library of *frog DNA*. It can be used to fill
the gaps in any dinosaur project. It holds useful functions and macros
developed by both [Finit][1] and the [OpenBSD][2] project. Most notably
the string functions: [strlcpy(3)][3], [strlcat(3)][3] and the highly
useful *BSD [sys/queue.h][4] API.
useful *BSD [sys/queue.h][4] and [sys/tree.h][7] API's.
Libite aims to fill in the gaps missing in GLIBC/EGLIBC. (It does not
aimo to become another [GLIB][5] though.) One such gap in GLIBC is the
missing `_SAFE` macros in `sys/queue.h` &mdash; highly recommended when
traversing lists to delete/free nodes.
Libite is the frog DNA missing in GNU libc. However, -lite does not aim
to become another [GLIB][5]! One noticeable gap in GLIBC is the missing
`_SAFE` macros in the BSD `sys/queue.h` API &mdash; highly recommended
when traversing lists to delete/free nodes.
The code is open sourced under a mix of the [MIT/X11 license][MIT], the
[ISC license][ISC] used by OpenBSD, and [BSD licenses][BSD], all of them
@@ -22,6 +38,38 @@ For an introduction to why Libite happened, and how you can use it, see
[this blog post][6].
Using -lite
-----------
Libite is by default installed as a library and a set of include files.
To prevent clashing with include files of the same name `-lite` employs
an include file namespace `lite/`, which is strongly recommended to use
in your applications:
#include <lite/lite.h>
#include <lite/conio.h>
#include <lite/queue.h>
#include <lite/tree.h>
The output from the `pkg-config` tool holds no surprises in this regard:
$ pkg-config --libs --static --cflags libite
-I/usr/local/include -L/usr/local/lib -lite
The prefix path `/usr/local/` shown here is only the default. Use the
`configure` script to select a different prefix when installing libite.
For GNU autotools based projects, use the following in `configure.ac`:
# Check for required libraries
PKG_CHECK_MODULES([lite], [libite >= 1.5.0])
and in your `Makefile.am`:
proggy_CFLAGS = $(lite_CFLAGS)
proggy_LDADD = $(lite_LIBS)
Helper Macros
-------------
@@ -40,19 +88,23 @@ Helper Macros
- `erase(path)`
Erase file/directory with `remove()`. Errors on stderr
Erase file/directory with `remove()`. Errors on `stderr`
- `makedir(path)`
Create directory, like `mkdir()`. Errors on stderr
Create directory, like `mkdir()`. Errors on `stderr`
- `makefifo(path)`
Create a FIFO, like `mkfifo()`. Errors on stderr
Create a FIFO, like `mkfifo()`. Errors on `stderr`
- `min(a,b)`/`max(a,b)`
These macros take care to avoid double evaluation.
- `touch(path)`
Create a file, or update mtime. Errors on stderr
Create a file, or update mtime. Errors on `stderr`
- `S_ISEXEC(mode_t m)`
@@ -68,7 +120,7 @@ Helper Macros
- `ISOTHER(word,bit)`
Is any other bits, except bit, in (integer) word set?
Are any other bits, except bit, in (integer) word set?
- `SETBIT(word,bit)`
@@ -103,7 +155,8 @@ Generic Functions
Wrapper for `scandir()` with optional filter. Returns a list of
names: files and directories that must be freed after use. See
the unit test at the bottom for an example.
the unit test for an example, or take a look at `glob(3)`, it's
probably what you want anyway.
- `fcopyfile(src, dst)`
@@ -112,11 +165,11 @@ Generic Functions
- `fexist(file)`
Check for the existance of a file, returns True(1) or False(0).
Check for the existence of a file, returns True(1) or False(0).
- `fisdir(path)`
Check for the existance of a directory, returns True(1) or False(0).
Check for the existence of a directory, returns True(1) or False(0).
- `fmode(file)`
@@ -131,7 +184,30 @@ Generic Functions
- `ifconfig(ifname, addr, mask, up)`
Basic ifconfig like operations on an interface. Only supports IPv4
adresses. Note that mask is not CIDR notation.
addresses. Note that mask is not CIDR notation.
- `lfopen(file, sep)`, `lfclose(lf)`
LITE file API for parsing UNIX style configuration files like
`/etc/protocols` and `/etc/services`.
- `lftok(lf)`
Read tokens, delimited by `sep`, from file opened with `lfopen()`.
- `lfgetkey(lf, key)`
Find `key` in file opened with `lfopen()`, return value/argument.
- `lfgetint(lf, key)`
Wrapper for `lfgetkey()`, returns positive integer value to `key`,
or `-1` if `key` is not found.
- `fgetint(file, sep, key)`
Wrapper for `lfopen()`, `lfgetint()`, and `lfclose()`. Useful for
when only reading a single `key` from a file.
- `makepath(dir)`
@@ -149,20 +225,26 @@ Generic Functions
- `pidfile(basename)`
Write a daemon pid file. Creates a pidfile in `_PATH_VARRUN` using
either `basename` or, if `basename` is `NULL`, `__progname`. The
file name has the form `/var/run/basename.pid`.
Create a daemon PID file in `_PATH_VARRUN` using either `basename` or,
if `basename` is `NULL`, `__progname`. The resulting file name is
available to the user as a read-only pointer:
Use this function to create a pid file for your daemon when it is
extern char *__pidfile_name;
Use this function to create a PID file for your daemon when it is
ready to receive signals. A client application may poll for the
existence of this file, so make sure to have your signal handlers
properly setup before calling this function.
The pidfile is removed when the program exits, using an `atexit()`
The PID file is removed when the program exits, using an `atexit()`
handler. However, depending on how the program terminates the file
may still exist even though the program is no longer running. This
is only a problem for clients.
Calling this function multiple times updates the mtime of the file.
Only one `atexit()` handler is created, regardless of the amount of
times the function is called.
See below for link to OpenBSD man page.
- `pidfile_read(pidfile)`
@@ -201,15 +283,52 @@ Generic Functions
set. The `path` argument should be a directory.
OpenBSD Functions
-----------------
GNU Functions
-------------
The following are the popular OpenBSD string functions.
The following are useful GNU functions, that do not exist on *BSD, and
some other platforms.
- `strdupa(str)`
http://man7.org/linux/man-pages/man3/strdupa.3.html
- `strndupa(str)`
http://man7.org/linux/man-pages/man3/strndupa.3.html
- `strnlen(str, lim)`
http://man7.org/linux/man-pages/man3/strnlen.3.html
OpenBSD/NetBSD/FreeBSD Functions
--------------------------------
The following are popular functions and highly useful macros from the
*BSD world of UNIX that are sadly missing on Linux.
- `fparseln(fp, *len, *lineno, delim, flags)`
http://man.openbsd.org/OpenBSD-current/man3/fparseln.3
- `pidfile(basename)`
http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/pidfile.3
**Note:** this version of `pidfile()` has been extended to handle it
being called multiple times, i.e. to not create multiple `atexit()`
handlers, and also to export a few internal paths:
- `__pidfile_path`: prefix path, default `_PATH_VARRUN`. Notice the
trailing slash requirement if you want to override it!
- `__pidfile_name`: full path to PID file , similar to `__progname`.
See previous section for details.
- `reallocarray(ptr, nmemb, size)`
http://man.openbsd.org/OpenBSD-current/man3/reallocarray.3
- `strlcpy(dst, src, len)`
http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/strlcpy.3
@@ -226,6 +345,29 @@ The following are the popular OpenBSD string functions.
http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/LIST_EMPTY.3
- `sys/tree.h` API
Niels Provos' famous splay and red-black tree implementation.
http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/SPLAY_FOREACH.3
Build & Install
---------------
This library was initially built for and developed on GNU/Linux systems
as a light weight utility library, these days NetBSD should also work.
Libite (LITE) employs the de facto standard GNU configure and build
system:
./configure
make -j5
make install-strip
**Note:** When checking code from GitHub, use <kbd>./autogen.sh</kbd> to
generate a `configure` script. It is a generated file and otherwise only
included in released tarballs.
TODO
----
@@ -239,6 +381,7 @@ TODO
[4]: http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/LIST_EMPTY.3
[5]: https://developer.gnome.org/glib/
[6]: http://troglobit.com/blog/2015/07/02/howto-using-lite-with-a-git-based-application/
[7]: http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/SPLAY_FOREACH.3
[MIT]: https://en.wikipedia.org/wiki/MIT_License
[ISC]: https://en.wikipedia.org/wiki/ISC_license
[BSD]: https://en.wikipedia.org/wiki/BSD_licenses
+7
View File
@@ -0,0 +1,7 @@
TODO ... in no particular order
===============================
* Investigate adding FreeBSD pidfile_open() et al
* Investigate FreeBSD libutil library, could be useful for porting between unices
Executable
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
autoreconf -W portability -visfm
-11
View File
@@ -45,19 +45,8 @@ char *chomp(char *str)
return str;
}
#ifdef UNITTEST
#include <stdio.h>
int main(void)
{
int i; char t[][16] = { "hej\ndej", "Slime\n\n\\n", "Tripple\n\n\n", "" };
for (i = 0; t[i][0]; i++) printf("[%02d]: '%s'\n", i, chomp(t[i])); return 0;
}
#endif
/**
* Local Variables:
* compile-command: "make V=1 -f chomp.mk"
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
-4
View File
@@ -1,4 +0,0 @@
OBJS =
TARGET = chomp.test clean
include rules.mk
+14
View File
@@ -0,0 +1,14 @@
AC_INIT(libite, 1.8.0, https://github.com/troglobit/libite/issues)
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
AM_SILENT_RULES([yes])
AC_CONFIG_SRCDIR(lite.h)
AM_CONFIG_HEADER(config.h)
AC_CONFIG_FILES([Makefile tests/Makefile libite.pc])
AC_CONFIG_MACRO_DIR([m4])
AC_PROG_CC
AM_PROG_AR
LT_INIT
AC_OUTPUT
-1
View File
@@ -75,7 +75,6 @@
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
+7 -73
View File
@@ -23,13 +23,9 @@
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include "lite.h"
/* Tests if dst is a directory, if so, reallocates dst and appends src filename returning 1 */
static int adjust_target(char *src, char **dst)
{
@@ -237,89 +233,27 @@ int movefile(char *src, char *dst)
*/
int fcopyfile(FILE *src, FILE *dst)
{
int ret;
char *buffer;
char *buf;
if (!src || !dst) {
errno = EINVAL;
return -1;
}
buffer = malloc(BUFSIZ);
if (!buffer)
buf = malloc(BUFSIZ);
if (!buf)
return -1;
ret = do_copy(fileno(src), fileno(dst), BUFSIZ, buffer, BUFSIZ);
if (ret > 0)
ret = 0;
else if (errno)
ret = -1;
free(buffer);
return ret;
}
#ifdef UNITTEST
#include <err.h>
int main(void)
{
int i = 0;
char *files[] = {
"/etc/passwd", "/tmp/tok", "/tmp/tok",
"/etc/passwd", "/tmp/", "/tmp/passwd",
"/etc/passwd", "/tmp", "/tmp/passwd",
NULL
};
FILE *src, *dst;
printf("=>Start testing fcopyfile()\n");
while (files[i]) {
printf("fcopyfile(%s, %s)\t", files[i], files[i + 1]);
src = fopen(files[i], "r");
dst = fopen(files[i + 1], "w");
if (fcopyfile(src, dst)) {
if (!fisdir(files[i + 1]))
err(1, "Failed fcopyfile(%s, %s)", files[i], files[i + 1]);
}
if (src)
fclose(src);
if (dst)
fclose(dst);
if (fexist(files[i + 2]))
printf("OK => %s", files[i + 2]);
printf("\n");
erase(files[i + 2]);
i += 3;
}
printf("\n=>Start testing copyfile()\n");
i = 0;
while (files[i]) {
printf("copyfile(%s, %s)\t", files[i], files[i + 1]);
if (!copyfile(files[i], files[i + 1], 0, 0))
err(1, "Failed copyfile(%s, %s)", files[i], files[i + 1]);
if (fexist(files[i + 2]))
printf("OK => %s", files[i + 2]);
printf("\n");
erase(files[i + 2]);
i += 3;
}
while (fgets(buf, BUFSIZ, src))
fputs(buf, dst);
free(buf);
return 0;
}
#endif /* UNITTEST */
/**
* Local Variables:
* compile-command: "make V=1 -f copyfile.mk"
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
-4
View File
@@ -1,4 +0,0 @@
OBJS = fisdir.o fexist.o fmode.o
TARGET = $(OBJS) copyfile.test clean
include rules.mk
+13 -110
View File
@@ -1,6 +1,6 @@
/* Functions for operating on files in directories.
*
* Copyright (c) 2008-2014 Joachim Nilsson <troglobit@gmail.com>
* Copyright (c) 2008-2016 Joachim Nilsson <troglobit@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -15,14 +15,14 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <assert.h>
#include <errno.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static const char *matcher_type = NULL;
static int (*matcher_filter) (const char *file) = NULL;
static int matcher(const struct dirent *entry)
{
char *pos = strrchr(entry->d_name, '.');
@@ -72,7 +72,8 @@ static int matcher(const struct dirent *entry)
* would be returned as "config0".
*
* Returns:
* Number of files in @list, zero if no matching files of @type.
* Number of files in @list, zero if no matching files of @type, or
* non-zero on error with @errno set.
*/
int dir(const char *dir, const char *type, int (*filter) (const char *file), char ***list, int strip)
{
@@ -80,7 +81,10 @@ int dir(const char *dir, const char *type, int (*filter) (const char *file), cha
char **files;
struct dirent **namelist;
assert(list);
if (!list) {
errno = EINVAL;
return -1;
}
if (!dir)
/* Assuming current directory */
@@ -92,9 +96,10 @@ int dir(const char *dir, const char *type, int (*filter) (const char *file), cha
matcher_type = type;
matcher_filter = filter;
n = scandir(dir, &namelist, matcher, alphasort);
if (n < 0) {
perror("scandir");
} else if (n > 0) {
if (n < 0)
return -1;
if (n > 0) {
files = (char **)malloc(n * sizeof(char *));
for (i = 0; i < n; i++) {
if (files) {
@@ -119,110 +124,8 @@ int dir(const char *dir, const char *type, int (*filter) (const char *file), cha
return num;
}
#ifdef UNITTEST
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "lite.h"
#define DIR_TYPE_IMAGE ".img"
#define DIR_TYPE_SYSLOG ""
#define DIR_TYPE_CONFIG ".cfg"
#define STARTUP_CONFIG "startup-config.cfg"
int simulate_files(int creat)
{
int i;
char *files[] =
{ "config0.cfg", "config1.cfg", "config2.cfg", "config3.cfg",
"rr109.img", "rx100.img", "rx107.img", "rm957.img", "messages"
};
for (i = 0; i < NELEMS(files); i++) {
if (creat)
touch(files[i]);
else
erase(files[i]);
}
if (creat)
symlink("config2.cfg", STARTUP_CONFIG);
else
erase(STARTUP_CONFIG);
return 0;
}
static int cfg_dir_filter(const char *file)
{
/* Skip the STARTUP_CONFIG file, it is a symbolic link to the
* current startup configuration. */
return ! !strcmp(file, STARTUP_CONFIG);
}
int main(int argc, char *argv[])
{
int i, num;
char *type = DIR_TYPE_CONFIG;
char **files;
int once = 1;
int is_startup_config(const char *entry) {
static char file[80];
if (once) {
int len = readlink(STARTUP_CONFIG, file, sizeof(file));
if (len == -1)
return 0;
file[len] = 0;
once = 0; /* Only once per call to dir() */
}
//printf ("Comparing link %s with entry %s\n", file, entry);
return !strcmp(file, entry);
}
simulate_files(1);
if (argc >= 2) {
if (!strcasecmp("CONFIG", argv[1])) {
type = DIR_TYPE_CONFIG;
system("ls -l *" DIR_TYPE_CONFIG);
}
if (!strcasecmp("IMAGE", argv[1])) {
type = DIR_TYPE_IMAGE;
system("ls -l *" DIR_TYPE_IMAGE);
}
if (!strcasecmp("SYSLOG", argv[1])) {
type = DIR_TYPE_SYSLOG;
system("ls -l *");
}
}
num = dir(NULL, type, cfg_dir_filter, &files, 0);
if (num) {
for (i = 0; i < num; i++) {
printf("%s", files[i]);
if (is_startup_config(files[i]))
printf(" --> startup-config");
printf("\n");
free(files[i]);
}
free(files);
}
simulate_files(0);
return 0;
}
#endif /* UNITTEST */
/**
* Local Variables:
* compile-command: "make V=1 -f dir.mk"
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
-4
View File
@@ -1,4 +0,0 @@
OBJS =
TARGET = dir.test clean
include rules.mk
-29
View File
@@ -44,37 +44,8 @@ int fexist(char *file)
return 1;
}
#ifdef UNITTEST
#include "lite.h"
int main(void)
{
int i = 0;
struct { char *file; int exist; } arr[] = {
{ "/etc/passwd", 1 },
{ "/etc/kalle", 0 },
{ "/sbin/init", 1 },
{ "/dev/null", 1 },
{ NULL, 0 },
};
FILE *src, *dst;
for (i = 0; i < NELEMS(arr); i++) {
if (fexist(arr[i].file) != arr[i].exist)
err(1, "Failed fexist(%s)", arr[i].file ?: "NULL");
else
printf("File %-11s %-14s => OK!\n", arr[i].file ?: "NULL",
arr[i].exist ? "does exist" : "does not exist");
}
return 0;
}
#endif /* UNITTEST */
/**
* Local Variables:
* compile-command: "make V=1 -f fexist.mk"
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
-4
View File
@@ -1,4 +0,0 @@
OBJS =
TARGET = fexist.test clean
include rules.mk
+1 -32
View File
@@ -21,7 +21,6 @@
* THE SOFTWARE.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -32,7 +31,7 @@
* Returns:
* %TRUE(1) if the file exists and is a directory, otherwise %FALSE(0).
*/
int fisdir(char *file)
int fisdir(const char *file)
{
struct stat sb;
@@ -42,38 +41,8 @@ int fisdir(char *file)
return 0;
}
#ifdef UNITTEST
#include "lite.h"
int main(void)
{
int i = 0;
struct { char *file; int exist; } arr[] = {
{ "/etc/passwd", 0 },
{ "/etc/", 1 },
{ "/sbin/init", 0 },
{ "/dev/null", 0 },
{ "/dev/", 1 },
{ NULL, 0 },
};
FILE *src, *dst;
for (i = 0; i < NELEMS(arr); i++) {
if (fisdir(arr[i].file) != arr[i].exist)
err(1, "Failed fisdir(%s)", arr[i].file ?: "NULL");
else
printf("fisdir() %-11s %-18s => OK!\n", arr[i].file ?: "NULL",
arr[i].exist ? "is a directory" : "is NOT a directory");
}
return 0;
}
#endif /* UNITTEST */
/**
* Local Variables:
* compile-command: "make V=1 -f fisdir.mk"
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
-4
View File
@@ -1,4 +0,0 @@
OBJS =
TARGET = fisdir.test clean
include rules.mk
-1
View File
@@ -50,7 +50,6 @@ mode_t fmode(char *file)
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
+202
View File
@@ -0,0 +1,202 @@
/* $NetBSD: fparseln.c,v 1.10 2009/10/21 01:07:45 snj Exp $ */
/*
* Copyright (c) 1997 Christos Zoulas. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: fparseln.c,v 1.10 2009/10/21 01:07:45 snj Exp $");
#endif /* LIBC_SCCS and not lint */
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "lite.h"
#define _DIAGASSERT(t)
static int isescaped(const char *, const char *, int);
/* isescaped():
* Return true if the character in *p that belongs to a string
* that starts in *sp, is escaped by the escape character esc.
*/
static int
isescaped(const char *sp, const char *p, int esc)
{
const char *cp;
size_t ne;
_DIAGASSERT(sp != NULL);
_DIAGASSERT(p != NULL);
/* No escape character */
if (esc == '\0')
return 0;
/* Count the number of escape characters that precede ours */
for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++)
continue;
/* Return true if odd number of escape characters */
return (ne & 1) != 0;
}
/* fparseln():
* Read a line from a file parsing continuations ending in \
* and eliminating trailing newlines, or comments starting with
* the comment char.
*/
char *
fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags)
{
static const char dstr[3] = { '\\', '\\', '#' };
ssize_t s;
size_t len, ptrlen;
char *buf;
char *ptr, *cp;
int cnt;
char esc, con, nl, com;
_DIAGASSERT(fp != NULL);
len = 0;
buf = NULL;
ptrlen = 0;
ptr = NULL;
cnt = 1;
if (str == NULL)
str = dstr;
esc = str[0];
con = str[1];
com = str[2];
/*
* XXX: it would be cool to be able to specify the newline character,
* getdelim(3) does let us, but supporting it would diverge from BSDs.
*/
nl = '\n';
flockfile(fp);
while (cnt) {
cnt = 0;
if (lineno)
(*lineno)++;
s = getline(&ptr, &ptrlen, fp);
if (s < 0)
break;
if (s && com) { /* Check and eliminate comments */
for (cp = ptr; cp < ptr + s; cp++)
if (*cp == com && !isescaped(ptr, cp, esc)) {
s = cp - ptr;
cnt = s == 0 && buf == NULL;
break;
}
}
if (s && nl) { /* Check and eliminate newlines */
cp = &ptr[s - 1];
if (*cp == nl)
s--; /* forget newline */
}
if (s && con) { /* Check and eliminate continuations */
cp = &ptr[s - 1];
if (*cp == con && !isescaped(ptr, cp, esc)) {
s--; /* forget continuation char */
cnt = 1;
}
}
if (s == 0) {
/*
* nothing to add, skip realloc except in case
* we need a minimal buf to return an empty line
*/
if (cnt || buf != NULL)
continue;
}
if ((cp = realloc(buf, len + s + 1)) == NULL) {
funlockfile(fp);
free(buf);
free(ptr);
return NULL;
}
buf = cp;
(void) memcpy(buf + len, ptr, s);
len += s;
buf[len] = '\0';
}
funlockfile(fp);
free(ptr);
if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL &&
strchr(buf, esc) != NULL) {
ptr = cp = buf;
while (cp[0] != '\0') {
int skipesc;
while (cp[0] != '\0' && cp[0] != esc)
*ptr++ = *cp++;
if (cp[0] == '\0' || cp[1] == '\0')
break;
skipesc = 0;
if (cp[1] == com)
skipesc += (flags & FPARSELN_UNESCCOMM);
if (cp[1] == con)
skipesc += (flags & FPARSELN_UNESCCONT);
if (cp[1] == esc)
skipesc += (flags & FPARSELN_UNESCESC);
if (cp[1] != com && cp[1] != con && cp[1] != esc)
skipesc = (flags & FPARSELN_UNESCREST);
if (skipesc)
cp++;
else
*ptr++ = *cp++;
*ptr++ = *cp++;
}
*ptr = '\0';
len = strlen(buf);
}
if (size)
*size = len;
return buf;
}
+4 -38
View File
@@ -41,10 +41,11 @@
* The number of bytes copied. If an error is detected -1 is returned
* and @errno will be set accordingly.
*/
size_t fsendfile(FILE *src, FILE *dst, size_t len)
ssize_t fsendfile(FILE *src, FILE *dst, size_t len)
{
char *buf;
size_t blk = BUFSIZ, num = 0, tot = 0;
size_t tot = 0;
ssize_t blk = BUFSIZ, num = 0;
if (!src) {
errno = EINVAL;
@@ -73,46 +74,11 @@ size_t fsendfile(FILE *src, FILE *dst, size_t len)
free(buf);
return (num == (size_t)-1) ? (size_t)-1 : tot;
return (num == -1) ? -1 : (ssize_t)tot;
}
#ifdef UNITTEST
#include <err.h>
#include <unistd.h>
int main(void)
{
int i = 0;
char *files[] = {
"/etc/passwd", "/tmp/tok",
"/etc/passwd", "/tmp/passwd",
"/etc/passwd", "/tmp/passwd",
NULL
};
FILE *src, *dst;
while (files[i]) {
src = fopen(files[i], "r");
dst = fopen(files[i + 1], "w");
printf("fsendfile(%s, %s, 512)\t", files[i], files[i + 1]);
if (-1 == fsendfile(src, dst, 512))
err(1, "Failed fsendfile(%s, %s)", files[i], files[i + 1]);
if (!access(files[i + 1], F_OK))
printf("OK => %s\n", files[i + 1]);
remove(files[i + 1]);
i += 2;
}
return 0;
}
#endif /* UNITTEST */
/**
* Local Variables:
* compile-command: "make V=1 -f fsendfile.mk"
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
-4
View File
@@ -1,4 +0,0 @@
OBJS =
TARGET = fsendfile.test clean
include rules.mk
-1
View File
@@ -85,7 +85,6 @@ int ifconfig(char *ifname, char *addr, char *mask, int up)
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
+195
View File
@@ -0,0 +1,195 @@
/* Parse UNIX /etc configuration files like /etc/protocols and /etc/services
*
* Copyright (c) 2015-2016 Joachim Nilsson <troglobit@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <errno.h>
#include <stdio.h> /* FILE */
#include <stdlib.h> /* atoi() */
#include <string.h> /* strlen(), strncmp(), strtok_r() */
#include <sys/param.h> /* MAX() */
typedef struct lfile {
FILE *fp;
char buf[256];
char *sep, *save;
} lfile_t;
/**
* lfopen - Open file and return parsing context
* @file: File to parse
* @sep: Separator(s) to use in lftok()
*
* Returns:
* Pointer to a &lftile_t parser context, or %NULL on error.
*/
lfile_t *lfopen(char *file, char *sep)
{
lfile_t *lf;
if (!file || !sep) {
errno = EINVAL;
return NULL;
}
/* Use calloc for clearing buf on behalf of lftok() */
lf = calloc(sizeof(*lf), sizeof(char));
if (lf) {
lf->fp = fopen(file, "r");
lf->sep = sep;
lf->save = lf->buf;
if (!lf->fp) {
free(lf);
return NULL;
}
}
return lf;
}
/**
* lfclose - Close a parser context
* @lf: Pointer to &lfile_t context from lfopen()
*/
void lfclose(lfile_t *lf)
{
if (!lf)
return;
if (lf->fp)
fclose(lf->fp);
free(lf);
}
/**
* lftok - Get next token in file
* @lf: Pointer to &lfile_t context from lfopen()
*
* Returns:
* Next token, read from file previously opened with lfopen(),
* or %NULL if EOF.
*/
char *lftok(lfile_t *lf)
{
char *token;
if (!lf || !lf->fp || !lf->sep) {
errno = EINVAL;
return NULL;
}
token = strtok_r(NULL, lf->sep, &lf->save);
if (!token) {
while (fgets(lf->buf, sizeof(lf->buf), lf->fp)) {
if (lf->buf[0] == '#')
continue;
token = strtok_r(lf->buf, lf->sep, &lf->save);
if (!token)
continue;
return token;
}
errno = ENOENT;
return NULL;
}
return token;
}
/**
* lfgetkey - Find key in file
* @lf: Pointer to &lfile_t context from lfopen()
* @key: Key to look for
*
* Locate @key from the current position in the file parser context
* returned from lfopen(). Please note, the search for @key does not
* start from the beginning of the file, it searches from the current
* position. To restart search from the beginning use rewind() on the
* lf->fp.
*
* Returns:
* The value to @key, or %NULL if not found.
*/
char *lfgetkey(lfile_t *lf, char *key)
{
char *token;
while ((token = lftok(lf))) {
if (token[0] == '#')
continue;
if (!strncmp(token, key, MAX(strlen(token), strlen(key))))
return lftok(lf);
}
return NULL;
}
/**
* lfgetint - Same as lfgetkey() but returns an integer
* @lf: Pointer to &lfile_t context from lfopen()
* @key: Key to look for
*
* This function is the same as lfgetkey() but returns the positive
* integer value for the matching @key, if found.
*
* Returns:
* The positive integer value for @key, or -1 if not found.
*/
int lfgetint(lfile_t *lf, char *key)
{
char *token = lfgetkey(lf, key);
if (token)
return atoi(token);
return -1;
}
/**
* fgetint - Find the integer value for key in a file
* @file: File to search for @key
* @sep: Separator for tokens in @file
* @key: Key to look for in @file
*
* This is a convenience wrapper for lfopen(), lfgetint(), and
* lfclose().
*
* Returns:
* The positive integer value for @key, or -1 if not found.
*/
int fgetint(char *file, char *sep, char *key)
{
int val = -1;
lfile_t *lf;
lf = lfopen(file, sep);
if (lf) {
val = lfgetint(lf, key);
lfclose(lf);
}
return val;
}
/**
* Local Variables:
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
*/
+12
View File
@@ -0,0 +1,12 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: @PACKAGE@
Description: Frog DNA, basically
Version: @VERSION@
Requires:
Libs: -L${libdir} -lite
Cflags: -I${includedir}
+38 -64
View File
@@ -1,7 +1,7 @@
/* Collection of utility funcs and C library extensions for finit & its plugins
/* Collection of frog DNA
*
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
* Copyright (c) 2008-2015 Joachim Nilsson <troglobit@gmail.com>
* Copyright (c) 2008-2016 Joachim Nilsson <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,32 +22,51 @@
* THE SOFTWARE.
*/
#ifndef FINIT_LITE_H_
#define FINIT_LITE_H_
#ifndef LITE_H_
#define LITE_H_
#include <err.h>
#include <stdio.h>
#include <stdint.h> /* uint8_t, uint16_t, uint32_t, INT32_MAX, etc. */
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/param.h> /* MAX(), isset(), setbit(), TRUE, FALSE, et consortes. :-) */
#include <unistd.h>
#include "strlite.h"
/*
* fparseln() specific operation flags.
*/
#define FPARSELN_UNESCESC 0x01
#define FPARSELN_UNESCCONT 0x02
#define FPARSELN_UNESCCOMM 0x04
#define FPARSELN_UNESCREST 0x08
#define FPARSELN_UNESCALL 0x0f
typedef struct lfile lfile_t;
char *chomp (char *str);
char *fparseln (FILE *, size_t *, size_t *, const char[3], int);
int fexist (char *file);
int fisdir (char *file);
int fisdir (const char *file);
mode_t fmode (char *file);
FILE *tempfile (void);
ssize_t copyfile (char *src, char *dst, int len, int sym);
int movefile (char *src, char *dst);
int fcopyfile (FILE *src, FILE *dst);
size_t fsendfile (FILE *src, FILE *dst, size_t len);
ssize_t fsendfile (FILE *src, FILE *dst, size_t len);
int ifconfig (char *ifname, char *addr, char *mask, int up);
lfile_t*lfopen (char *file, char *sep);
void lfclose (lfile_t *lf);
char *lftok (lfile_t *lf);
char *lfgetkey (lfile_t *lf, char *key);
int lfgetint (lfile_t *lf, char *key);
int fgetint (char *file, char *sep, char *key);
int mkpath (char *dir, mode_t mode);
int makepath (char *dir);
@@ -59,17 +78,12 @@ int pidfile_signal(const char *pidfile, int signal);
pid_t pidfile_read (const char *pidfile);
pid_t pidfile_poll (const char *pidfile);
#ifndef strlcpy
size_t strlcpy (char *dst, const char *src, size_t siz);
#endif
#ifndef strlcat
size_t strlcat (char *dst, const char *src, size_t siz);
#endif
#ifndef strtonum
long long strtonum (const char *numstr, long long minval, long long maxval, const char **errstrp);
#endif
void *reallocarray(void *optr, size_t nmemb, size_t size);
int tree(char *path, int show_perms);
int tree(char *path, int show_perms);
void progress (int percent, int max_width);
void progress_simple(int percent);
#ifndef touch
# define touch(x) do { if (mknod((x), S_IFREG|0644, 0) && errno != EEXIST) warn("Failed creating %s", x); } while (0)
@@ -121,55 +135,16 @@ int tree(char *path, int show_perms);
#define UNUSED(x) UNUSED_ ## x __attribute__ ((unused))
#endif
/* Does directory end with a slash? */
static inline int fisslashdir(char *dir)
{
if (!dir) return 0;
if (strlen (dir) > 0) return dir[strlen (dir) - 1] == '/';
return 0;
}
if (!dir)
return 0;
/* Convert string to natural number (0-2147483647), returns -1 on error. */
static inline int atonum(const char *str)
{
int val = -1;
const char *errstr;
if (strlen(dir) > 0)
return dir[strlen(dir) - 1] == '/';
if (str) {
val = strtonum(str, 0, INT32_MAX, &errstr);
if (errstr)
return -1;
}
return val;
}
/* Validate string, non NULL and not zero length */
static inline int string_valid(const char *s)
{
return s && strlen(s);
}
/* Relaxed comparison, e.g., sys_string_match("small", "smaller") => TRUE */
static inline int string_match(const char *a, const char *b)
{
size_t min = MIN(strlen(a), strlen(b));
return !strncasecmp(a, b, min);
}
/* Strict comparison, e.g., sys_string_match("small", "smaller") => FALSE */
static inline int string_compare (const char *a, const char *b)
{
return strlen(a) == strlen(b) && !strcmp(a, b);
}
/* Strict comparison, like sys_string_compare(), but case insensitive,
* e.g., sys_string_match("small", "SmAlL") => TRUE
*/
static inline int string_case_compare (const char *a, const char *b)
{
return strlen (a) == strlen (b) && !strcasecmp (a, b);
return 0;
}
/* Compat */
@@ -177,11 +152,10 @@ static inline int string_case_compare (const char *a, const char *b)
#define pidfile_read_pid(file) pifile_read(file)
#define signal_pidfile(file,signo) pidfile_signal(file,signo)
#endif /* FINIT_LITE_H_ */
#endif /* LITE_H_ */
/**
* Local Variables:
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
+1
View File
@@ -0,0 +1 @@
*.m4
+13 -68
View File
@@ -1,6 +1,6 @@
/* mkpath() -- Create all components leading up to a given directory
*
* Copyright (c) 2013 Joachim Nilsson <troglobit@gmail.com>
* Copyright (c) 2013-2016 Joachim Nilsson <troglobit@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -17,20 +17,28 @@
#include <errno.h>
#include <libgen.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "lite.h"
/**
* mkpath - Like makepath() but takes a mode_t argument
* @dir: Directory to created, relative or absolute
* @mode: A &mode_t mode to create @dir with
*
* Returns:
* POSIX OK(0) on success, otherwise -1 with @errno set.
*/
int mkpath(char *dir, mode_t mode)
{
struct stat sb;
if (!dir) {
errno = EINVAL;
return 1;
}
if (strlen(dir) == 1 && dir[0] == '/')
if (!stat(dir, &sb))
return 0;
mkpath(dirname(strdupa(dir)), mode);
@@ -53,71 +61,8 @@ int makepath(char *dir)
return mkpath(dir, 0777);
}
/********************************* UNIT TESTS ************************************/
#ifdef UNITTEST
#include "lite.h"
int checkpath(char *dir)
{
char tmp[256];
struct stat sb;
snprintf(tmp, sizeof(tmp), "ls -ld %s", dir);
if (system(tmp))
perror("system");
if (!stat(dir, &sb) && S_ISDIR(sb.st_mode))
return 0;
errno = ENOTDIR;
return 1;
}
int test_makepath(char *dir)
{
int ret = makepath(dir);
if (!ret)
ret = checkpath(dir);
if (ret)
perror("Failed");
return ret;
}
int main(void)
{
int i, ret = 0;
char *list[] = {
"/tmp/tok/",
"/tmp/tok2",
"/tmp/ab",
"/tmp/b",
"/tmp/a/",
"/tmp/a/b",
"/tmp/a/c/",
NULL
};
for (i = 0; list[i]; i++)
rmdir(list[i]);
printf("Testing makepath() ...\n");
for (i = 0; list[i] && !ret; i++)
ret = test_makepath(list[i]);
printf("\nCleaning up ...\n");
for (i = 0; list[i]; i++)
rmdir(list[i]);
return ret;
}
#endif /* UNITTEST */
/**
* Local Variables:
* compile-command: "make V=1 -f makepath.mk"
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
-4
View File
@@ -1,4 +0,0 @@
OBJS =
TARGET = makepath.test clean
include rules.mk
+26 -4
View File
@@ -1,3 +1,4 @@
/* Updated by troglobit for libite/finit/uftpd projects 2016/03/19 */
/* $OpenBSD: pidfile.c,v 1.11 2015/06/03 02:24:36 millert Exp $ */
/* $NetBSD: pidfile.c,v 1.4 2001/02/19 22:43:42 cgd Exp $ */
@@ -30,6 +31,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/stat.h> /* utimensat() */
#include <sys/types.h>
#include <errno.h>
#include <paths.h>
@@ -37,30 +39,42 @@
#include <stdlib.h>
#include <unistd.h>
static char *pidfile_path;
#ifndef pidfile
static char *pidfile_path = NULL;
static pid_t pidfile_pid;
static void pidfile_cleanup(void);
const char *__pidfile_path = _PATH_VARRUN; /* Note: includes trailing slash '/' */
const char *__pidfile_name = NULL;
extern char *__progname;
int
pidfile(const char *basename)
{
int save_errno;
int atexit_already;
pid_t pid;
FILE *f;
if (basename == NULL)
basename = __progname;
pid = getpid();
atexit_already = 0;
if (pidfile_path != NULL) {
if (pid == pidfile_pid) {
utimensat(0, pidfile_path, NULL, 0);
return (0);
}
free(pidfile_path);
pidfile_path = NULL;
__pidfile_name = NULL;
atexit_already = 1;
}
/* _PATH_VARRUN includes trailing / */
if (asprintf(&pidfile_path, "%s%s.pid", _PATH_VARRUN, basename) == -1)
if (asprintf(&pidfile_path, "%s%s.pid", __pidfile_path, basename) == -1)
return (-1);
if ((f = fopen(pidfile_path, "w")) == NULL) {
@@ -71,7 +85,6 @@ pidfile(const char *basename)
return (-1);
}
pid = getpid();
if (fprintf(f, "%ld\n", (long)pid) <= 0 || fflush(f) != 0) {
save_errno = errno;
(void) fclose(f);
@@ -83,6 +96,13 @@ pidfile(const char *basename)
}
(void) fclose(f);
/*
* LITE extension, no need to set up another atexit() handler
* if user only called us to update the mtime of the PID file
*/
if (atexit_already)
return (0);
pidfile_pid = pid;
if (atexit(pidfile_cleanup) < 0) {
save_errno = errno;
@@ -93,6 +113,7 @@ pidfile(const char *basename)
errno = save_errno;
return (-1);
}
__pidfile_name = pidfile_path;
return (0);
}
@@ -104,3 +125,4 @@ pidfile_cleanup(void)
if (pidfile_path != NULL && pidfile_pid == getpid())
(void) unlink(pidfile_path);
}
#endif
-47
View File
@@ -117,56 +117,9 @@ int pidfile_signal(const char *pidfile, int signal)
return 0;
}
/********************************* UNIT TESTS ************************************/
#ifdef UNITTEST
#include <paths.h>
#include "lite.h"
extern char *__progname;
static char PIDFILE[42];
static void sigterm_handler(int signo)
{
printf("Exiting ...\n");
}
static void sigalrm_handler(int signo)
{
printf("Testing pidfile() ...\n");
pidfile(NULL);
if (!fexist(PIDFILE))
err(1, "pidfile() failed creating %s", PIDFILE);
}
int main(void)
{
snprintf(PIDFILE, sizeof(PIDFILE), "%s%s.pid", _PATH_VARRUN, __progname);
signal(SIGTERM, sigterm_handler);
signal(SIGALRM, sigalrm_handler);
alarm(1);
printf("Testing pidfile_poll() ...\n");
if (!pidfile_poll(PIDFILE))
printf("Timed out!\n");
else
printf("We got signal!\n");
printf("Reading pid file, should be %d ...\n", getpid());
printf("=> %d\n", pidfile_read(PIDFILE));
printf("Signalling ourselves ...\n");
return pidfile_signal(PIDFILE, SIGTERM);
}
#endif /* UTEST_PIDFN */
/**
* Local Variables:
* compile-command: "make V=1 -f pidfilefn.mk"
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
-5
View File
@@ -1,5 +0,0 @@
OBJS = pidfile.o chomp.o fexist.o
ASROOT = 1
TARGET = clean $(OBJS) pidfilefn.test
include rules.mk
-53
View File
@@ -114,61 +114,8 @@ void progress_simple(int percent)
}
}
#ifdef UNITTEST
#include <stdlib.h> /* atexit() */
#include <unistd.h> /* usleep() */
#define MAX_WIDTH 80
#define msleep(msec) usleep(msec * 1000)
static void bye(void)
{
showcursor();
}
static void testit(int fn, int percent)
{
if (fn)
progress(percent, MAX_WIDTH);
else
progress_simple(percent);
}
static void test(int fn)
{
int i, percent, block = 0, num = 85;
while (block < num) {
percent = block * 100 / num;
for (i = 0; i < 10; i++) {
testit(fn, percent);
msleep(5);
}
block++;
msleep(10);
}
testit(fn, 100);
}
int main(void)
{
atexit(bye);
hidecursor();
printf("\nAdvanced:\n");
test(1);
printf("\nSimple:\n");
test(0);
printf("\n");
return 0;
}
#endif /* UNITTEST */
/**
* Local Variables:
* compile-command: "make V=1 -f progress.mk"
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
-4
View File
@@ -1,4 +0,0 @@
OBJS =
TARGET = progress.test clean
include rules.mk
+31 -146
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: queue.h,v 1.38 2013/07/03 15:05:21 fgsch Exp $ */
/* $OpenBSD: queue.h,v 1.43 2015/12/28 19:38:40 millert Exp $ */
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
/*
@@ -36,8 +36,8 @@
#define _SYS_QUEUE_H_
/*
* This file defines five types of data structures: singly-linked lists,
* lists, simple queues, tail queues, and circular queues.
* This file defines five types of data structures: singly-linked lists,
* lists, simple queues, tail queues and XOR simple queues.
*
*
* A singly-linked list is headed by a single forward pointer. The elements
@@ -57,7 +57,7 @@
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A simple queue is headed by a pair of pointers, one the head of the
* A simple queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are singly
* linked to save space, so elements can only be removed from the
* head of the list. New elements can be added to the list before or after
@@ -71,13 +71,10 @@
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* A circle queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the list.
* A circle queue may be traversed in either direction, but has a more
* complex end of list detection.
* An XOR simple queue is used in the same way as a regular simple queue.
* The difference is that the head structure also includes a "cookie" that
* is XOR'd with the queue pointer (first, last or next) to generate the
* real pointer value.
*
* For details on the use of these macros, see the queue(3) manual page.
*/
@@ -95,15 +92,15 @@
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List access methods.
*/
@@ -157,8 +154,8 @@ struct { \
curelm = curelm->field.sle_next; \
curelm->field.sle_next = \
curelm->field.sle_next->field.sle_next; \
_Q_INVALIDATE((elm)->field.sle_next); \
} \
_Q_INVALIDATE((elm)->field.sle_next); \
} while (0)
/*
@@ -179,7 +176,7 @@ struct { \
}
/*
* List access methods
* List access methods.
*/
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_END(head) NULL
@@ -316,6 +313,14 @@ struct { \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (0)
#define SIMPLEQ_CONCAT(head1, head2) do { \
if (!SIMPLEQ_EMPTY((head2))) { \
*(head1)->sqh_last = (head2)->sqh_first; \
(head1)->sqh_last = (head2)->sqh_last; \
SIMPLEQ_INIT((head2)); \
} \
} while (0)
/*
* XOR Simple queue definitions.
*/
@@ -395,7 +400,7 @@ struct { \
XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
} while (0)
/*
* Tail queue definitions.
*/
@@ -414,8 +419,8 @@ struct { \
struct type **tqe_prev; /* address of previous next element */ \
}
/*
* tail queue access methods
/*
* Tail queue access methods.
*/
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_END(head) NULL
@@ -516,133 +521,13 @@ struct { \
_Q_INVALIDATE((elm)->field.tqe_next); \
} while (0)
/*
* Circular queue definitions.
*/
#define CIRCLEQ_HEAD(name, type) \
struct name { \
struct type *cqh_first; /* first element */ \
struct type *cqh_last; /* last element */ \
}
#define CIRCLEQ_HEAD_INITIALIZER(head) \
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
#define CIRCLEQ_ENTRY(type) \
struct { \
struct type *cqe_next; /* next element */ \
struct type *cqe_prev; /* previous element */ \
}
/*
* Circular queue access methods
*/
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
#define CIRCLEQ_END(head) ((void *)(head))
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
#define CIRCLEQ_EMPTY(head) \
(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
#define CIRCLEQ_FOREACH(var, head, field) \
for((var) = CIRCLEQ_FIRST(head); \
(var) != CIRCLEQ_END(head); \
(var) = CIRCLEQ_NEXT(var, field))
#define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = CIRCLEQ_FIRST(head); \
(var) != CIRCLEQ_END(head) && \
((tvar) = CIRCLEQ_NEXT(var, field), 1); \
(var) = (tvar))
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
for((var) = CIRCLEQ_LAST(head); \
(var) != CIRCLEQ_END(head); \
(var) = CIRCLEQ_PREV(var, field))
#define CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = CIRCLEQ_LAST(head, headname); \
(var) != CIRCLEQ_END(head) && \
((tvar) = CIRCLEQ_PREV(var, headname, field), 1); \
(var) = (tvar))
/*
* Circular queue functions.
*/
#define CIRCLEQ_INIT(head) do { \
(head)->cqh_first = CIRCLEQ_END(head); \
(head)->cqh_last = CIRCLEQ_END(head); \
} while (0)
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
(elm)->field.cqe_prev = (listelm); \
if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm); \
else \
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
(listelm)->field.cqe_next = (elm); \
} while (0)
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm); \
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm); \
else \
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
(listelm)->field.cqe_prev = (elm); \
} while (0)
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
(elm)->field.cqe_next = (head)->cqh_first; \
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
if ((head)->cqh_last == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm); \
else \
(head)->cqh_first->field.cqe_prev = (elm); \
(head)->cqh_first = (elm); \
} while (0)
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.cqe_next = CIRCLEQ_END(head); \
(elm)->field.cqe_prev = (head)->cqh_last; \
if ((head)->cqh_first == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm); \
else \
(head)->cqh_last->field.cqe_next = (elm); \
(head)->cqh_last = (elm); \
} while (0)
#define CIRCLEQ_REMOVE(head, elm, field) do { \
if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm)->field.cqe_prev; \
else \
(elm)->field.cqe_next->field.cqe_prev = \
(elm)->field.cqe_prev; \
if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm)->field.cqe_next; \
else \
(elm)->field.cqe_prev->field.cqe_next = \
(elm)->field.cqe_next; \
_Q_INVALIDATE((elm)->field.cqe_prev); \
_Q_INVALIDATE((elm)->field.cqe_next); \
} while (0)
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
CIRCLEQ_END(head)) \
(head)->cqh_last = (elm2); \
else \
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
CIRCLEQ_END(head)) \
(head)->cqh_first = (elm2); \
else \
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
_Q_INVALIDATE((elm)->field.cqe_prev); \
_Q_INVALIDATE((elm)->field.cqe_next); \
#define TAILQ_CONCAT(head1, head2, field) do { \
if (!TAILQ_EMPTY(head2)) { \
*(head1)->tqh_last = (head2)->tqh_first; \
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \
} \
} while (0)
#endif /* !_SYS_QUEUE_H_ */
+38
View File
@@ -0,0 +1,38 @@
/* $OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $ */
/*
* Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
/*
* This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
* if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
*/
#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
void *
reallocarray(void *optr, size_t nmemb, size_t size)
{
if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
nmemb > 0 && SIZE_MAX / nmemb < size) {
errno = ENOMEM;
return NULL;
}
return realloc(optr, size * nmemb);
}
-112
View File
@@ -193,120 +193,8 @@ static int prune(char *dst, char **new_files, int new_num)
return result;
}
#ifdef UNITTEST
#define BASE "/tmp/.unittest/"
#define SRC BASE "src/"
#define DST BASE "dst/"
static int verbose = 0;
static char *files[] = {
SRC "sub1/1.tst",
SRC "sub1/2.tst",
SRC "sub1/3.tst",
SRC "sub2/4.tst",
SRC "sub2/5.tst",
SRC "sub2/6.tst",
SRC "sub3/7.tst",
SRC "sub3/8.tst",
SRC "sub3/9.tst",
NULL
};
void cleanup_test(void)
{
system("rm -rf " BASE);
}
void setup_test(void)
{
int i;
char cmd[256];
mode_t dir_modes[] = { 755, 700 };
mode_t file_modes[] = { 644, 600 };
cleanup_test();
mkdir(BASE, 0755);
mkdir(SRC, 0755);
mkdir(DST, 0755);
for (i = 0; files[i]; i++) {
snprintf(cmd, sizeof(cmd), "mkdir -m %d -p `dirname %s`",
dir_modes[i % 2], files[i]);
system(cmd);
snprintf(cmd, sizeof(cmd), "touch %s; chmod %d %s", files[i],
file_modes[i % 2], files[i]);
system(cmd);
}
}
static void check_tree(char *heading, char *dir)
{
if (verbose) {
char cmd[128];
if (heading)
puts(heading);
tree(dir, 1);
}
}
int run_test(void)
{
int result = 0;
#if 0
setup_test();
check_tree("Before:", BASE);
result += rsync(SRC, DST, 0, NULL);
check_tree("After:", BASE);
cleanup_test();
#endif
setup_test();
result += rsync(BASE "src", DST, 0, NULL);
check_tree("Only partial rsync of src <-- No slash!", BASE);
#if 0
cleanup_test();
setup_test();
result += rsync(BASE "src/sub1", BASE "dst", 0, NULL);
check_tree("Only partial rsync of src/sub1 <-- No slashes!!", BASE);
cleanup_test();
setup_test();
result += rsync(BASE "src/sub1/", DST, 0, NULL);
check_tree("Only partial rsync of src/sub1/", BASE);
cleanup_test();
setup_test();
result += rsync(BASE "src/sub1", DST, 0, NULL);
check_tree("Only partial rsync of src/sub1 <-- No slash!", BASE);
result += rsync("/etc", "/var/tmp", 0, NULL);
check_tree("Real life test:", "/var/tmp");
#endif
return result;
}
int main(int argc, char *argv[])
{
if (argc > 1)
verbose = !strncmp("-v", argv[1], 2);
atexit(cleanup_test);
return run_test();
}
#endif /* UNITTEST */
/**
* Local Variables:
* compile-command: "make V=1 -f rsync.mk"
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
-4
View File
@@ -1,4 +0,0 @@
OBJS = dir.o copyfile.o fexist.o fisdir.o fmode.o tree.o
TARGET = clean $(OBJS) rsync.test
include rules.mk
-68
View File
@@ -1,68 +0,0 @@
.PHONY: all clean distclean
# Figure out root of library, unless used as submodule
ROOTDIR ?= $(shell pwd)
CC ?= $(CROSS)gcc
AR ?= $(CROSS)ar
STRIP ?= $(CROSS)strip
INSTALL := install --backup=off
STRIPINST := $(INSTALL) -s --strip-program=$(CROSS)strip -m 0755
CPPFLAGS += -D_GNU_SOURCE
ARFLAGS = crus
# Default to silent build, use V=1 to get verbose mode.
ifeq ($V,1)
Q =
PRINT = @true
REDIRECT =
MAKEFLAGS =
VERBOSE = -v
else
Q = @
PRINT = @printf
REDIRECT = >/dev/null
MAKEFLAGS = --no-print-directory --silent
VERBOSE =
endif
# Some tests may need to be run as root, e.g. pidfile()
ifeq ($(ASROOT), 1)
SUDO = sudo -n
else
SUDO =
endif
# Default install paths
prefix ?= /usr/local
libdir ?= $(prefix)/lib
datadir ?= $(prefix)/share/doc/$(LIBNAME)
incdir ?= $(prefix)/include
# Pretty printing and GCC -M for auto dep files
%.o: %.c
$(PRINT) " CC $(subst $(ROOTDIR)/,,$(shell pwd)/)$@\n"
$(Q)$(CC) $(CFLAGS) $(CPPFLAGS) -c -MMD -MP -o $@ $<
%: %.o
$(PRINT) " LINK $(subst $(ROOTDIR)/,,$(shell pwd)/)$@\n"
$(Q)$(CC) $(CFLAGS) $(LDFLAGS) -Wl,-Map,$@.map -o $@ $^ $(LDLIBS$(LDLIBS-$(@)))
.PHONY: %.test
%.test: %.c
$(PRINT) " TEST $(subst $(ROOTDIR)/,,$(shell pwd)/)$(@:.test=)\n"
$(Q)$(CC) $(CFLAGS) $(CPPFLAGS) -g -o $@ -DUNITTEST $< $(OBJS)
$(Q)$(RM) $(OBJS)
$(Q)$(SUDO) ./$@ $(VERBOSE) $(REDIRECT)
# Default build rules for both main and unit test makefiles
all:: $(TARGET)
clean::
-$(Q)$(RM) $(OBJS) $(DEPS) $(TARGET) $(SOLIB) $(STATICLIB)
distclean::
-$(Q)$(RM) $(JUNK) unittest *.o *.a *.so* *.unittest *.test
+52
View File
@@ -0,0 +1,52 @@
/* ==========================================================================
* strdupa.h - Re-implementation of glibc strdupa.
* --------------------------------------------------------------------------
* Copyright (c) 2009 William Ahern
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to permit
* persons to whom the Software is furnished to do so, subject to the
* following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
* ==========================================================================
*/
#ifndef LITE_STRDUPA_H
#define LITE_STRDUPA_H
#if !defined(HAVE_STRDUPA)
#if defined(strdupa)
#define HAVE_STRDUPA 1
#endif
#endif
#if !HAVE_STRDUPA
#if defined(__GNUC__)
#include <stddef.h> /* size_t */
#include <string.h> /* memcpy(3) strlen(3) */
#define strdupa(src) (__extension__ ({ \
size_t len_ = strlen(src); \
char *dst_ = __builtin_alloca(len_ + 1); \
dst_[len_] = '\0'; \
(char *)memcpy(dst_, src, len_); \
}))
#else /* If not GCC, e.g. Clang */
#error strdupa() may use an unsupported GNU C API, please forward any fix to maintainer, cheers!
#endif /* __GNUC__ */
#endif /* !HAVE_STRDUPA */
#endif /* LITE_STRDUPA_H */
+24 -33
View File
@@ -1,7 +1,7 @@
/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
/* $OpenBSD: strlcat.c,v 1.15 2015/03/02 21:41:08 millert Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
* Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -21,46 +21,37 @@
#ifndef strlcat
/*
* Appends src to string dst of size siz (unlike strncat, siz is the
* full size of dst, not space left). At most siz-1 characters
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
* If retval >= siz, truncation occurred.
* Appends src to string dst of size dsize (unlike strncat, dsize is the
* full size of dst, not space left). At most dsize-1 characters
* will be copied. Always NUL terminates (unless dsize <= strlen(dst)).
* Returns strlen(src) + MIN(dsize, strlen(initial dst)).
* If retval >= dsize, truncation occurred.
*/
size_t
strlcat(char *dst, const char *src, size_t siz)
strlcat(char *dst, const char *src, size_t dsize)
{
char *d = dst;
const char *s = src;
size_t n = siz;
const char *odst = dst;
const char *osrc = src;
size_t n = dsize;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = siz - dlen;
/* Find the end of dst and adjust bytes left but don't go past end. */
while (n-- != 0 && *dst != '\0')
dst++;
dlen = dst - odst;
n = dsize - dlen;
if (n == 0)
return(dlen + strlen(s));
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
if (n-- == 0)
return(dlen + strlen(src));
while (*src != '\0') {
if (n != 0) {
*dst++ = *src;
n--;
}
s++;
src++;
}
*d = '\0';
*dst = '\0';
return(dlen + (s - src)); /* count does not include NUL */
return(dlen + (src - osrc)); /* count does not include NUL */
}
#endif
/**
* Local Variables:
* version-control: t
* c-file-style: "bsd"
* End:
*/
+18 -27
View File
@@ -1,7 +1,7 @@
/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
/* $OpenBSD: strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
* Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -21,41 +21,32 @@
#ifndef strlcpy
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
* Copy string src to buffer dst of size dsize. At most dsize-1
* chars will be copied. Always NUL terminates (unless dsize == 0).
* Returns strlen(src); if retval >= dsize, truncation occurred.
*/
size_t
strlcpy(char *dst, const char *src, size_t siz)
strlcpy(char *dst, const char *src, size_t dsize)
{
char *d = dst;
const char *s = src;
size_t n = siz;
const char *osrc = src;
size_t nleft = dsize;
/* Copy as many bytes as will fit */
if (n != 0) {
while (--n != 0) {
if ((*d++ = *s++) == '\0')
/* Copy as many bytes as will fit. */
if (nleft != 0) {
while (--nleft != 0) {
if ((*dst++ = *src++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
/* Not enough room in dst, add NUL and traverse rest of src. */
if (nleft == 0) {
if (dsize != 0)
*dst = '\0'; /* NUL-terminate dst */
while (*src++)
;
}
return(s - src - 1); /* count does not include NUL */
return(src - osrc - 1); /* count does not include NUL */
}
#endif
/**
* Local Variables:
* version-control: t
* c-file-style: "bsd"
* End:
*/
+100
View File
@@ -0,0 +1,100 @@
/* Collection of frog DNA
*
* Copyright (c) 2008-2016 Joachim Nilsson <troglobit@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef LITE_STRING_H_
#define LITE_STRING_H_
#include <string.h>
#include "strdupa.h"
#include "strndupa.h"
#include "strnlen.h"
#ifndef strlcpy
size_t strlcpy (char *dst, const char *src, size_t siz);
#endif
#ifndef strlcat
size_t strlcat (char *dst, const char *src, size_t siz);
#endif
#ifndef strtonum
long long strtonum (const char *numstr, long long minval, long long maxval, const char **errstrp);
#endif
/* Convert string to natural number (0-2147483647), returns -1 on error. */
static inline int atonum(const char *str)
{
int val = -1;
const char *errstr;
if (str) {
val = strtonum(str, 0, INT32_MAX, &errstr);
if (errstr)
return -1;
}
return val;
}
/* Validate string, non NULL and not zero length */
static inline int string_valid(const char *s)
{
return s && strlen(s);
}
/* Relaxed comparison, e.g., sys_string_match("small", "smaller") => TRUE */
static inline int string_match(const char *a, const char *b)
{
size_t min = MIN(strlen(a), strlen(b));
return !strncasecmp(a, b, min);
}
/* Strict comparison, e.g., sys_string_match("small", "smaller") => FALSE */
static inline int string_compare(const char *a, const char *b)
{
return strlen(a) == strlen(b) && !strcmp(a, b);
}
/* Strict comparison, like sys_string_compare(), but case insensitive,
* e.g., sys_string_match("small", "SmAlL") => TRUE
*/
static inline int string_case_compare(const char *a, const char *b)
{
return strlen (a) == strlen (b) && !strcasecmp (a, b);
}
#define min(a,b) \
({ \
__typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; \
})
#define max(a,b) \
({ \
__typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; \
})
#endif /* LITE_STRING_H_ */
+53
View File
@@ -0,0 +1,53 @@
/* ==========================================================================
* strndupa.h - Re-implementation of glibc strndupa.
* --------------------------------------------------------------------------
* Copyright (c) 2009 William Ahern
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to permit
* persons to whom the Software is furnished to do so, subject to the
* following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
* ==========================================================================
*/
#ifndef LITE_STRNDUPA_H_
#define LITE_STRNDUPA_H_
#if !defined(HAVE_STRNDUPA)
#if defined(strndupa)
#define HAVE_STRNDUPA 1
#endif
#endif
#if !HAVE_STRNDUPA
#if defined(__GNUC__)
#include <stddef.h> /* size_t */
#include <string.h> /* memcpy(3) */
#include "strnlen.h"
#define strndupa(src, lim) (__extension__ ({ \
size_t len_ = strnlen(src, lim); \
char *dst_ = __builtin_alloca(len_ + 1); \
dst_[len_] = '\0'; \
(char *)memcpy(dst_, src, len_); \
}))
#else /* If not GCC, e.g. Clang */
+#error strndupa() may use an unsupported GNU C API, please forward any fix to maintainer, cheers!
#endif /* __GNUC__ */
#endif /* !HAVE_STRNDUPA */
#endif /* GNU_STRING_STRNDUPA_H */
+43
View File
@@ -0,0 +1,43 @@
/* strnlen.h - Re-implementation of GLIBC strnlen()
*
* Copyright (c) 2016 Joachim Nilsson <troglobit@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef LITE_STRNLEN_H_
#define LITE_STRNLEN_H_
#if !defined(HAVE_STRNLEN)
#if defined(strnlen)
#define HAVE_STRNLEN 1
#endif
#endif
#if !HAVE_STRNLEN
#include <stddef.h> /* size_t */
#define strnlen(str, lim) xstrnlen(str, lim)
static inline size_t xstrnlen(const char *str, size_t lim)
{
size_t i = 0;
while (str[i] && i < lim)
i++;
return i;
}
#endif
#endif /* LITE_STRNLEN_H_ */
+7 -7
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */
/* $OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $ */
/*
* Copyright (c) 2004 Ted Unangst and Todd Miller
@@ -22,17 +22,17 @@
#include <stdlib.h>
#ifndef strtonum
#define INVALID 1
#define TOOSMALL 2
#define TOOLARGE 3
#define INVALID 1
#define TOOSMALL 2
#define TOOLARGE 3
long long
strtonum(const char *numstr, long long minval, long long maxval,
const char **errstrp)
{
long long ll = 0;
char *ep;
int error = 0;
char *ep;
struct errval {
const char *errstr;
int err;
@@ -45,9 +45,9 @@ strtonum(const char *numstr, long long minval, long long maxval,
ev[0].err = errno;
errno = 0;
if (minval > maxval)
if (minval > maxval) {
error = INVALID;
else {
} else {
ll = strtoll(numstr, &ep, 10);
if (numstr == ep || *ep != '\0')
error = INVALID;
+3 -21
View File
@@ -1,6 +1,6 @@
/* A secure tmpfile() replacement.
*
* Copyright (c) 2015 Joachim Nilsson <troglobit@gmail.com>
* Copyright (c) 2015-2016 Joachim Nilsson <troglobit@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -17,16 +17,9 @@
#include <paths.h>
#include <fcntl.h> /* O_TMPFILE requires -D_GNU_SOURCE */
#include <linux/version.h>
#include <stdlib.h> /* mkstemp() */
#include <stdio.h> /* fdopen() */
#include <sys/stat.h> /* umask() */
#ifndef O_TMPFILE /* Too old GLIBC or kernel */
#warning O_TMPFILE missing on your system, tempfile() may not work!
#define O_TMPFILE 020200000 /* Define and let it fail at runtime */
#endif
/**
* tempfile - A secure tmpfile() replacement
*
@@ -42,7 +35,7 @@
*/
FILE *tempfile(void)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0)
#ifdef O_TMPFILE /* Only on Linux, with fairly recent (G)LIBC */
int fd;
mode_t oldmask;
@@ -54,23 +47,12 @@ FILE *tempfile(void)
return fdopen(fd, "rw");
#else
#warning Too old kernel, reverting to wrap unsafe tmpfile() ...
return tmpfile();
return tmpfile(); /* Fallback on older GLIBC/Linux and actual UNIX systems */
#endif
}
#ifdef UNITTEST
int main(void)
{
FILE *fp = tempfile(); system("ls -lrt "
_PATH_TMP " | tail -10"); return fclose(fp);
}
#endif
/**
* Local Variables:
* compile-command: "make V=1 -f tempfile.mk"
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
-4
View File
@@ -1,4 +0,0 @@
OBJS =
TARGET = tempfile.test clean
include rules.mk
+15
View File
@@ -0,0 +1,15 @@
*.log
*.trs
chomp
copyfile
dir
fexist
fisdir
fsendfile
lfile
makepath
pidfile
progress
rsync
tempfile
tree
+24
View File
@@ -0,0 +1,24 @@
EXTRA_DIST = check.h
CLEANFILES = *~ *.trs *.log
TESTS =
TESTS += chomp
TESTS += copyfile
TESTS += dir
TESTS += fexist
TESTS += fisdir
TESTS += fsendfile
TESTS += lfile
TESTS += makepath
TESTS += pidfile
TESTS += progress
TESTS += rsync
TESTS += tempfile
TESTS += tree
check_PROGRAMS = $(TESTS)
# Ignore warnings about unused result, in e.g. write()
CFLAGS = -W -Wall -Wextra -Wno-unused-result
CPPFLAGS = -D_GNU_SOURCE
LDADD = -L../ ../libite.la
+78
View File
@@ -0,0 +1,78 @@
#ifndef LITE_TESTS_CHECK_H_
#define LITE_TESTS_CHECK_H_
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "../lite.h"
#define fail_unless(test) \
do { \
if (!(test)) { \
fprintf(stderr, \
"----------------------------------------------\n" \
"%s:%d: test FAILED:\nFailed test: %s\n" \
"----------------------------------------------\n", \
__FILE__, __LINE__, #test); \
exit(1); \
} \
} while (0)
static inline int test(int result, const char *fmt, ...)
{
char buf[80];
size_t len;
va_list ap;
const char success[] = " \e[1m[ OK ]\e[0m\n";
const char failure[] = " \e[7m[FAIL]\e[0m\n";
const char dots[] = " .....................................................................";
va_start(ap, fmt);
len = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
write(STDERR_FILENO, buf, len);
write(STDERR_FILENO, dots, 60 - len); /* pad with dots. */
if (!result)
write(STDERR_FILENO, success, strlen(success));
else
write(STDERR_FILENO, failure, strlen(failure));
return result;
}
static inline int timespec_newer(const struct timespec *a, const struct timespec *b)
{
if (a->tv_sec != b->tv_sec)
return a->tv_sec > b->tv_sec;
return a->tv_nsec > b->tv_nsec;
}
static inline char *timespec2str(struct timespec *ts, char *buf, size_t len)
{
size_t ret, pos;
struct tm t;
memset(buf, 0, len);
tzset();
if (localtime_r(&(ts->tv_sec), &t) == NULL)
return buf;
ret = strftime(buf, len, "%F %T", &t);
if (ret == 0)
return buf;
len -= ret - 1;
pos = strlen(buf);
len -= pos;
snprintf(&buf[pos], len, ".%09ld", ts->tv_nsec);
return buf;
}
#endif /* LITE_TESTS_CHECK_H_ */
+24
View File
@@ -0,0 +1,24 @@
#include "check.h"
int main(void)
{
size_t i;
char t[][16] = {
"hej\ndej",
"Slime\n\n\\n",
"Tripple\n\n\n"
};
for (i = 0; i < NELEMS(t); i++) {
char *str = t[i];
size_t len;
chomp(str);
len = strlen(str);
printf("[%02zd]: '%s'\n", i, str);
fail_unless(str[len] != '\n');
}
return 0;
}
+55
View File
@@ -0,0 +1,55 @@
#include <err.h>
#include <errno.h>
#include "check.h"
int main(void)
{
int i = 0;
char *files[] = {
"/etc/passwd", "/tmp/mypwd", "/tmp/mypwd",
"/etc/passwd", "/tmp/", "/tmp/passwd",
"/etc/passwd", "/tmp", "/tmp/passwd",
NULL
};
FILE *src, *dst;
printf("=>Start testing fcopyfile()\n");
while (files[i]) {
printf("fcopyfile(%s, %s)\t", files[i], files[i + 1]);
src = fopen(files[i], "r");
dst = fopen(files[i + 1], "w");
if (fcopyfile(src, dst)) {
if (!fisdir(files[i + 1]))
err(1, "Failed fcopyfile(%s, %s)", files[i], files[i + 1]);
}
if (src)
fclose(src);
if (dst)
fclose(dst);
if (fexist(files[i + 2]))
printf("OK => %s", files[i + 2]);
printf("\n");
erase(files[i + 2]);
i += 3;
}
printf("\n=>Start testing copyfile()\n");
i = 0;
while (files[i]) {
printf("copyfile(%s, %s)\t", files[i], files[i + 1]);
if (!copyfile(files[i], files[i + 1], 0, 0))
err(1, "Failed copyfile(%s, %s)", files[i], files[i + 1]);
if (fexist(files[i + 2]))
printf("OK => %s", files[i + 2]);
printf("\n");
erase(files[i + 2]);
i += 3;
}
return 0;
}
+99
View File
@@ -0,0 +1,99 @@
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include "check.h"
#define DIR_TYPE_IMAGE ".img"
#define DIR_TYPE_SYSLOG ""
#define DIR_TYPE_CONFIG ".cfg"
#define STARTUP_CONFIG "startup-config.cfg"
int simulate_files(int creat)
{
size_t i;
char *files[] =
{ "config0.cfg", "config1.cfg", "config2.cfg", "config3.cfg",
"rr109.img", "rx100.img", "rx107.img", "rm957.img", "messages"
};
for (i = 0; i < NELEMS(files); i++) {
if (creat)
touch(files[i]);
else
erase(files[i]);
}
if (creat)
symlink("config2.cfg", STARTUP_CONFIG);
else
erase(STARTUP_CONFIG);
return 0;
}
static int cfg_dir_filter(const char *file)
{
/* Skip the STARTUP_CONFIG file, it is a symbolic link to the
* current startup configuration. */
return ! !strcmp(file, STARTUP_CONFIG);
}
static int is_startup_config(const char *entry)
{
static int once = 1;
static char file[80];
if (once) {
int len = readlink(STARTUP_CONFIG, file, sizeof(file));
if (len == -1)
return 0;
file[len] = 0;
once = 0; /* Only once per call to dir() */
}
//printf ("Comparing link %s with entry %s\n", file, entry);
return !strcmp(file, entry);
}
int main(int argc, char *argv[])
{
int i, num;
char *type = DIR_TYPE_CONFIG;
char **files;
simulate_files(1);
if (argc >= 2) {
if (!strcasecmp("CONFIG", argv[1])) {
type = DIR_TYPE_CONFIG;
system("ls -l *" DIR_TYPE_CONFIG);
}
if (!strcasecmp("IMAGE", argv[1])) {
type = DIR_TYPE_IMAGE;
system("ls -l *" DIR_TYPE_IMAGE);
}
if (!strcasecmp("SYSLOG", argv[1])) {
type = DIR_TYPE_SYSLOG;
system("ls -l *");
}
}
num = dir(NULL, type, cfg_dir_filter, &files, 0);
if (num) {
for (i = 0; i < num; i++) {
printf("%s", files[i]);
if (is_startup_config(files[i]))
printf(" --> startup-config");
printf("\n");
free(files[i]);
}
free(files);
}
simulate_files(0);
return 0;
}
+23
View File
@@ -0,0 +1,23 @@
#include "check.h"
int main(void)
{
size_t i = 0;
struct { char *file; int exist; } arr[] = {
{ "/etc/passwd", 1 },
{ "/etc/kalle", 0 },
{ "/sbin/init", 1 },
{ "/dev/null", 1 },
{ NULL, 0 },
};
for (i = 0; i < NELEMS(arr); i++) {
if (fexist(arr[i].file) != arr[i].exist)
err(1, "Failed fexist(%s)", arr[i].file ?: "NULL");
else
printf("File %-11s %-14s => OK!\n", arr[i].file ?: "NULL",
arr[i].exist ? "does exist" : "does not exist");
}
return 0;
}
+24
View File
@@ -0,0 +1,24 @@
#include "check.h"
int main(void)
{
size_t i = 0;
struct { char *file; int exist; } arr[] = {
{ "/etc/passwd", 0 },
{ "/etc/", 1 },
{ "/sbin/init", 0 },
{ "/dev/null", 0 },
{ "/dev/", 1 },
{ NULL, 0 },
};
for (i = 0; i < NELEMS(arr); i++) {
if (fisdir(arr[i].file) != arr[i].exist)
err(1, "Failed fisdir(%s)", arr[i].file ?: "NULL");
else
printf("fisdir() %-11s %-18s => OK!\n", arr[i].file ?: "NULL",
arr[i].exist ? "is a directory" : "is NOT a directory");
}
return 0;
}
+31
View File
@@ -0,0 +1,31 @@
#include <err.h>
#include <unistd.h>
#include "check.h"
int main(void)
{
int i = 0;
char *files[] = {
"/etc/passwd", "/tmp/tok",
"/etc/passwd", "/tmp/passwd",
"/etc/passwd", "/tmp/passwd",
NULL
};
FILE *src, *dst;
while (files[i]) {
src = fopen(files[i], "r");
dst = fopen(files[i + 1], "w");
printf("fsendfile(%s, %s, 512)\t", files[i], files[i + 1]);
if (-1 == fsendfile(src, dst, 512))
err(1, "Failed fsendfile(%s, %s)", files[i], files[i + 1]);
if (!access(files[i + 1], F_OK))
printf("OK => %s\n", files[i + 1]);
remove(files[i + 1]);
i += 2;
}
return 0;
}
+37
View File
@@ -0,0 +1,37 @@
#include <stdio.h>
#include "check.h"
int main(void)
{
int val;
val = fgetint("/etc/protocols", " \n\t", "udp");
if (val == -1) {
perror("Failed locating 'udp' protocol");
return 1;
}
printf("udp has proto %d\n", val);
val = fgetint("/etc/services", " /\n\t", "ftp");
if (val == -1) {
perror("Failed locating 'ftp' service");
return 1;
}
printf("ftp is inet port %d\n", val);
val = fgetint("/etc/group", "x:\n", "utmp");
if (val == -1) {
perror("Failed locating group 'utmp'");
return 1;
}
printf("utmp is gid %d\n", val);
val = fgetint("/etc/passwd", "x:\n", "nobody");
if (val == -1) {
perror("Failed locating user 'nobody'");
return 1;
}
printf("nobody is uid %d\n", val);
return 0;
}
+60
View File
@@ -0,0 +1,60 @@
#include <errno.h>
#include <stdlib.h>
#include "check.h"
int checkpath(char *dir)
{
char tmp[256];
struct stat sb;
snprintf(tmp, sizeof(tmp), "ls -ld %s", dir);
if (system(tmp))
perror("system");
if (!stat(dir, &sb) && S_ISDIR(sb.st_mode))
return 0;
errno = ENOTDIR;
return 1;
}
int test_makepath(char *dir)
{
int ret = makepath(dir);
if (!ret)
ret = checkpath(dir);
if (ret)
perror("Failed");
return ret;
}
int main(void)
{
int i, ret = 0;
char *list[] = {
"/tmp/tok/",
"/tmp/tok2",
"/tmp/ab",
"/tmp/b",
"/tmp/a/",
"/tmp/a/b",
"/tmp/a/c/",
"../../sometestdir/arpa/inet",
NULL
};
for (i = 0; list[i]; i++)
rmdir(list[i]);
printf("Testing makepath() ...\n");
for (i = 0; list[i] && !ret; i++)
ret |= test_makepath(list[i]);
printf("\nCleaning up ...\n");
for (i = 0; list[i]; i++)
rmdir(list[i]);
return ret;
}
+73
View File
@@ -0,0 +1,73 @@
#include <paths.h>
#include <signal.h>
#include <stdarg.h>
#include <time.h>
#include "check.h"
extern char *__progname;
extern char *__pidfile_name;
extern char *__pidfile_path;
static char PIDFILE[42];
static int verbose = 0;
static struct stat before, after;
static void sigterm_handler(int UNUSED(signo))
{
if (verbose)
printf("Exiting ...\n");
}
static void sigalrm_handler(int UNUSED(signo))
{
pidfile(NULL);
if (!fexist(PIDFILE))
err(1, "failed creating %s", PIDFILE);
stat(PIDFILE, &before);
}
static int mtime()
{
int ret;
char buf[80];
/* Must sleep a while here otherwise we execute too fast => no mtime change :-( */
usleep(10000);
if (verbose)
printf("Calling pidfile() again to update mtime ...\n");
pidfile(NULL);
stat(PIDFILE, &after);
ret = timespec_newer(&after.st_mtim, &before.st_mtim);
if (verbose) {
printf("Before: %s\n", timespec2str(&before.st_mtim, buf, sizeof(buf)));
printf("After : %s\n", timespec2str(&after.st_mtim, buf, sizeof(buf)));
}
return !ret;
}
int main(int argc, char *argv[])
{
if (argc > 1 && !strcmp(argv[1], "-v"))
verbose = 1;
/* Override default _PATH_VARRUN in pidfile() */
__pidfile_path = _PATH_TMP;
snprintf(PIDFILE, sizeof(PIDFILE), "%s%s.pid", __pidfile_path, __progname);
signal(SIGTERM, sigterm_handler);
signal(SIGALRM, sigalrm_handler);
alarm(1);
return test(pidfile_poll(PIDFILE) != getpid(), "Testing pidfile_poll()")
|| test(strcmp(__pidfile_name, PIDFILE), "Testing __pidfile_name vs guessed PID filename")
|| test(mtime(), "Testing mtime update of followup pidfile() call")
|| test(pidfile_signal(PIDFILE, SIGTERM), "Testing signalling ourselves")
;
return 0;
}
+50
View File
@@ -0,0 +1,50 @@
#include <stdlib.h> /* atexit() */
#include <unistd.h> /* usleep() */
#include "conio.h"
#include "check.h"
#define MAX_WIDTH 80
#define msleep(msec) usleep(msec * 1000)
static void bye(void)
{
showcursor();
}
static void testit(int fn, int percent)
{
if (fn)
progress(percent, MAX_WIDTH);
else
progress_simple(percent);
}
static void run_test(int fn)
{
int i, percent, block = 0, num = 85;
while (block < num) {
percent = block * 100 / num;
for (i = 0; i < 10; i++) {
testit(fn, percent);
msleep(1);
}
block++;
msleep(1);
}
testit(fn, 100);
}
int main(void)
{
atexit(bye);
hidecursor();
printf("\nAdvanced:\n");
run_test(1);
printf("\nSimple:\n");
run_test(0);
printf("\n");
return 0;
}
+108
View File
@@ -0,0 +1,108 @@
#include <stdlib.h>
#include "check.h"
#define BASE "/tmp/.unittest/"
#define SRC BASE "src/"
#define DST BASE "dst/"
static int verbose = 0;
static char *files[] = {
SRC "sub1/1.tst",
SRC "sub1/2.tst",
SRC "sub1/3.tst",
SRC "sub2/4.tst",
SRC "sub2/5.tst",
SRC "sub2/6.tst",
SRC "sub3/7.tst",
SRC "sub3/8.tst",
SRC "sub3/9.tst",
NULL
};
void cleanup_test(void)
{
system("rm -rf " BASE);
}
void setup_test(void)
{
int i;
char cmd[256];
mode_t dir_modes[] = { 755, 700 };
mode_t file_modes[] = { 644, 600 };
cleanup_test();
mkdir(BASE, 0755);
mkdir(SRC, 0755);
mkdir(DST, 0755);
for (i = 0; files[i]; i++) {
snprintf(cmd, sizeof(cmd), "mkdir -m %d -p `dirname %s`",
dir_modes[i % 2], files[i]);
system(cmd);
snprintf(cmd, sizeof(cmd), "touch %s; chmod %d %s", files[i],
file_modes[i % 2], files[i]);
system(cmd);
}
}
static void check_tree(char *heading, char *dir)
{
if (verbose) {
if (heading)
puts(heading);
tree(dir, 1);
}
}
int run_test(void)
{
int result = 0;
#if 0
setup_test();
check_tree("Before:", BASE);
result += rsync(SRC, DST, 0, NULL);
check_tree("After:", BASE);
cleanup_test();
#endif
setup_test();
result += rsync(BASE "src", DST, 0, NULL);
check_tree("Only partial rsync of src <-- No slash!", BASE);
#if 0
cleanup_test();
setup_test();
result += rsync(BASE "src/sub1", BASE "dst", 0, NULL);
check_tree("Only partial rsync of src/sub1 <-- No slashes!!", BASE);
cleanup_test();
setup_test();
result += rsync(BASE "src/sub1/", DST, 0, NULL);
check_tree("Only partial rsync of src/sub1/", BASE);
cleanup_test();
setup_test();
result += rsync(BASE "src/sub1", DST, 0, NULL);
check_tree("Only partial rsync of src/sub1 <-- No slash!", BASE);
result += rsync("/etc", "/var/tmp", 0, NULL);
check_tree("Real life test:", "/var/tmp");
#endif
return result;
}
int main(int argc, char *argv[])
{
if (argc > 1)
verbose = !strncmp("-v", argv[1], 2);
atexit(cleanup_test);
return run_test();
}
+25
View File
@@ -0,0 +1,25 @@
#include <fcntl.h> /* O_TMPFILE requires -D_GNU_SOURCE */
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include "check.h"
#ifndef O_TMPFILE
#warning O_TMPFILE is missing, either too old GLIBC, Linux, or non-Linux system
#endif
int main(void)
{
FILE *fp;
printf("Before tempfile():\n");
system("ls -lrt " _PATH_TMP " | tail -3");
fp = tempfile();
fail_unless(fp != NULL);
printf("\nAfter tempfile(), should be same list:\n");
system("ls -lrt " _PATH_TMP " | tail -3");
return fclose(fp);
}
+19
View File
@@ -0,0 +1,19 @@
#include "check.h"
int main(void)
{
int result = 0;
size_t i;
struct { char *path; int fail; } arr[] = {
{ "/etc/passwd", -1 },
{ "/dev", 0 },
{ "/sbin", 0 },
};
for (i = 0; i < NELEMS(arr); i++) {
if (tree(arr[i].path, 1) != arr[i].fail)
result++;
}
return result;
}
-23
View File
@@ -120,31 +120,8 @@ int tree(char *path, int show_perms)
return descend(path, show_perms, "");
}
#ifdef UNITTEST
#include "lite.h"
int main(void)
{
int i, result = 0;
struct { char *path; int fail; } arr[] = {
{ "/etc/passwd", -1 },
{ "/dev", 0 },
{ "/sbin", 0 },
};
for (i = 0; i < NELEMS(arr); i++) {
if (tree(arr[i].path, 1) != arr[i].fail)
result++;
}
return result;
}
#endif
/**
* Local Variables:
* compile-command: "make V=1 -f tree.mk"
* version-control: t
* indent-tabs-mode: t
* c-file-style: "linux"
* End:
+748
View File
@@ -0,0 +1,748 @@
/* $OpenBSD: tree.h,v 1.14 2015/05/25 03:07:49 deraadt Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SYS_TREE_H_
#define _SYS_TREE_H_
/*
* This file defines data structures for different types of trees:
* splay trees and red-black trees.
*
* A splay tree is a self-organizing data structure. Every operation
* on the tree causes a splay to happen. The splay moves the requested
* node to the root of the tree and partly rebalances it.
*
* This has the benefit that request locality causes faster lookups as
* the requested nodes move to the top of the tree. On the other hand,
* every lookup causes memory writes.
*
* The Balance Theorem bounds the total access time for m operations
* and n inserts on an initially empty tree as O((m + n)lg n). The
* amortized cost for a sequence of m accesses to a splay tree is O(lg n);
*
* A red-black tree is a binary search tree with the node color as an
* extra attribute. It fulfills a set of conditions:
* - every search path from the root to a leaf consists of the
* same number of black nodes,
* - each red node (except for the root) has a black parent,
* - each leaf node is black.
*
* Every operation on a red-black tree is bounded as O(lg n).
* The maximum height of a red-black tree is 2lg (n+1).
*/
#define SPLAY_HEAD(name, type) \
struct name { \
struct type *sph_root; /* root of the tree */ \
}
#define SPLAY_INITIALIZER(root) \
{ NULL }
#define SPLAY_INIT(root) do { \
(root)->sph_root = NULL; \
} while (0)
#define SPLAY_ENTRY(type) \
struct { \
struct type *spe_left; /* left element */ \
struct type *spe_right; /* right element */ \
}
#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
#define SPLAY_ROOT(head) (head)->sph_root
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (0)
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (0)
#define SPLAY_LINKLEFT(head, tmp, field) do { \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
} while (0)
#define SPLAY_LINKRIGHT(head, tmp, field) do { \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
} while (0)
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
} while (0)
/* Generates prototypes and inline functions */
#define SPLAY_PROTOTYPE(name, type, field, cmp) \
void name##_SPLAY(struct name *, struct type *); \
void name##_SPLAY_MINMAX(struct name *, int); \
struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
\
/* Finds the node with the same key as elm */ \
static __inline struct type * \
name##_SPLAY_FIND(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) \
return(NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) \
return (head->sph_root); \
return (NULL); \
} \
\
static __inline struct type * \
name##_SPLAY_NEXT(struct name *head, struct type *elm) \
{ \
name##_SPLAY(head, elm); \
if (SPLAY_RIGHT(elm, field) != NULL) { \
elm = SPLAY_RIGHT(elm, field); \
while (SPLAY_LEFT(elm, field) != NULL) { \
elm = SPLAY_LEFT(elm, field); \
} \
} else \
elm = NULL; \
return (elm); \
} \
\
static __inline struct type * \
name##_SPLAY_MIN_MAX(struct name *head, int val) \
{ \
name##_SPLAY_MINMAX(head, val); \
return (SPLAY_ROOT(head)); \
}
/* Main splay operation.
* Moves node close to the key of elm to top
*/
#define SPLAY_GENERATE(name, type, field, cmp) \
struct type * \
name##_SPLAY_INSERT(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) { \
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
} else { \
int __comp; \
name##_SPLAY(head, elm); \
__comp = (cmp)(elm, (head)->sph_root); \
if(__comp < 0) { \
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
SPLAY_RIGHT(elm, field) = (head)->sph_root; \
SPLAY_LEFT((head)->sph_root, field) = NULL; \
} else if (__comp > 0) { \
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT(elm, field) = (head)->sph_root; \
SPLAY_RIGHT((head)->sph_root, field) = NULL; \
} else \
return ((head)->sph_root); \
} \
(head)->sph_root = (elm); \
return (NULL); \
} \
\
struct type * \
name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *__tmp; \
if (SPLAY_EMPTY(head)) \
return (NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) { \
if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
} else { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
name##_SPLAY(head, elm); \
SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
} \
return (elm); \
} \
return (NULL); \
} \
\
void \
name##_SPLAY(struct name *head, struct type *elm) \
{ \
struct type __node, *__left, *__right, *__tmp; \
int __comp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while ((__comp = (cmp)(elm, (head)->sph_root))) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) > 0){ \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
} \
\
/* Splay with either the minimum or the maximum element \
* Used to find minimum or maximum element in tree. \
*/ \
void name##_SPLAY_MINMAX(struct name *head, int __comp) \
{ \
struct type __node, *__left, *__right, *__tmp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while (1) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp > 0) { \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
}
#define SPLAY_NEGINF -1
#define SPLAY_INF 1
#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_INF))
#define SPLAY_FOREACH(x, name, head) \
for ((x) = SPLAY_MIN(name, head); \
(x) != NULL; \
(x) = SPLAY_NEXT(name, head, x))
/* Macros that define a red-black tree */
#define RB_HEAD(name, type) \
struct name { \
struct type *rbh_root; /* root of the tree */ \
}
#define RB_INITIALIZER(root) \
{ NULL }
#define RB_INIT(root) do { \
(root)->rbh_root = NULL; \
} while (0)
#define RB_BLACK 0
#define RB_RED 1
#define RB_ENTRY(type) \
struct { \
struct type *rbe_left; /* left element */ \
struct type *rbe_right; /* right element */ \
struct type *rbe_parent; /* parent element */ \
int rbe_color; /* node color */ \
}
#define RB_LEFT(elm, field) (elm)->field.rbe_left
#define RB_RIGHT(elm, field) (elm)->field.rbe_right
#define RB_PARENT(elm, field) (elm)->field.rbe_parent
#define RB_COLOR(elm, field) (elm)->field.rbe_color
#define RB_ROOT(head) (head)->rbh_root
#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
#define RB_SET(elm, parent, field) do { \
RB_PARENT(elm, field) = parent; \
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
RB_COLOR(elm, field) = RB_RED; \
} while (0)
#define RB_SET_BLACKRED(black, red, field) do { \
RB_COLOR(black, field) = RB_BLACK; \
RB_COLOR(red, field) = RB_RED; \
} while (0)
#ifndef RB_AUGMENT
#define RB_AUGMENT(x) do {} while (0)
#endif
#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
(tmp) = RB_RIGHT(elm, field); \
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \
RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
} \
RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
} else \
(head)->rbh_root = (tmp); \
RB_LEFT(tmp, field) = (elm); \
RB_PARENT(elm, field) = (tmp); \
RB_AUGMENT(tmp); \
if ((RB_PARENT(tmp, field))) \
RB_AUGMENT(RB_PARENT(tmp, field)); \
} while (0)
#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
(tmp) = RB_LEFT(elm, field); \
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \
RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
} \
RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
} else \
(head)->rbh_root = (tmp); \
RB_RIGHT(tmp, field) = (elm); \
RB_PARENT(elm, field) = (tmp); \
RB_AUGMENT(tmp); \
if ((RB_PARENT(tmp, field))) \
RB_AUGMENT(RB_PARENT(tmp, field)); \
} while (0)
/* Generates prototypes and inline functions */
#define RB_PROTOTYPE(name, type, field, cmp) \
RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static)
#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
attr struct type *name##_RB_REMOVE(struct name *, struct type *); \
attr struct type *name##_RB_INSERT(struct name *, struct type *); \
attr struct type *name##_RB_FIND(struct name *, struct type *); \
attr struct type *name##_RB_NFIND(struct name *, struct type *); \
attr struct type *name##_RB_NEXT(struct type *); \
attr struct type *name##_RB_PREV(struct type *); \
attr struct type *name##_RB_MINMAX(struct name *, int); \
\
/* Main rb operation.
* Moves node close to the key of elm to top
*/
#define RB_GENERATE(name, type, field, cmp) \
RB_GENERATE_INTERNAL(name, type, field, cmp,)
#define RB_GENERATE_STATIC(name, type, field, cmp) \
RB_GENERATE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static)
#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
attr void \
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
{ \
struct type *parent, *gparent, *tmp; \
while ((parent = RB_PARENT(elm, field)) && \
RB_COLOR(parent, field) == RB_RED) { \
gparent = RB_PARENT(parent, field); \
if (parent == RB_LEFT(gparent, field)) { \
tmp = RB_RIGHT(gparent, field); \
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_RIGHT(parent, field) == elm) { \
RB_ROTATE_LEFT(head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(parent, gparent, field); \
RB_ROTATE_RIGHT(head, gparent, tmp, field); \
} else { \
tmp = RB_LEFT(gparent, field); \
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_LEFT(parent, field) == elm) { \
RB_ROTATE_RIGHT(head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(parent, gparent, field); \
RB_ROTATE_LEFT(head, gparent, tmp, field); \
} \
} \
RB_COLOR(head->rbh_root, field) = RB_BLACK; \
} \
\
attr void \
name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
{ \
struct type *tmp; \
while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
elm != RB_ROOT(head)) { \
if (RB_LEFT(parent, field) == elm) { \
tmp = RB_RIGHT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) { \
RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_LEFT(head, parent, tmp, field);\
tmp = RB_RIGHT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \
parent = RB_PARENT(elm, field); \
} else { \
if (RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
struct type *oleft; \
if ((oleft = RB_LEFT(tmp, field)))\
RB_COLOR(oleft, field) = RB_BLACK;\
RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_RIGHT(head, tmp, oleft, field);\
tmp = RB_RIGHT(parent, field); \
} \
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
RB_COLOR(parent, field) = RB_BLACK; \
if (RB_RIGHT(tmp, field)) \
RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
RB_ROTATE_LEFT(head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} else { \
tmp = RB_LEFT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) { \
RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_RIGHT(head, parent, tmp, field);\
tmp = RB_LEFT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \
parent = RB_PARENT(elm, field); \
} else { \
if (RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
struct type *oright; \
if ((oright = RB_RIGHT(tmp, field)))\
RB_COLOR(oright, field) = RB_BLACK;\
RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_LEFT(head, tmp, oright, field);\
tmp = RB_LEFT(parent, field); \
} \
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
RB_COLOR(parent, field) = RB_BLACK; \
if (RB_LEFT(tmp, field)) \
RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
RB_ROTATE_RIGHT(head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} \
} \
if (elm) \
RB_COLOR(elm, field) = RB_BLACK; \
} \
\
attr struct type * \
name##_RB_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *child, *parent, *old = elm; \
int color; \
if (RB_LEFT(elm, field) == NULL) \
child = RB_RIGHT(elm, field); \
else if (RB_RIGHT(elm, field) == NULL) \
child = RB_LEFT(elm, field); \
else { \
struct type *left; \
elm = RB_RIGHT(elm, field); \
while ((left = RB_LEFT(elm, field))) \
elm = left; \
child = RB_RIGHT(elm, field); \
parent = RB_PARENT(elm, field); \
color = RB_COLOR(elm, field); \
if (child) \
RB_PARENT(child, field) = parent; \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
if (RB_PARENT(elm, field) == old) \
parent = elm; \
(elm)->field = (old)->field; \
if (RB_PARENT(old, field)) { \
if (RB_LEFT(RB_PARENT(old, field), field) == old)\
RB_LEFT(RB_PARENT(old, field), field) = elm;\
else \
RB_RIGHT(RB_PARENT(old, field), field) = elm;\
RB_AUGMENT(RB_PARENT(old, field)); \
} else \
RB_ROOT(head) = elm; \
RB_PARENT(RB_LEFT(old, field), field) = elm; \
if (RB_RIGHT(old, field)) \
RB_PARENT(RB_RIGHT(old, field), field) = elm; \
if (parent) { \
left = parent; \
do { \
RB_AUGMENT(left); \
} while ((left = RB_PARENT(left, field))); \
} \
goto color; \
} \
parent = RB_PARENT(elm, field); \
color = RB_COLOR(elm, field); \
if (child) \
RB_PARENT(child, field) = parent; \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
color: \
if (color == RB_BLACK) \
name##_RB_REMOVE_COLOR(head, parent, child); \
return (old); \
} \
\
/* Inserts a node into the RB tree */ \
attr struct type * \
name##_RB_INSERT(struct name *head, struct type *elm) \
{ \
struct type *tmp; \
struct type *parent = NULL; \
int comp = 0; \
tmp = RB_ROOT(head); \
while (tmp) { \
parent = tmp; \
comp = (cmp)(elm, parent); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
RB_SET(elm, parent, field); \
if (parent != NULL) { \
if (comp < 0) \
RB_LEFT(parent, field) = elm; \
else \
RB_RIGHT(parent, field) = elm; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = elm; \
name##_RB_INSERT_COLOR(head, elm); \
return (NULL); \
} \
\
/* Finds the node with the same key as elm */ \
attr struct type * \
name##_RB_FIND(struct name *head, struct type *elm) \
{ \
struct type *tmp = RB_ROOT(head); \
int comp; \
while (tmp) { \
comp = cmp(elm, tmp); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
return (NULL); \
} \
\
/* Finds the first node greater than or equal to the search key */ \
attr struct type * \
name##_RB_NFIND(struct name *head, struct type *elm) \
{ \
struct type *tmp = RB_ROOT(head); \
struct type *res = NULL; \
int comp; \
while (tmp) { \
comp = cmp(elm, tmp); \
if (comp < 0) { \
res = tmp; \
tmp = RB_LEFT(tmp, field); \
} \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
return (res); \
} \
\
/* ARGSUSED */ \
attr struct type * \
name##_RB_NEXT(struct type *elm) \
{ \
if (RB_RIGHT(elm, field)) { \
elm = RB_RIGHT(elm, field); \
while (RB_LEFT(elm, field)) \
elm = RB_LEFT(elm, field); \
} else { \
if (RB_PARENT(elm, field) && \
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \
elm = RB_PARENT(elm, field); \
else { \
while (RB_PARENT(elm, field) && \
(elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
elm = RB_PARENT(elm, field); \
elm = RB_PARENT(elm, field); \
} \
} \
return (elm); \
} \
\
/* ARGSUSED */ \
attr struct type * \
name##_RB_PREV(struct type *elm) \
{ \
if (RB_LEFT(elm, field)) { \
elm = RB_LEFT(elm, field); \
while (RB_RIGHT(elm, field)) \
elm = RB_RIGHT(elm, field); \
} else { \
if (RB_PARENT(elm, field) && \
(elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
elm = RB_PARENT(elm, field); \
else { \
while (RB_PARENT(elm, field) && \
(elm == RB_LEFT(RB_PARENT(elm, field), field)))\
elm = RB_PARENT(elm, field); \
elm = RB_PARENT(elm, field); \
} \
} \
return (elm); \
} \
\
attr struct type * \
name##_RB_MINMAX(struct name *head, int val) \
{ \
struct type *tmp = RB_ROOT(head); \
struct type *parent = NULL; \
while (tmp) { \
parent = tmp; \
if (val < 0) \
tmp = RB_LEFT(tmp, field); \
else \
tmp = RB_RIGHT(tmp, field); \
} \
return (parent); \
}
#define RB_NEGINF -1
#define RB_INF 1
#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
#define RB_PREV(name, x, y) name##_RB_PREV(y)
#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
#define RB_FOREACH(x, name, head) \
for ((x) = RB_MIN(name, head); \
(x) != NULL; \
(x) = name##_RB_NEXT(x))
#define RB_FOREACH_SAFE(x, name, head, y) \
for ((x) = RB_MIN(name, head); \
((x) != NULL) && ((y) = name##_RB_NEXT(x), 1); \
(x) = (y))
#define RB_FOREACH_REVERSE(x, name, head) \
for ((x) = RB_MAX(name, head); \
(x) != NULL; \
(x) = name##_RB_PREV(x))
#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \
for ((x) = RB_MAX(name, head); \
((x) != NULL) && ((y) = name##_RB_PREV(x), 1); \
(x) = (y))
#endif /* _SYS_TREE_H_ */
-4
View File
@@ -1,4 +0,0 @@
OBJS =
TARGET = clean $(OBJS) tree.test
include rules.mk