mirror of
https://github.com/troglobit/libite.git
synced 2026-10-15 10:29:31 +00:00
Fix I/O plugin watcher, load plugins earlier to enable a new early hook!
Restructure start by calling the plugin loader earlier. This makes it
possible to run hooks even earlier. This also adds a new hook:
HOOK_ROOTFS_UP which runs as soon as the system root (/) is available.
Another very notable change is the slow refactor of helpers.c into a finit
helper library called libite.so (-lite). This is a light-weight
Also, lots of misc. fixes all over the place. Signal handling still really
needs to be looked into once more!
Makefile:
Add dependency handling for parallell build
Add libite library
ChangeLog:
Update with new 1.4 release. There is a lot of fixes!
libite/:
Collection of utility functions and C library extensions for
finit & its plugins
reboot.c:
New reboot tool. Simply sends SIGINT to PID 1
finit.h:
Cleanup old LISTEN_INITCTL define, code is in an optional plugin now
finit.c:
Let mdev/udev run *after* cls()
Add useful debug statement for /proc/cmdline
Earlier plugin load => new early hook point
Show OK/FAIL for total plugin load, not for each plugin => speedup
helpers.h:
Rename syslog macros to prevent common name clashes (DEBUG/ERROR)
Add __FILE__ to _e(), _d() and _pe() macros
helpers.c:
In ifconfig() the addr and mask arguments are now optional
The copyfile() has been moved to libite.so
Temporarily remove const directive from some functions to build
Use DFLSIG() macro in run_getty() to simplify code
plugin.h:
Add new HOOK_ROOTFS_UP hook
plugin.c:
Fix init_plugins() to actually register the plugin's I/O fd
Skip verbose listing of all plugins in plugin_load_all()
svc.c:
svc_start(): Dito
plugins/Makefile:
Inherit CFLAGS and LDFLAGS, but make sure to filter out -rdynamic
from LDFLAGS, it's used by the daemon, only
plugins/initctl.c:
New includes after helpers.h refactor
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
This commit is contained in:
commit
777502f175
9 files changed
+1148
No files matched your search
@@ -0,0 +1,79 @@
|
||||
# Finit libite -- Light-weight utility functions and C-library extensions
|
||||
#
|
||||
# Copyright (c) 2008-2012 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.
|
||||
|
||||
.EXPORT_ALL_VARIABLES:
|
||||
.PHONY: all install clean
|
||||
|
||||
include ../common.mk
|
||||
|
||||
CFLAGS += -fPIC
|
||||
HEADERS = lite.h
|
||||
OBJS := copyfile.o dir.o fexist.o fisdir.o fmode.o rsync.o
|
||||
DEPS := $(addprefix ., $(OBJS:.o=.d))
|
||||
|
||||
VER = 0
|
||||
LIBNAME = libite
|
||||
TARGET = $(LIBNAME).so
|
||||
VERLIB = $(TARGET).$(VER)
|
||||
STATICLIB = $(LIBNAME).a
|
||||
|
||||
CHECK_FLAGS = $(CFLAGS) $(CPPFLAGS)
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(OBJS): Makefile
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
@printf " LINK %s\n" $@
|
||||
# @$(AR) $(ARFLAGS) $(STATICLIB) $(OBJS)
|
||||
@$(CC) $(LDFLAGS) -shared $(OBJS) -lrt -lcrypt -Wl,-soname,$@ -o $@
|
||||
@ln -sf $@ $(VERLIB)
|
||||
|
||||
install-exec: all
|
||||
@install -d $(DESTDIR)$(libdir)
|
||||
@echo " INSTALL $(DESTDIR)$(libdir)/$(TARGET)"
|
||||
@$(STRIPINST) $(TARGET) $(DESTDIR)$(libdir)/$(TARGET)
|
||||
@ln -sf $(TARGET) $(DESTDIR)$(libdir)/$(VERLIB)
|
||||
|
||||
install-dev:
|
||||
@for file in $(HEADERS); do \
|
||||
printf " INSTALL $(DESTDIR)$(incdir)/$$file\n"; \
|
||||
$(INSTALL) -m 0644 $$file $(DESTDIR)$(incdir)/$$file; \
|
||||
done
|
||||
|
||||
install: install-dev install-exec
|
||||
|
||||
uninstall:
|
||||
-@$(RM) $(DESTDIR)$(libdir)/$(VERLIB)
|
||||
-@$(RM) $(DESTDIR)$(libdir)/$(TARGET)
|
||||
|
||||
clean: uninstall
|
||||
-@$(RM) $(OBJS) $(DEPS) $(TARGET) $(VERLIB) $(STATICLIB)
|
||||
|
||||
distclean: clean
|
||||
-@$(RM) $(JUNK) unittest *.o .*.d *.unittest
|
||||
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
ifneq ($(MAKECMDGOALS),distclean)
|
||||
-include $(DEPS)
|
||||
endif
|
||||
endif
|
||||
+317
@@ -0,0 +1,317 @@
|
||||
/* Fastinit (finit) copyfile() implementation.
|
||||
*
|
||||
* Copyright (c) 2008 Claudio Matsuoka <http://helllabs.org/finit/>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h> /* MAX(), isset(), setbit(), TRUE, FALSE, et consortes. :-) */
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lite.h"
|
||||
|
||||
static int __isdir_and_append_filename(char *src, char **dst);
|
||||
|
||||
/**
|
||||
* copyfile - Copy a file to another.
|
||||
* @src: Source file.
|
||||
* @dst: Target file.
|
||||
* @len: Number of bytes to copy, zero (0) for entire file.
|
||||
*
|
||||
* This is a C implementation of the command line cp(1) utility. It is one
|
||||
* of the classic missing links in the UNIX C library. This version is from
|
||||
* the finit project, http://helllabs.org/finit/, which is a reimplementation
|
||||
* of fastinit for the Asus EeePC.
|
||||
*
|
||||
* Only some small changes to save stack space have been introduced.
|
||||
*
|
||||
* Returns:
|
||||
* The number of bytes copied, zero may be error (check errno!), but it
|
||||
* may also indicate that @src was empty. If @src is a directory errno
|
||||
* will be set to %EISDIR since copyfile() is not recursive.
|
||||
*/
|
||||
ssize_t copyfile(char *src, char *dst, int len)
|
||||
{
|
||||
char *buffer;
|
||||
int s, d, n, isdir = 0, saved_errno = 0;
|
||||
ssize_t size = 0;
|
||||
|
||||
errno = 0; /* Reset before leaving this function. */
|
||||
// fprintf (stderr, "%s() src: %s, dst: %s, len: %d\n", __func__, src, dst, len);
|
||||
|
||||
buffer = malloc(BUFSIZ);
|
||||
if (!buffer)
|
||||
return 0;
|
||||
|
||||
if (fisdir(src)) {
|
||||
errno = EISDIR; /* Error: source is a directory */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if target is a directory, then append the src base filename. */
|
||||
isdir = __isdir_and_append_filename(src, &dst);
|
||||
|
||||
/* Len == 0 means copy entire file */
|
||||
if (len == 0) {
|
||||
/* XXX: This feels a bit unsafe, but 2047 MiB may be sufficient for us.
|
||||
* --Jocke 2008-08-11 */
|
||||
len = INT_MAX;
|
||||
}
|
||||
|
||||
if ((s = open(src, O_RDONLY)) >= 0) {
|
||||
if ((d =
|
||||
open(dst, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
fmode(src))) >= 0) {
|
||||
do {
|
||||
int clen = len > BUFSIZ ? BUFSIZ : len;
|
||||
|
||||
if ((n = read(s, buffer, clen)) > 0) {
|
||||
size += write(d, buffer, n);
|
||||
}
|
||||
len -= clen;
|
||||
}
|
||||
while (len > 0 && n == BUFSIZ);
|
||||
|
||||
close(d);
|
||||
} else {
|
||||
saved_errno = errno;
|
||||
}
|
||||
|
||||
close(s);
|
||||
} else {
|
||||
saved_errno = errno;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
if (isdir)
|
||||
free(dst);
|
||||
errno = saved_errno;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* movefile - Move a file to another location
|
||||
* @src: Source file.
|
||||
* @dst: Target file, or location.
|
||||
*
|
||||
* This is a C implementation of the command line mv(1) utility.
|
||||
* Usually the rename() API is sufficient, but not when moving across
|
||||
* file system boundaries.
|
||||
*
|
||||
* The @src argument must include the full path to the source file,
|
||||
* whereas the @dst argument may only be a directory, in which case the
|
||||
* same file name from @src is used.
|
||||
*
|
||||
* Returns:
|
||||
* POSIX OK(0), or non-zero with errno set.
|
||||
*/
|
||||
int movefile(char *src, char *dst)
|
||||
{
|
||||
int isdir, result = 0;
|
||||
|
||||
/* Check if target is a directory, then append the src base filename. */
|
||||
isdir = __isdir_and_append_filename(src, &dst);
|
||||
|
||||
if (rename(src, dst)) {
|
||||
if (errno == EXDEV) {
|
||||
errno = 0;
|
||||
copyfile(src, dst, 0);
|
||||
if (errno)
|
||||
result = 1;
|
||||
else
|
||||
result = remove(src);
|
||||
} else {
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (isdir)
|
||||
free(dst);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* copy_filep - Copy between FILE *fp.
|
||||
* @src: Source FILE.
|
||||
* @dst: Destination FILE.
|
||||
*
|
||||
* Function takes signals into account and will restart the syscalls as long
|
||||
* as error is %EINTR.
|
||||
*
|
||||
* Returns:
|
||||
* POSIX OK(0), or non-zero with errno set on error.
|
||||
*/
|
||||
int copy_filep(FILE *src, FILE *dst)
|
||||
{
|
||||
int result = 0;
|
||||
char *buf = (char *)malloc(BUFSIZ);
|
||||
|
||||
if (!src || !dst)
|
||||
return EINVAL;
|
||||
|
||||
if (!buf)
|
||||
return errno;
|
||||
|
||||
while (1) {
|
||||
if (!fgets(buf, BUFSIZ, src)) {
|
||||
if (errno == EINTR) {
|
||||
clearerr(src);
|
||||
continue;
|
||||
}
|
||||
if (feof(src))
|
||||
break;
|
||||
|
||||
result = errno;
|
||||
goto exit;
|
||||
}
|
||||
while (EOF == fputs(buf, dst)) {
|
||||
if (errno == EINTR) {
|
||||
clearerr(dst);
|
||||
continue;
|
||||
}
|
||||
|
||||
result = errno;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
free(buf);
|
||||
return errno = result;
|
||||
}
|
||||
|
||||
/* Tests if dst is a directory, if so, reallocates dst and appends src filename returning 1 */
|
||||
static int __isdir_and_append_filename(char *src, char **dst)
|
||||
{
|
||||
int isdir = 0;
|
||||
|
||||
if (fisdir(*dst)) {
|
||||
int slash = 0;
|
||||
char *tmp, *ptr = strrchr(src, '/');
|
||||
|
||||
if (!ptr)
|
||||
ptr = src;
|
||||
else
|
||||
ptr++;
|
||||
|
||||
// fprintf (stderr, "Yes %s is a dir --> add %s\n", *dst, ptr);
|
||||
tmp = malloc(strlen(*dst) + strlen(ptr) + 2);
|
||||
if (!tmp) {
|
||||
errno = EISDIR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
isdir = 1; /* Free dst before exit! */
|
||||
slash = fisslashdir(*dst);
|
||||
|
||||
sprintf(tmp, "%s%s%s", *dst, slash ? "" : "/", ptr);
|
||||
*dst = tmp;
|
||||
// fprintf (stderr, "NEW DST:%s\n", *dst);
|
||||
}
|
||||
|
||||
return isdir;
|
||||
}
|
||||
|
||||
#ifdef UNITTEST
|
||||
#include <stdio.h>
|
||||
/* XXX: Make a real set of unit tests ... */
|
||||
#if 0
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 3) {
|
||||
fprintf(stderr,
|
||||
"Usage: %s <src> <dst>\nCopies the <src> file to the <dst> file.\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Copying file %s to %s\n", argv[1], argv[2]);
|
||||
|
||||
return copyfile(argv[1], argv[2], 0);
|
||||
}
|
||||
#else
|
||||
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;
|
||||
|
||||
fprintf(stderr, "\n=>Start testing copy_filep()\n");
|
||||
while (files[i]) {
|
||||
fprintf(stderr, "copy_filep(%s, %s)\t", files[i],
|
||||
files[i + 1]);
|
||||
src = fopen(files[i], "r");
|
||||
dst = fopen(files[i + 1], "w");
|
||||
if (copy_filep(src, dst))
|
||||
perror("Failed");
|
||||
|
||||
if (src)
|
||||
fclose(src);
|
||||
if (dst)
|
||||
fclose(dst);
|
||||
|
||||
if (fexist(files[i + 2]))
|
||||
fprintf(stderr, "OK => %s\n", files[i + 2]);
|
||||
|
||||
remove(files[i + 2]);
|
||||
i += 3;
|
||||
}
|
||||
|
||||
printf("\n\n=>Start testing copyfile()\n");
|
||||
i = 0;
|
||||
while (files[i]) {
|
||||
fprintf(stderr, "copyfile(%s, %s)\t", files[i], files[i + 1]);
|
||||
if (!copyfile(files[i], files[i + 1], 0))
|
||||
perror("Failed");
|
||||
|
||||
if (fexist(files[i + 2]))
|
||||
fprintf(stderr, "OK => %s\n", files[i + 2]);
|
||||
|
||||
remove(files[i + 2]);
|
||||
i += 3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif /* UNITTEST */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* compile-command: "gcc -g -I../include -o unittest -DUNITTEST copyfile.c && ./unittest"
|
||||
* version-control: t
|
||||
* kept-new-versions: 2
|
||||
* c-file-style: "ellemtel"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,228 @@
|
||||
/* Functions for operating on files in directories.
|
||||
*
|
||||
* Copyright (c) 2008-2012 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 <assert.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, '.');
|
||||
|
||||
if (matcher_filter && !matcher_filter(entry->d_name))
|
||||
/* User matcher overrides the rest. */
|
||||
return 0;
|
||||
|
||||
/* Skip current dir "." from list of files. */
|
||||
if ((1 == strlen(entry->d_name) && entry->d_name[0] == '.') ||
|
||||
(2 == strlen(entry->d_name) && !strcmp(entry->d_name, "..")))
|
||||
return 0;
|
||||
|
||||
/* filetype == "" */
|
||||
if (matcher_type[0] == 0)
|
||||
return 1;
|
||||
|
||||
/* Entry has no "." */
|
||||
if (!pos)
|
||||
return 0;
|
||||
|
||||
return !strcmp(pos, matcher_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* dir - List all files of a certain type in the given directory.
|
||||
* @dir: Base directory for dir operation.
|
||||
* @type: File type suffix, e.g. ".cfg".
|
||||
* @filter: Optional file name filter.
|
||||
* @list: Pointer to an array of file names.
|
||||
* @strip: Flag, if set dir() strips the file type.
|
||||
*
|
||||
* This function returns a @list of files, matching the @type suffix,
|
||||
* in the given directory @dir.
|
||||
*
|
||||
* The @list argument is a pointer to where to store the dynamically
|
||||
* allocated list of file names. This list should be free'd by first
|
||||
* calling free() on each file name and then on the list itself.
|
||||
*
|
||||
* If @filter is not %NULL it will be called for each file found. If
|
||||
* @filter returns non-zero the @file argument will be included in the
|
||||
* resulting @list. If @filter returns zero for given @file it will
|
||||
* be discarded.
|
||||
*
|
||||
* If the @strip flag is set the resulting @list of files has their
|
||||
* file type stripped, including the dot. So a match "config0.cfg"
|
||||
* would be returned as "config0".
|
||||
*
|
||||
* Returns:
|
||||
* Number of files in @list, zero if no matching files of @type.
|
||||
*/
|
||||
int dir(const char *dir, const char *type, int (*filter) (const char *file), char ***list, int strip)
|
||||
{
|
||||
int i, n, num = 0;
|
||||
char **files;
|
||||
struct dirent **namelist;
|
||||
|
||||
assert(list);
|
||||
|
||||
if (!dir)
|
||||
/* Assuming current directory */
|
||||
dir = ".";
|
||||
if (!type)
|
||||
/* Assuming all files. */
|
||||
type = "";
|
||||
|
||||
matcher_type = type;
|
||||
matcher_filter = filter;
|
||||
n = scandir(dir, &namelist, matcher, alphasort);
|
||||
if (n < 0) {
|
||||
perror("scandir");
|
||||
} else {
|
||||
files = (char **)malloc(n * sizeof(char *));
|
||||
for (i = 0; i < n; i++) {
|
||||
if (files) {
|
||||
char *name = namelist[i]->d_name;
|
||||
char *type = strrchr(name, '.');
|
||||
|
||||
if (type && strip)
|
||||
*type = 0;
|
||||
|
||||
files[i] = strdup(name);
|
||||
num++;
|
||||
}
|
||||
free(namelist[i]);
|
||||
}
|
||||
free(namelist);
|
||||
}
|
||||
|
||||
if (num)
|
||||
*list = files;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
#ifdef UNITTEST
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include "otn/c.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 < ARRAY_ELEMENTS(files); i++) {
|
||||
if (creat)
|
||||
touch(files[i]);
|
||||
else
|
||||
remove(files[i]);
|
||||
}
|
||||
|
||||
if (creat)
|
||||
symlink("config2.cfg", STARTUP_CONFIG);
|
||||
else
|
||||
remove(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: "gcc -g -DUNITTEST -o unittest dir.c"
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,53 @@
|
||||
/* Check if file exists
|
||||
*
|
||||
* Copyright (c) 2008 Claudio Matsuoka <http://helllabs.org/finit/>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/**
|
||||
* fexist - Check if a file exists in the file system.
|
||||
* @file: File to look for, with full path.
|
||||
*
|
||||
* Returns:
|
||||
* %TRUE(1) if the file exists, otherwise %FALSE(0).
|
||||
*/
|
||||
int fexist(char *file)
|
||||
{
|
||||
if (!file) {
|
||||
errno = EINVAL;
|
||||
return 0; /* Doesn't exist ... */
|
||||
}
|
||||
|
||||
if (-1 == access(file, F_OK))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,51 @@
|
||||
/* Check if directory exists
|
||||
*
|
||||
* Copyright (c) 2008 Claudio Matsuoka <http://helllabs.org/finit/>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/**
|
||||
* fexist - Check if a file exists and is a directory.
|
||||
* @file: File to look for, with full path.
|
||||
*
|
||||
* Returns:
|
||||
* %TRUE(1) if the file exists and is a directory, otherwise %FALSE(0).
|
||||
*/
|
||||
int fisdir(char *file)
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
if (!stat(file, &sb) && S_ISDIR(sb.st_mode))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,57 @@
|
||||
/* File mode bit operations
|
||||
*
|
||||
* Copyright (c) 2008 Claudio Matsuoka <http://helllabs.org/finit/>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/**
|
||||
* fmode - Return a file's mode bits.
|
||||
* @file: File to look for, with full path.
|
||||
*
|
||||
* Returns:
|
||||
* The mode bits or zero when @file does not exist and errno set to %ENOENT.
|
||||
*/
|
||||
mode_t fmode(char *file)
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
if (!file) {
|
||||
errno = EINVAL;
|
||||
return 0; /* Doesn't exist ... */
|
||||
}
|
||||
|
||||
if (!stat(file, &sb))
|
||||
return sb.st_mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,61 @@
|
||||
/* Collection of utility funcs and C library extensions for finit & its plugins
|
||||
*
|
||||
* Copyright (c) 2008-2010 Claudio Matsuoka <cmatsuoka@gmail.com>
|
||||
* Copyright (c) 2008-2012 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 FINIT_LITE_H_
|
||||
#define FINIT_LITE_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int fexist (char *file);
|
||||
int fisdir (char *file);
|
||||
mode_t fmode (char *file);
|
||||
|
||||
ssize_t copyfile (char *src, char *dst, int len);
|
||||
int movefile (char *src, char *dst);
|
||||
int copy_filep (FILE *src, FILE *dst);
|
||||
|
||||
int dir (const char *dir, const char *type, int (*filter) (const char *file), char ***list, int strip);
|
||||
int rsync (char *src, char *dst, int delete, int (*filter) (const char *file));
|
||||
|
||||
static inline int fisslashdir(char *dir)
|
||||
{
|
||||
if (!dir) return 0;
|
||||
if (strlen (dir) > 0) return dir[strlen (dir) - 1] == '/';
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* FINIT_LITE_H_ */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,280 @@
|
||||
/* Micro "rsync" implementation.
|
||||
*
|
||||
* Copyright (c) 2011, 2012 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 <stdlib.h> /* NULL, free() */
|
||||
#include <string.h> /* strlen() */
|
||||
#include <strings.h> /* rindex() */
|
||||
#include <stdio.h>
|
||||
#include <sys/param.h> /* MAX(), isset(), setbit(), TRUE, FALSE, et consortes. :-) */
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "lite.h"
|
||||
#include "../helpers.h"
|
||||
|
||||
static int makedir(char *buf, size_t buf_len, char *dir, char *name, mode_t mode);
|
||||
static int prune(char *dst, char **new_files, int new_num);
|
||||
|
||||
|
||||
/**
|
||||
* rsync - Synchronize contents and optionally remove non-existing backups
|
||||
* @src: Source directory
|
||||
* @dst: Destination directory
|
||||
* @delete: Prune files from @dst that no longer exist in @src.
|
||||
* @filter: Optional filtering function for source directory.
|
||||
*
|
||||
* This is a miniature implementation of the famous rsync for local use only.
|
||||
* In fact, it is not even a true rsync since it copies all files from @src
|
||||
* to @dst. The @delete option is useful for creating backups, when set all
|
||||
* files removed from src since last backup are pruned from the destination
|
||||
* (backup) directory.
|
||||
*
|
||||
* The filter callback, @filter, if provided, is used to determine what files to
|
||||
* include from the source directory when backing up. If a file is to be skipped
|
||||
* the callback should simply return zero.
|
||||
*
|
||||
* Returns:
|
||||
* POSIX OK(0), or non-zero with @errno set on error.
|
||||
*/
|
||||
int rsync(char *src, char *dst, int delete, int (*filter) (const char *file))
|
||||
{
|
||||
char source[256];
|
||||
char dest[256];
|
||||
int i = 0, num = 0, result = 0;
|
||||
char **files; /* Array of file names. */
|
||||
|
||||
void copy(char *src, char *dst)
|
||||
{
|
||||
errno = 0;
|
||||
copyfile(src, dst, 0);
|
||||
if (errno) result++;
|
||||
}
|
||||
|
||||
if (!fisdir(dst))
|
||||
mkdir(dst, 0755);
|
||||
|
||||
if (!fisdir(src)) {
|
||||
if (!fexist(src))
|
||||
return 1;
|
||||
|
||||
copy(src, dst);
|
||||
return errno;
|
||||
}
|
||||
|
||||
/* Copy dir as well? */
|
||||
if (!fisslashdir(src)) {
|
||||
char *ptr = rindex(src, '/');
|
||||
|
||||
if (!ptr)
|
||||
ptr = src;
|
||||
else
|
||||
ptr++;
|
||||
|
||||
if (makedir(dest, sizeof(dest), dst, ptr, fmode(src)))
|
||||
return 1;
|
||||
dst = dest;
|
||||
}
|
||||
|
||||
num = dir(src, "", filter, &files, 0);
|
||||
for (i = 0; i < num; i++) {
|
||||
/* Recursively copy sub-directries */
|
||||
snprintf(source, sizeof(source), "%s%s%s", src, fisslashdir(src) ? "" : "/", files[i]);
|
||||
if (fisdir(source)) {
|
||||
char dst2[256];
|
||||
|
||||
strcat(source, "/");
|
||||
if (makedir (dst2, sizeof(dst2), dst, files[i], fmode(source))) {
|
||||
result++;
|
||||
continue;
|
||||
}
|
||||
|
||||
rsync(source, dst2, delete, filter);
|
||||
continue; /* Next file/dir in @src to copy... */
|
||||
}
|
||||
copy(source, dst);
|
||||
}
|
||||
|
||||
/* We ignore any errors from the pruning, that phase albeit useful is only
|
||||
* cosmetic. --Jocke 2011-03-24 */
|
||||
if (delete)
|
||||
prune(dst, files, num);
|
||||
|
||||
if (num) {
|
||||
for (i = 0; i < num; i++)
|
||||
free(files[i]);
|
||||
free(files);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Creates dir/name @mode ... skipping / if dir already ends so. */
|
||||
static int makedir(char *buf, size_t buf_len, char *dir, char *name, mode_t mode)
|
||||
{
|
||||
snprintf(buf, buf_len, "%s%s%s/", dir, fisslashdir(dir) ? "" : "/", name);
|
||||
if (mkdir(buf, mode))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Prune old files, no longer existing on source, from destination directory. */
|
||||
static int prune(char *dst, char **new_files, int new_num)
|
||||
{
|
||||
int i, num, result = 0;
|
||||
char **files;
|
||||
|
||||
int find(char *file) {
|
||||
int n;
|
||||
|
||||
for (n = 0; n < new_num; n++)
|
||||
if (!strncmp (new_files[n], file, MAX(strlen(new_files[n]), strlen(file))))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
num = dir(dst, "", NULL, &files, 0);
|
||||
if (num) {
|
||||
for (i = 0; i < num; i++) {
|
||||
if (!find(files[i])) {
|
||||
char *name;
|
||||
size_t len = strlen(files[i]) + 2 + strlen(dst);
|
||||
|
||||
name = malloc(len);
|
||||
if (name) {
|
||||
snprintf(name, len, "%s%s%s", dst, fisslashdir(dst) ? "" : "/", files[i]);
|
||||
if (remove(name))
|
||||
result++;
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
free(files[i]);
|
||||
}
|
||||
free(files);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef UNITTEST
|
||||
#define BASE "/tmp/.unittest/"
|
||||
#define SRC BASE "src/"
|
||||
#define DST BASE "dst/"
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
int run_test()
|
||||
{
|
||||
#if 0
|
||||
setup_test();
|
||||
puts("Before:");
|
||||
system("tree -np " BASE);
|
||||
|
||||
rsync(SRC, DST, 0, NULL);
|
||||
puts("After:");
|
||||
system("tree -np " BASE);
|
||||
cleanup_test();
|
||||
#endif
|
||||
|
||||
setup_test();
|
||||
rsync(BASE "src", DST, 0, NULL);
|
||||
puts("Only partial rsync of src <-- No slash!");
|
||||
system("tree -np " BASE);
|
||||
#if 0
|
||||
cleanup_test();
|
||||
setup_test();
|
||||
rsync(BASE "src/sub1", BASE "dst", 0, NULL);
|
||||
puts("Only partial rsync of src/sub1 <-- No slashes!!");
|
||||
system("tree -np " BASE);
|
||||
|
||||
cleanup_test();
|
||||
setup_test();
|
||||
rsync(BASE "src/sub1/", DST, 0, NULL);
|
||||
puts("Only partial rsync of src/sub1/");
|
||||
system("tree -np " BASE);
|
||||
|
||||
cleanup_test();
|
||||
setup_test();
|
||||
rsync(BASE "src/sub1", DST, 0, NULL);
|
||||
puts("Only partial rsync of src/sub1 <-- No slash!");
|
||||
system("tree -np " BASE);
|
||||
|
||||
rsync("/etc", "/var/tmp", 0, NULL);
|
||||
puts("Real life test:");
|
||||
system("tree -np /var/tmp");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
atexit(cleanup_test);
|
||||
|
||||
return run_test();
|
||||
}
|
||||
#endif /* UNITTEST */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* compile-command: "make -f rsync.mk"
|
||||
* version-control: t
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,22 @@
|
||||
# Unittest makefile for rsync.c
|
||||
.PHONY: clean
|
||||
|
||||
SRC = rsync.c
|
||||
OBJS = dir.o copyfile.o fexist.o fisdir.o fmode.o
|
||||
UNIT = rsync.unittest
|
||||
#CPPFLAGS = -DDEBUG -I../../.. -I../../include
|
||||
|
||||
all: build run
|
||||
|
||||
clean:
|
||||
@rm -f $(OBJS) $(UNIT)
|
||||
|
||||
# This rule also forces a cleanup of built objects to not leave any object files
|
||||
# lingering in the tree to interfere with cross builds.
|
||||
build: clean $(OBJS)
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -o $(UNIT) -DUNITTEST $(SRC) $(OBJS)
|
||||
@rm -f $(OBJS)
|
||||
|
||||
run:
|
||||
@./$(UNIT)
|
||||
|
||||
Reference in new issue
Block a user