[cowdancer] 01/01: Unify logging and add colors

James Clarke jrtc27-guest at moszumanska.debian.org
Wed Aug 3 00:57:57 UTC 2016


This is an automated email from the git hooks/post-receive script.

jrtc27-guest pushed a commit to branch wip-colors
in repository cowdancer.

commit f91fd3dfd22ef1ed1e6dc3f745c75488bc455b1a
Author: James Clarke <jrtc27 at jrtc27.com>
Date:   Wed Aug 3 01:55:01 2016 +0100

    Unify logging and add colors
---
 Makefile               |  16 ++--
 cow-shell.c            |  15 ++--
 cowbuilder.8           |  38 ++++-----
 cowbuilder.c           | 116 ++++++++++++-------------
 cowbuilder_util.c      |   6 +-
 cowdancer-ilistdump.c  |   7 +-
 cowdancer.c            |  65 +++++++-------
 debian/control         |   1 +
 file.c                 |  45 +++++-----
 forkexec.c             |  35 ++++----
 ilistcreate.c          |   3 +-
 log.c                  | 224 +++++++++++++++++++++++++++++++++++++++++++++++++
 log.h                  |  67 +++++++++++++++
 parameter.c            | 110 ++++++++++++++++++------
 parameter.h            |   5 +-
 qemuarch.c             |   2 +-
 qemubuilder.c          | 203 ++++++++++++++++++++++----------------------
 qemuipsanitize.c       |   5 +-
 test_cowbuilder.c      |   2 +-
 test_cowbuilder_util.c |   2 +-
 test_file.c            |   2 +-
 test_forkexec.c        |   2 +-
 test_ilistcreate.c     |   2 +-
 test_parameter.c       |   2 +-
 test_qemuarch.c        |   2 +-
 test_qemuipsanitize.c  |   2 +-
 26 files changed, 673 insertions(+), 306 deletions(-)

diff --git a/Makefile b/Makefile
index c6c59ee..aebc2f8 100644
--- a/Makefile
+++ b/Makefile
@@ -14,6 +14,7 @@ LIBDIR=$(PREFIX)/lib
 CFLAGS := $(CFLAGS) -fno-strict-aliasing
 CFLAGS_LFS=$(CFLAGS) $(shell getconf LFS_CFLAGS)
 PWD=$(shell pwd)
+LDFLAGS += -lncurses
 
 export VERSION=$(shell sed -n '1s/.*(\(.*\)).*$$/\1/p' < debian/changelog )
 
@@ -47,19 +48,22 @@ ifeq ($(DEB_BUILD_ARCH_OS),linux)
 endif
 	$(INSTALL_FILE) bash_completion.cowbuilder $(DESTDIR)/usr/share/bash-completion/completions/cowbuilder
 
-libcowdancer.so: cowdancer.lo ilistcreate.lo
+libcowdancer.so: cowdancer.lo ilistcreate.lo log.lo
 	$(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -ldl
 
-cow-shell: cow-shell.o ilistcreate.o
+cow-shell: cow-shell.o ilistcreate.o log.o
 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
 
-cowdancer-ilistcreate: cowdancer-ilistcreate.o ilistcreate.o
+cowdancer-ilistcreate: cowdancer-ilistcreate.o ilistcreate.o log.o
 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
 
-cowbuilder: cowbuilder.o parameter.o forkexec.o ilistcreate.o main.o cowbuilder_util.o
+cowdancer-ilistdump: cowdancer-ilistdump.o log.o
 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
 
-qemubuilder: qemubuilder.lfso parameter.lfso forkexec.lfso qemuipsanitize.lfso qemuarch.lfso file.lfso main.lfso
+cowbuilder: cowbuilder.o parameter.o forkexec.o ilistcreate.o main.o cowbuilder_util.o log.o
+	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
+
+qemubuilder: qemubuilder.lfso parameter.lfso forkexec.lfso qemuipsanitize.lfso qemuarch.lfso file.lfso main.lfso log.lfso
 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
 
 %.lo: %.c
@@ -71,7 +75,7 @@ qemubuilder: qemubuilder.lfso parameter.lfso forkexec.lfso qemuipsanitize.lfso q
 %.o: %.c parameter.h
 	$(CC) $(CFLAGS) $< -o $@ -c -D LIBDIR="\"${LIBDIR}\""
 
-clean: 
+clean:
 	-rm -f *~ *.o *.lo *.lfso $(BINARY)
 	-make -C initrd clean
 
diff --git a/cow-shell.c b/cow-shell.c
index 090a2e5..853befb 100755
--- a/cow-shell.c
+++ b/cow-shell.c
@@ -15,6 +15,7 @@
 #include <string.h>
 #include <sys/wait.h>
 #include "ilist.h"
+#include "log.h"
 
 const char* ilist_PRGNAME="cow-shell";
 
@@ -32,7 +33,7 @@ static void ilist_deleter(const char* ilistfile)
       pid_t parent_pid=getppid();
       if (daemon(0,1) < 0)
 	{
-	  perror("cow-shell daemon");
+	  log_perror("cow-shell daemon");
 	  exit (-1);
 	}
       while (kill(parent_pid,0) >= 0)
@@ -41,7 +42,7 @@ static void ilist_deleter(const char* ilistfile)
 	}
       if (unlink(ilistfile)==-1)
 	{
-	  perror("cow-shell unlink .ilist");
+	  log_perror("cow-shell unlink .ilist");
 	  exit(1);
 	}
       exit(0);
@@ -94,7 +95,7 @@ int main(int ac, char** av)
 	    }
 	  else
 	    {
-	      perror("cow-shell: unlink of .ilist failed");
+	      log_perror("cow-shell: unlink of .ilist failed");
 	      return 1;
 	    }
 	}
@@ -118,18 +119,18 @@ int main(int ac, char** av)
   else
     {
       const char* myshell=getenv("SHELL")?:"/bin/sh";
-      fprintf(stderr, "Invoking %s\n", myshell);
+      log_printf(log_info, "Invoking %s", myshell);
 
       execlp(myshell,
 	     myshell,
 	     NULL);
-      perror("cow-shell: exec");
+      log_perror("cow-shell: exec");
 
-      fprintf(stderr, "Falling back to /bin/sh\n");
+      log_printf(log_warn, "Falling back to /bin/sh");
       execlp("/bin/sh",
 	     "/bin/sh",
 	     NULL);
     }
-  perror("cow-shell: exec");
+  log_perror("cow-shell: exec");
   return 1;
 }
diff --git a/cowbuilder.8 b/cowbuilder.8
index 4146ee0..99561b5 100644
--- a/cowbuilder.8
+++ b/cowbuilder.8
@@ -141,10 +141,10 @@ Create a base.cow image.
 # cowbuilder --create --hookdir /usr/share/doc/pbuilder/examples/workaround/ --distribution etch --debootstrap debootstrap --basepath /var/cache/pbuilder/base-test.cow
 bash: /root/.pbuilderrc: No such file or directory
 W: /home/dancer/.pbuilderrc does not exist
- -> Running in no-targz mode
+I: Running in no-targz mode
 Distribution is etch.
 Building the build environment
- -> running debootstrap
+I: running debootstrap
 /usr/sbin/debootstrap
 I: Retrieving Release
 	.
@@ -158,16 +158,16 @@ Update the base.cow image.
 .nf
 # cowbuilder --update
 bash: /root/.pbuilderrc: No such file or directory
- -> Copying COW directory
- -> Invoking pbuilder
+I: Copying COW directory
+I: Invoking pbuilder
 W: /home/dancer/.pbuilderrc does not exist
- -> Running in no-targz mode
- -> copying local configuration
- -> mounting /proc filesystem
- -> mounting /dev/pts filesystem
- -> policy-rc.d already exists
+I: Running in no-targz mode
+I: copying local configuration
+I: mounting /proc filesystem
+I: mounting /dev/pts filesystem
+I: policy-rc.d already exists
 Refreshing the base.tgz
- -> upgrading packages
+I: upgrading packages
 	.
 	.
 .hy
@@ -202,16 +202,16 @@ Note that cowbuilder will not cow-protect what is inside
 .nf
 # cowbuilder --login --bindmount ${HOME}
 bash: /root/.pbuilderrc: No such file or directory
- -> Copying COW directory
- -> Invoking pbuilder
+I: Copying COW directory
+I: Invoking pbuilder
 W: /home/dancer/.pbuilderrc does not exist
- -> Running in no-targz mode
- -> copying local configuration
- -> mounting /proc filesystem
- -> mounting /dev/pts filesystem
--> Mounting /home/dancer
- -> policy-rc.d already exists
- -> entering the shell
+I: Running in no-targz mode
+I: copying local configuration
+I: mounting /proc filesystem
+I: mounting /dev/pts filesystem
+I: Mounting /home/dancer
+I: policy-rc.d already exists
+I: entering the shell
 #
 .hy
 
diff --git a/cowbuilder.c b/cowbuilder.c
index 4581fd8..0ae0a76 100755
--- a/cowbuilder.c
+++ b/cowbuilder.c
@@ -98,7 +98,7 @@ static char* get_ilistfile_path(const struct pbuilderconfig* pc)
   if (0>asprintf(&ilistfile, "%s/.ilist", pc->buildplace))
     {
       /* outofmemory */
-      fprintf(stderr, "cowdancer: out of memory.\n");
+      log_printf(log_error, "cowdancer: out of memory.");
       return NULL;
     }
   return ilistfile;
@@ -136,7 +136,7 @@ int break_cowlink(const char* s)
 	  /* child process, run cp */
 	  putenv("COWDANCER_IGNORE=yes");
 	  execl("/bin/cp", "/bin/cp", "-a", s, backup_file, NULL);
-	  perror("execl:cp:");
+	  log_perror("execl:cp:");
 	  exit(EXIT_FAILURE);
 	case -1:
 	  /* error condition in fork(); something is really wrong */
@@ -146,8 +146,8 @@ int break_cowlink(const char* s)
 	  /* parent process, waiting for cp -a to terminate */
 	  if(-1==waitpid(pid, &status, 0))
 	    {
-	      perror("waitpid:cp");
-	      fprintf(stderr, "%s: unexpected waitpid error when waiting for process %i with status %x\n",
+	      log_perror("waitpid:cp");
+	      log_printf(log_error, "%s: unexpected waitpid error when waiting for process %i with status %x",
 		      ilist_PRGNAME, pid, status);
 	      goto error_spm;
 	    }
@@ -155,21 +155,21 @@ int break_cowlink(const char* s)
 	  if (!WIFEXITED(status))
 	    {
 	      /* something unexpected */
-	      fprintf(stderr, "%s: unexpected WIFEXITED status in waitpid: %x\n", ilist_PRGNAME,
+	      log_printf(log_error, "%s: unexpected WIFEXITED status in waitpid: %x", ilist_PRGNAME,
 		      (int)status);
 	      goto error_spm;
 	    }
 	  else if (WEXITSTATUS(status))
 	    {
 	      /* cp -a failed */
-	      fprintf(stderr, "%s: cp -a failed for %s\n", ilist_PRGNAME, backup_file);
+	      log_printf(log_error, "%s: cp -a failed for %s", ilist_PRGNAME, backup_file);
 	      goto error_spm;
 	    }
 	  /* when cp -a succeeded, overwrite the target file from the temporary file with rename */
 	  else if (-1==rename(backup_file, s))
 	    {
-	      perror ("file overwrite with rename");
-	      fprintf(stderr, "while trying rename of %s to %s\n",  backup_file, s);
+	      log_perror("file overwrite with rename");
+	      log_printf(log_error, "while trying rename of %s to %s",  backup_file, s);
 	      goto error_spm;
 	    }
 	}
@@ -202,7 +202,7 @@ static int cpbuilder_internal_cowcopy(const struct pbuilderconfig* pc)
 {
   char *ilistfile;
 
-  printf(" -> Copying COW directory\n");
+  log_printf(log_info, "Copying COW directory");
   if (0!=rmrf_check_mount(pc->buildplace))
     return 1;
   if (0!=forkexeclp("cp", "cp", "-al", pc->basepath, pc->buildplace, NULL))
@@ -213,7 +213,7 @@ static int cpbuilder_internal_cowcopy(const struct pbuilderconfig* pc)
   if(!(ilistfile=get_ilistfile_path(pc)))
     {
       /* outofmemory */
-      fprintf(stderr, "cowdancer: out of memory.\n");
+      log_printf(log_error, "cowdancer: out of memory.");
       return 1;
     }
   if (unlink(ilistfile))
@@ -221,11 +221,11 @@ static int cpbuilder_internal_cowcopy(const struct pbuilderconfig* pc)
       /* if there was no ilist file in the beginning, that's not a
 	 problem.
        */
-      printf("I: unlink for ilistfile %s failed, it didn't exist?\n", ilistfile);
+      log_printf(log_info, "unlink for ilistfile %s failed, it didn't exist?", ilistfile);
     }
   else
     {
-      printf("I: removed stale ilistfile %s\n", ilistfile);
+      log_printf(log_info, "removed stale ilistfile %s", ilistfile);
     }
   free(ilistfile);
 
@@ -243,7 +243,7 @@ static int cpbuilder_internal_cowcopy(const struct pbuilderconfig* pc)
  */
 static int cpbuilder_internal_cleancow(const struct pbuilderconfig* pc)
 {
-  printf(" -> Cleaning COW directory\n");
+  log_printf(log_info, "Cleaning COW directory");
 
   if (!pc->debug && 0!=rmrf_check_mount(pc->buildplace))
     return 1;
@@ -263,13 +263,13 @@ int cpbuilder_build(const struct pbuilderconfig* pc, const char* dscfile_)
 
   if (!dscfile)
     {
-      fprintf(stderr, "File not found: %s\n", dscfile_);
+      log_printf(log_error, "File not found: %s", dscfile_);
       return 1;
     }
 
   if (cpbuilder_internal_cowcopy(pc))
     {
-      fprintf(stderr, "Failed cowcopy.\n");
+      log_printf(log_error, "Failed cowcopy.");
       return 1;
     }
 
@@ -277,14 +277,14 @@ int cpbuilder_build(const struct pbuilderconfig* pc, const char* dscfile_)
   if (0>asprintf(&buf_chroot, "chroot %s cow-shell", pc->buildplace))
     {
       /* outofmemory */
-      fprintf(stderr, "cowdancer: out of memory.\n");
+      log_printf(log_error, "cowdancer: out of memory.");
       return -1;
     }
 
   if(!(ilistfile=get_ilistfile_path(pc)))
     {
       /* outofmemory */
-      fprintf(stderr, "cowdancer: out of memory.\n");
+      log_printf(log_error, "cowdancer: out of memory.");
       return 1;
     }
 
@@ -304,7 +304,7 @@ int cpbuilder_build(const struct pbuilderconfig* pc, const char* dscfile_)
       /* but first, try etch-workaround */
       if (pc->debian_etch_workaround)
 	{
-	  fprintf(stderr, "W: Trying my backup method for working with Debian Etch chroots.\n");
+	  log_printf(log_warn, "Trying my backup method for working with Debian Etch chroots.");
 	  if (forkexeclp("chroot",
 			 "chroot",
 			 pc->buildplace,
@@ -313,7 +313,7 @@ int cpbuilder_build(const struct pbuilderconfig* pc, const char* dscfile_)
 			 NULL))
 	    {
 	      /* I failed, what can I do? noooo */
-	      fprintf(stderr, "E: failed running Debian Etch compatibility backup plan, I'm in panic, eek.\n");
+	      log_printf(log_error, "failed running Debian Etch compatibility backup plan, I'm in panic, eek.");
 	      return 1;
 	    }
 	}
@@ -324,7 +324,7 @@ int cpbuilder_build(const struct pbuilderconfig* pc, const char* dscfile_)
 
 	     It probably doesn't work but try it anyway.
 	   */
-	  fprintf(stderr, "W: cowdancer-ilistcreate failed to run within chroot, falling back to old method\n");
+	  log_printf(log_warn, "cowdancer-ilistcreate failed to run within chroot, falling back to old method");
 	  ilistcreate(ilistfile,
 		      "find . -xdev -path ./home -prune -o \\( \\( -type l -o -type f \\) -a -links +1 -print0 \\) | xargs -0 stat --format '%d %i '");
 	}
@@ -332,7 +332,7 @@ int cpbuilder_build(const struct pbuilderconfig* pc, const char* dscfile_)
   chdir(prevdir);
   free(prevdir);
 
-  printf(" -> Invoking pbuilder\n");
+  log_printf(log_info, "Invoking pbuilder");
   pbuildercommandline[1]="build";
   PBUILDER_ADD_PARAM("--buildplace");
   PBUILDER_ADD_PARAM(pc->buildplace);
@@ -364,7 +364,7 @@ int cpbuilder_build(const struct pbuilderconfig* pc, const char* dscfile_)
   if (ret < 128)
     cpbuilder_internal_cleancow(pc);
   else
-    printf("pbuilder build aborted, not cleaning\n");
+    log_printf(log_warn, "pbuilder build aborted, not cleaning");
 
   free(ilistfile);
   return ret;
@@ -375,7 +375,7 @@ int cpbuilder_create(const struct pbuilderconfig* pc)
   int ret;
 
   mkdir(pc->basepath,0777);
-  printf(" -> Invoking pbuilder\n");
+  log_printf(log_info, "Invoking pbuilder");
 
   pbuildercommandline[1]="create";
   PBUILDER_ADD_PARAM("--buildplace");
@@ -399,7 +399,7 @@ int cpbuilder_create(const struct pbuilderconfig* pc)
       char *extrapackages;
       if (0>asprintf(&extrapackages, "%s cowdancer", pc->extrapackages))
 	{
-	  fprintf(stderr, "cowdancer: out of memory.\n");
+	  log_printf(log_error, "cowdancer: out of memory.");
 	  ret = 1;
 	  goto out;
 	}
@@ -415,10 +415,10 @@ int cpbuilder_create(const struct pbuilderconfig* pc)
 out:
   if (ret)
     {
-      printf("pbuilder create failed\n");
+      log_printf(log_error, "pbuilder create failed");
       if (!pc->debug && 0!=rmrf_check_mount(pc->basepath))
 	{
-	  fprintf(stderr, "Could not remove original tree\n");
+	  log_printf(log_error, "Could not remove original tree");
 	}
     }
   return ret;
@@ -442,24 +442,24 @@ int cpbuilder_internal_saveupdate(const struct pbuilderconfig* pc)
       /* outofmemory */
       return -1;
     }
-  printf(" -> Moving work directory [%s] to final location [%s] and cleaning up old copy\n",
+  log_printf(log_info, "Moving work directory [%s] to final location [%s] and cleaning up old copy",
 	 pc->buildplace, pc->basepath);
 
   if(-1==rename(pc->basepath, buf_tmpfile))
     {
-      perror("rename");
+      log_perror("rename");
       ret=-1;
       goto out;
     }
   if(-1==rename(pc->buildplace, pc->basepath))
     {
-      perror("rename");
+      log_perror("rename");
       ret=-1;
       goto out;
     }
   if (0!=rmrf_check_mount(buf_tmpfile))
     {
-      printf("Could not remove original tree\n");
+      log_printf(log_error, "Could not remove original tree");
       ret=-1;
       goto out;
     }
@@ -476,7 +476,7 @@ int cpbuilder_login(const struct pbuilderconfig* pc)
 
   if (cpbuilder_internal_cowcopy(pc))
     {
-      fprintf(stderr, "Failed cowcopy.\n");
+      log_printf(log_error, "Failed cowcopy.");
       return 1;
     }
 
@@ -486,7 +486,7 @@ int cpbuilder_login(const struct pbuilderconfig* pc)
       /* outofmemory */
       return -1;
     }
-  printf(" -> Invoking pbuilder\n");
+  log_printf(log_info, "Invoking pbuilder");
   pbuildercommandline[1]="login";
   PBUILDER_ADD_PARAM("--buildplace");
   PBUILDER_ADD_PARAM(pc->buildplace);
@@ -511,7 +511,7 @@ int cpbuilder_login(const struct pbuilderconfig* pc)
 	}
     }
   else
-    printf("pbuilder login aborted, not cleaning\n");
+    log_printf(log_warn, "pbuilder login aborted, not cleaning");
 
   return ret;
 }
@@ -529,7 +529,7 @@ int cpbuilder_execute(const struct pbuilderconfig* pc, char** av)
 
   if (cpbuilder_internal_cowcopy(pc))
     {
-      fprintf(stderr, "Failed cowcopy.\n");
+      log_printf(log_error, "Failed cowcopy.");
       return 1;
     }
 
@@ -538,7 +538,7 @@ int cpbuilder_execute(const struct pbuilderconfig* pc, char** av)
       /* outofmemory */
       return -1;
     }
-  printf(" -> Invoking pbuilder\n");
+  log_printf(log_info, "Invoking pbuilder");
   pbuildercommandline[1]="execute";
   PBUILDER_ADD_PARAM("--buildplace");
   PBUILDER_ADD_PARAM(pc->buildplace);
@@ -570,7 +570,7 @@ int cpbuilder_execute(const struct pbuilderconfig* pc, char** av)
 	}
     }
   else
-    printf("pbuilder execute aborted, not cleaning\n");
+    log_printf(log_warn, "pbuilder execute aborted, not cleaning");
 
   return ret;
 }
@@ -629,17 +629,17 @@ int cpbuilder_update(const struct pbuilderconfig* pc)
 		 pc->buildplace))
     {
       /* if outofmemory, die. */
-      fprintf(stderr, "Out of memory.\n");
+      log_printf(log_error, "Out of memory.");
       return -1;
     }
 
   if (cpbuilder_internal_cowcopy(pc))
     {
-      fprintf(stderr, "Failed cowcopy.\n");
+      log_printf(log_error, "Failed cowcopy.");
       return 1;
     }
 
-  printf(" -> Invoking pbuilder\n");
+  log_printf(log_info, "Invoking pbuilder");
 
   pbuildercommandline[1]="update";
   PBUILDER_ADD_PARAM("--buildplace");
@@ -669,27 +669,27 @@ int cpbuilder_update(const struct pbuilderconfig* pc)
     {
       if (ret < 128)
 	{
-	  fprintf(stderr, "pbuilder update failed\n");
+	  log_printf(log_error, "pbuilder update failed");
 
 	  if (!pc->no_cowdancer_update)
 	    {
 	      /* advise the user to try this option first */
-	      fprintf(stderr, "E: could not update with cowdancer, try --no-cowdancer-update option\n");
+	      log_printf(log_error, "could not update with cowdancer, try --no-cowdancer-update option");
 	    }
 
 	  if (!pc->debug && 0!=rmrf_check_mount(pc->buildplace))
 	    {
-	      fprintf(stderr, "Could not remove original tree\n");
+	      log_printf(log_error, "Could not remove original tree");
 	    }
 	}
       else
-	printf("pbuilder update aborted, not cleaning\n");
+	log_printf(log_warn, "pbuilder update aborted, not cleaning");
 
       /* either way, I don't want to touch the original tree */
       goto out;
 
     }
-  printf(" -> removing %s working copy\n", ilist_PRGNAME);
+  log_printf(log_info, "removing %s working copy", ilist_PRGNAME);
   cpbuilder_internal_saveupdate(pc);
  out:
   free(buf_chroot);
@@ -698,20 +698,20 @@ int cpbuilder_update(const struct pbuilderconfig* pc)
 
 int cpbuilder_help(void)
 {
-  printf("%s [operation] [options]\n"
-	 "operation:\n"
-	 " --build\n"
-	 " --create\n"
-	 " --update\n"
-	 " --login\n"
-	 " --execute\n"
-	 " --help\n"
-	 " --dumpconfig\n"
-	 "options:\n"
-	 " --basepath:\n"
-	 " --buildplace:\n"
-	 " --distribution:\n"
-	 " ... and other pbuilder options \n", ilist_PRGNAME
+  printf("%s [operation] [options]"
+	 "operation:"
+	 " --build"
+	 " --create"
+	 " --update"
+	 " --login"
+	 " --execute"
+	 " --help"
+	 " --dumpconfig"
+	 "options:"
+	 " --basepath:"
+	 " --buildplace:"
+	 " --distribution:"
+	 " ... and other pbuilder options ", ilist_PRGNAME
 	 );
   return 0;
 }
diff --git a/cowbuilder_util.c b/cowbuilder_util.c
index 895a780..5f8c4a5 100644
--- a/cowbuilder_util.c
+++ b/cowbuilder_util.c
@@ -4,6 +4,7 @@
 #include <string.h>
 
 #include "cowbuilder_util.h"
+#include "log.h"
 
 /**
  * @return 0 if not mounted, 1 if something under the mountpoint is mounted.
@@ -20,8 +21,9 @@ int check_mountpoint(const char* mountpoint) {
             {
               if (strstr(part->mnt_dir, mountpoint) == part->mnt_dir)
                 {
-                  printf("E: Something (%s) is still mounted under %s; unmount and remove %s manually\n",
-			 part->mnt_dir, mountpoint, mountpoint);
+                  log_printf(log_error,
+                      "Something (%s) is still mounted under %s; unmount and remove %s manually",
+                      part->mnt_dir, mountpoint, mountpoint);
                   endmntent(mtab);
                   return 1;
                 }
diff --git a/cowdancer-ilistdump.c b/cowdancer-ilistdump.c
index d37e885..6b0499d 100755
--- a/cowdancer-ilistdump.c
+++ b/cowdancer-ilistdump.c
@@ -8,6 +8,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include "ilist.h"
+#include "log.h"
 
 const char* ilist_PRGNAME="cowdancer-ilistdump";
 
@@ -31,9 +32,9 @@ int main(int argc, char** argv)
   f=fopen (argv[1], "r");
   if (!f)
     {
-      fprintf (stderr,
-	       "%s: cannot open file %s\n",
-	       argv[0], argv[1]);
+      log_printf(log_error,
+	  "%s: cannot open file %s",
+	  argv[0], argv[1]);
       return 1;
     }
   
diff --git a/cowdancer.c b/cowdancer.c
index dd9fc1b..850e62b 100644
--- a/cowdancer.c
+++ b/cowdancer.c
@@ -19,6 +19,7 @@
 #include <sched.h>
 #include <errno.h>
 #include "ilist.h"
+#include "log.h"
 
 /* This is the type that mode_t has when passed as a vararg. If mode_t is
    smaller than int, then this will be int, but it could also potentially be
@@ -74,18 +75,18 @@ static int load_ilist(void)
 
   if (!getenv("COWDANCER_ILISTFILE"))
     {
-      fprintf(stderr, "env var COWDANCER_ILISTFILE not defined\n");
+      log_printf(log_error, "env var COWDANCER_ILISTFILE not defined");
       return 1;
     }
 
   if (-1==(fd=origlibc_open(getenv("COWDANCER_ILISTFILE"),O_RDONLY,0)))
     {
-      fprintf(stderr, "%s: cannot open ilistfile %s\n", ilist_PRGNAME, getenv("COWDANCER_ILISTFILE"));
+      log_printf(log_error, "%s: cannot open ilistfile %s", ilist_PRGNAME, getenv("COWDANCER_ILISTFILE"));
       return 1;
     }
   if (-1==fstat(fd,&stbuf))
     {
-      fprintf(stderr, "%s: cannot fstat ilistfile %s\n", ilist_PRGNAME, getenv("COWDANCER_ILISTFILE"));
+      log_printf(log_error, "%s: cannot fstat ilistfile %s", ilist_PRGNAME, getenv("COWDANCER_ILISTFILE"));
       return 1;
     }
 
@@ -93,7 +94,7 @@ static int load_ilist(void)
 
   if (stbuf.st_size != (sizeof(struct ilist_struct) * local_ilist_len + sizeof (struct ilist_header)))
     {
-      fprintf(stderr, "%s: .ilist size: %li\n", ilist_PRGNAME, (long)stbuf.st_size);
+      log_printf(log_error, "%s: .ilist size: %li", ilist_PRGNAME, (long)stbuf.st_size);
       ilist_outofmemory(".ilist size unexpected");
       return 1;
     }
@@ -102,17 +103,17 @@ static int load_ilist(void)
       (local_ilist=mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE,
 		  fd, 0)))
     {
-      perror("mmap failed, failback to other method");
+      log_perror("mmap failed, failback to other method");
       /* fall back to non-mmap method. */
       if (NULL==(f=fdopen(fd, "r")))
 	{
-	  fprintf(stderr, "%s: cannot fdopen ilistfile %s\n", ilist_PRGNAME, getenv("COWDANCER_ILISTFILE"));
+	  log_printf(log_error, "%s: cannot fdopen ilistfile %s", ilist_PRGNAME, getenv("COWDANCER_ILISTFILE"));
 	  return 1;
 	}
 
       if (NULL==(local_ilist=malloc(stbuf.st_size)))
 	{
-	  fprintf(stderr, "%s: out of memory while trying to allocate memory for ilist\n", ilist_PRGNAME);
+	  log_printf(log_error, "%s: out of memory while trying to allocate memory for ilist", ilist_PRGNAME);
 	  return 1;
 	}
       fread(&header, sizeof(struct ilist_header), 1, f);
@@ -144,13 +145,13 @@ static int load_ilist(void)
 static void debug_cowdancer (const char * s)
 {
   if (getenv("COWDANCER_DEBUG"))
-    fprintf (stderr, "%s: DEBUG %s\n", ilist_PRGNAME, s);
+    log_printf(log_debug | log_always_print, "%s: DEBUG %s", ilist_PRGNAME, s);
 }
 
 static void debug_cowdancer_2 (const char * s, const char*e)
 {
   if (getenv("COWDANCER_DEBUG"))
-    fprintf (stderr, "%s: DEBUG %s:%s\n", ilist_PRGNAME, s, e);
+    log_printf(log_debug | log_always_print, "%s: DEBUG %s:%s", ilist_PRGNAME, s, e);
 }
 
 /**
@@ -210,8 +211,8 @@ static int initialize_functions ()
 
       if (getenv("COWDANCER_DEBUG"))
 	{
-	  fprintf(stderr,
-		  "chown:%p lchown:%p\n", origlibc_chown, origlibc_lchown);
+	  log_printf(log_debug | log_always_print,
+		     "chown:%p lchown:%p", origlibc_chown, origlibc_lchown);
 	}
 
       /* load the ilist */
@@ -223,7 +224,7 @@ static int initialize_functions ()
 	      return 1;
 	    }
 	  initialized = 2;
-	  debug_cowdancer ("Initialization successfully finished.\n");
+	  debug_cowdancer ("Initialization successfully finished.");
 	}
     }
   /*
@@ -245,8 +246,8 @@ __attribute__ ((constructor))
 {
   if (initialize_functions())
     {
-      fprintf(stderr,
-	      "%s: Fatal, initialize_functions failed\n", ilist_PRGNAME);
+      log_printf(log_error,
+          "%s: Fatal, initialize_functions failed", ilist_PRGNAME);
     }
 }
 
@@ -296,10 +297,10 @@ static int check_inode_and_copy(const char* s, int canonicalize)
   //do some hardcore debugging here:
   if (getenv("COWDANCER_DEBUG"))
     {
-      fprintf (stderr,
-	       "ciac: s:%s=canonical:%s nlink:%i reg:%i lnk:%i match:%p\n", s, canonical, (int)buf.st_nlink, S_ISREG(buf.st_mode), S_ISLNK(buf.st_mode),
-	      bsearch(&search_target, ilist, ilist_len,
-		      sizeof(search_target), compare_ilist));
+      log_printf(log_debug | log_always_print,
+		 "ciac: s:%s=canonical:%s nlink:%i reg:%i lnk:%i match:%p", s, canonical, (int)buf.st_nlink, S_ISREG(buf.st_mode), S_ISLNK(buf.st_mode),
+		 bsearch(&search_target, ilist, ilist_len,
+			 sizeof(search_target), compare_ilist));
     }
 
   if((buf.st_nlink > 1) && 	/* it is hardlinked */
@@ -326,7 +327,7 @@ static int check_inode_and_copy(const char* s, int canonicalize)
       close(ret=mkstemp(backup_file));
       if (ret==-1)
 	{
-	  perror("mkstemp");
+	  log_perror("mkstemp");
 	  goto error_buf;
 	}
 
@@ -336,7 +337,7 @@ static int check_inode_and_copy(const char* s, int canonicalize)
       sigaddset (&newmask, SIGCHLD);
       if (sigprocmask (SIG_BLOCK, &newmask, &omask) < 0)
 	{
-	  perror("sigprocmask");
+	  log_perror("sigprocmask");
 	  goto error_buf;
 	}
 
@@ -354,7 +355,7 @@ static int check_inode_and_copy(const char* s, int canonicalize)
 	  putenv("COWDANCER_IGNORE=yes");
 	  sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL); /* unmask SIGCHLD signal */
 	  execl("/bin/cp", "/bin/cp", "-a", canonical, backup_file, NULL);
-	  perror("execl:cp:");
+	  log_perror("execl:cp:");
 	  exit(EXIT_FAILURE);
 	case -1:
 	  /* error condition in fork(); something is really wrong */
@@ -364,30 +365,30 @@ static int check_inode_and_copy(const char* s, int canonicalize)
 	  /* parent process, waiting for cp -a to terminate */
 	  if(-1==waitpid(pid, &status, 0))
 	    {
-	      perror("waitpid:cp");
-	      fprintf(stderr, "%s: unexpected waitpid error when waiting for process %i with status %x\n",
-		      ilist_PRGNAME, pid, status);
+	      log_perror("waitpid:cp");
+	      log_printf(log_error, "%s: unexpected waitpid error when waiting for process %i with status %x",
+		  ilist_PRGNAME, pid, status);
 	      goto error_spm;
 	    }
 
 	  if (!WIFEXITED(status))
 	    {
 	      /* something unexpected */
-	      fprintf(stderr, "%s: unexpected WIFEXITED status in waitpid: %x\n", ilist_PRGNAME,
-		      (int)status);
+	      log_printf(log_error, "%s: unexpected WIFEXITED status in waitpid: %x", ilist_PRGNAME,
+		  (int)status);
 	      goto error_spm;
 	    }
 	  else if (WEXITSTATUS(status))
 	    {
 	      /* cp -a failed */
-	      fprintf(stderr, "%s: cp -a failed for %s\n", ilist_PRGNAME, backup_file);
+	      log_printf(log_error, "%s: cp -a failed for %s", ilist_PRGNAME, backup_file);
 	      goto error_spm;
 	    }
 	  /* when cp -a succeeded, overwrite the target file from the temporary file with rename */
 	  else if (-1==rename(backup_file, canonical))
 	    {
-	      perror ("file overwrite with rename");
-	      fprintf(stderr, "%s: while trying rename of %s to %s\n",  ilist_PRGNAME, canonical, backup_file);
+	      log_perror("file overwrite with rename");
+	      log_printf(log_error, "%s: while trying rename of %s to %s",  ilist_PRGNAME, canonical, backup_file);
 	      goto error_spm;
 	    }
 	}
@@ -619,9 +620,9 @@ static int check_fd_inode_and_warn(int fd, const char* operation)
 
 	 If there is any better way, I'd like to know.
        */
-      fprintf(stderr,
-	      "W: cowdancer: unsupported operation %s, read-only open and fchown/fchmod/flock are not supported: tried opening dev:inode of %li:%li\n",
-	      operation, (long)buf.st_dev, (long)buf.st_ino);
+      log_printf(log_warn,
+          "cowdancer: unsupported operation %s, read-only open and fchown/fchmod/flock are not supported: tried opening dev:inode of %li:%li",
+          operation, (long)buf.st_dev, (long)buf.st_ino);
       /* emit a warning and do not fail,
 	 if you want to make it fail, add a return 1;
 	 apt seems to want to use this operation; thus apt will always fail.
diff --git a/debian/control b/debian/control
index b9ce6b0..5c3a68c 100644
--- a/debian/control
+++ b/debian/control
@@ -9,6 +9,7 @@ Build-Depends: cpio,
                debhelper (>> 9),
                klibc-utils [linux-any],
                libklibc-dev [linux-any],
+               libncurses-dev,
                pbuilder,
 Standards-Version: 3.9.8
 Vcs-Browser: https://anonscm.debian.org/git/pbuilder/cowdancer.git
diff --git a/file.c b/file.c
index b7afebc..0255185 100644
--- a/file.c
+++ b/file.c
@@ -38,6 +38,7 @@
 #include <alloca.h>
 #include <errno.h>
 #include "file.h"
+#include "log.h"
 
 /**
  * Copy file from orig to dest.
@@ -56,46 +57,46 @@ int copy_file(const char*orig, const char*dest)
 
   if (!buf)
     {
-      fprintf(stderr, "Out of memory\n");
+      log_printf(log_error, "Out of memory");
       goto out;
     }
 
   if (-1==(fin=open(orig,O_RDONLY)))
     {
-      perror("file copy: open for read");
+      log_perror("file copy: open for read");
       goto out;
     }
   if (-1==(fout=creat(dest,0666)))
     {
-      perror("file copy: open for write");
+      log_perror("file copy: open for write");
       goto out;
     }
   while((count=read(fin, buf, buffer_size))>0)
     {
       if (-1==write(fout, buf, count))
 	{			/* error */
-	  perror("file copy: write");
-	  fprintf(stderr, "%i\n", fin);
-	  fprintf(stderr, "%i %i\n", fout, (int)count);
+	  log_perror("file copy: write");
+	  log_printf(log_error, "%i", fin);
+	  log_printf(log_error, "%i %i", fout, (int)count);
 	  goto out;
 	}
     }
   if(count==-1)
     {
-      perror("file copy: read ");
+      log_perror("file copy: read ");
       goto out;
     }
   if (-1==close(fin) ||
       -1==close(fout))
     {
-      perror("file copy: close ");
+      log_perror("file copy: close ");
       goto out;
     }
 
   if (0>stat(orig, &st))
     {
-      fprintf(stderr,
-	      "Error calling stat '%s': %s\n",
+      log_printf(log_error,
+	      "Error calling stat '%s': %s",
 	      orig,
 	      strerror(errno));
       goto out;
@@ -103,8 +104,8 @@ int copy_file(const char*orig, const char*dest)
 
   if (chmod(dest, st.st_mode))
     {
-      fprintf(stderr,
-	      "Error calling chmod('%s' 0%llo): %s\n",
+      log_printf(log_error,
+	      "Error calling chmod('%s' 0%llo): %s",
 	      orig,
 	      (unsigned long long) st.st_mode,
 	      strerror(errno));
@@ -127,8 +128,8 @@ int create_sparse_file(const char* filename, unsigned long int size)
   int fd=creat(filename, 0660);
   if (-1==fd)
     {
-      perror("creat");
-      fprintf(stderr, "E: Could not create %s\n", filename);
+      log_perror("creat");
+      log_printf(log_error, "Could not create %s", filename);
       return 1;
     }
 
@@ -137,33 +138,33 @@ int create_sparse_file(const char* filename, unsigned long int size)
   size--;
   if (-1==lseek(fd, 0, SEEK_SET))
     {
-	perror("initial lseek");
+	log_perror("initial lseek");
 	return 1;
     }
 
   while(size > seeksize) {
     if (-1==lseek(fd, seeksize, SEEK_CUR))
       {
-	perror("intermediate lseek");
+	log_perror("intermediate lseek");
 	return 1;
       }
     size -= seeksize;
   }
   if (-1==lseek(fd, size - 1, SEEK_CUR))
     {
-      perror("final lseek");
+      log_perror("final lseek");
       return 1;
     }
 
   if (-1==write(fd, "", 1))		/* A string consists of \0, write 0 to end of file */
     {
-      perror("write");
+      log_perror("write");
       return 1;
     }
 
   if (-1==close(fd))
     {
-      perror("close");
+      log_perror("close");
       return 1;
     }
   return 0;
@@ -179,13 +180,13 @@ int mknod_inside_chroot(const char* chroot, const char* pathname, mode_t mode, d
 
   if (!p)
     {
-      fprintf(stderr, "error on alloca\n");
+      log_printf(log_error, "error on alloca");
       return -1;
     }
 
   if (-1==sprintf(p, "%s/%s", chroot, pathname))
     {
-      fprintf(stderr, "error on sprintf\n");
+      log_printf(log_error, "error on sprintf");
       return -1;
     }
 
@@ -194,7 +195,7 @@ int mknod_inside_chroot(const char* chroot, const char* pathname, mode_t mode, d
   if (ret == -1)
     {
       /* output the error message for debug, but ignore it here. */
-      perror(p);
+      log_perror(p);
     }
 
   return ret;
diff --git a/forkexec.c b/forkexec.c
index 91872ce..35936a2 100644
--- a/forkexec.c
+++ b/forkexec.c
@@ -40,14 +40,14 @@ int forkexecvp (char *const argv[])
   /* DEBUG: */
   {
     int i=0;
-    printf("  forking: ");
+    log_begin(log_info);
+    log_middle(log_info, "forking:");
 
-    while(argv[i])
+    for (i = 0; argv[i]; ++i)
       {
-	printf("%s ", argv[i]);
-	i++;
+	log_middle(log_info, " '%s'", argv[i]);
       }
-    printf("\n");
+    log_end(log_info);
   }
 
   fflush(NULL);
@@ -56,19 +56,19 @@ int forkexecvp (char *const argv[])
     {
     case 0:
       execvp(argv[0], (char*const*)argv);
-      perror("execvp");
-      fprintf(stderr, "Could not execute %s\n", argv[0]);
+      log_perror("execvp");
+      log_printf(log_error, "Could not execute %s", argv[0]);
       exit(EXIT_FAILURE);
     case -1:
       /* error condition in fork(); something is really wrong */
-      perror("fork");
+      log_perror("fork");
       return -1;
     default:
       /* parent process, waiting for termination */
       if (-1==waitpid(pid, &status, 0))
 	{
-	  perror("waitpid");
-	  fprintf(stderr, "unexpected waitpid error when waiting for process %i with status %x\n",
+	  log_perror("waitpid");
+	  log_printf(log_error, "Unexpected waitpid error when waiting for process %i with status %x",
 		  pid, status);
 	  return -1;
 	}
@@ -105,13 +105,14 @@ forkexeclp (const char *path, const char *arg0, ...)
   argv[0] = arg0;
   i = 1;
 
-  printf("  forking: %s ", argv[0]);/* debug message */
+  log_begin(log_info);
+  log_middle(log_info, "forking: '%s'", argv[0]); /* debug message */
 
   do
     {
       argv[i] = va_arg(args, const char *);
       if (argv[i])
-	printf("%s ", argv[i]);   /* debug message */
+	log_middle(log_info, " '%s'", argv[i]);    /* debug message */
 
       if ( i >= 1023 )
 	{
@@ -122,7 +123,7 @@ forkexeclp (const char *path, const char *arg0, ...)
   while (argv[i++] != NULL);
   va_end (args);
 
-  printf("\n");			/* debug message */
+  log_end(log_info);				  /* debug message */
 
   fflush(NULL);
 
@@ -130,18 +131,18 @@ forkexeclp (const char *path, const char *arg0, ...)
     {
     case 0:
       execvp(path, (char*const*)argv);
-      perror("pbuilder: execlp");
-      fprintf(stderr, "Could not execute %s\n", path);
+      log_perror("pbuilder: execlp");
+      log_printf(log_error, "Could not execute %s", path);
       exit(EXIT_FAILURE);
     case -1:
       /* error condition in fork(); something is really wrong */
-      perror("pbuilder: fork");
+      log_perror("pbuilder: fork");
       return -1;
     default:
       /* parent process, waiting for termination */
       if (-1==waitpid(pid, &status, 0))
 	{
-	  perror("waitpid");
+	  log_perror("waitpid");
 	  return -1;
 	}
       if (!WIFEXITED(status))
diff --git a/ilistcreate.c b/ilistcreate.c
index 351e84f..bc3f8a8 100755
--- a/ilistcreate.c
+++ b/ilistcreate.c
@@ -9,11 +9,12 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include "ilist.h"
+#include "log.h"
 
 /* Output error message. You need to process the error result. */
 void ilist_outofmemory(const char* msg)
 {
-  fprintf (stderr, "E: %s: %s\n", ilist_PRGNAME, msg);
+  log_printf(log_error, "%s: %s", ilist_PRGNAME, msg);
 }
 
 /* return 1 on error, 0 on success */
diff --git a/log.c b/log.c
new file mode 100644
index 0000000..74b5ec6
--- /dev/null
+++ b/log.c
@@ -0,0 +1,224 @@
+/*BINFMTC:
+ *  logging for cowdancer.
+ *  Copyright (C) 2016 James Clarke
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ */
+
+#define _GNU_SOURCE
+
+#include "log.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <curses.h>
+#include <term.h>
+
+static const char *red="\033[0;31m";
+static const char *yellow="\033[1;33m";
+static const char *blue="\033[0;34m";
+static const char *reset="\033[0m";
+
+static int called_setupterm = 0;
+static log_level filter_level = log_info;
+static log_use_colors use_colors = log_use_colors_auto;
+/* Same as use_colors, but stays as auto even when auto has been resolved */
+static log_use_colors use_colors_orig = log_use_colors_auto;
+
+static int term_supports_colors(void)
+{
+  /* Don't use log_printf - potential for infinite mutual recursion... */
+
+  int colors;
+  int erret;
+
+  if (!isatty(STDOUT_FILENO))
+    return 0;
+
+  if (!called_setupterm)
+    {
+      if (setupterm(NULL, STDOUT_FILENO, &erret) != OK && erret <= 0)
+	{
+	  fprintf(stderr, "E: Error calling setupterm: %d\n", erret);
+	  return 0;
+	}
+
+      called_setupterm = 1;
+    }
+
+  colors = tigetnum("colors");
+
+  if (colors < 0)
+    fprintf(stderr, "E: Error getting colors termcap: %d\n", colors);
+
+  return colors >= 8;
+}
+
+static FILE *file_for_level(log_level level)
+{
+  switch (level & LOG_LEVEL_MASK) {
+    case log_debug:
+    case log_info:
+      return stdout;
+    case log_warn:
+    case log_error:
+    default:
+      return stderr;
+  }
+}
+
+log_level log_get_filter_level(void)
+{
+  return filter_level;
+}
+
+void log_set_filter_level(log_level filter_level_new)
+{
+  filter_level = filter_level_new;
+}
+
+log_use_colors log_get_use_colors(void)
+{
+  return use_colors_orig;
+}
+
+void log_set_use_colors(log_use_colors use_colors_new)
+{
+  use_colors = use_colors_orig = use_colors_new;
+}
+
+void log_perror(const char *s)
+{
+  if (s != NULL && *s)
+    log_printf(log_error, "%s: %s", s, strerror(errno));
+  else
+    log_printf(log_error, "%s", strerror(errno));
+}
+
+void log_printf(log_level level, const char *format, ...)
+{
+  va_list args;
+
+  if (level < filter_level)
+    return;
+
+  log_begin(level);
+
+  va_start(args, format);
+  log_vmiddle(level, format, args);
+  va_end(args);
+
+  log_end(level);
+}
+
+void log_begin(log_level level)
+{
+  const char *color_str;
+  FILE *file;
+  const char *level_str;
+
+  if (level < filter_level)
+    return;
+
+  file = file_for_level(level);
+
+  if (use_colors == log_use_colors_auto)
+    {
+      if (term_supports_colors())
+	use_colors = log_use_colors_yes;
+      else
+	use_colors = log_use_colors_no;
+    }
+
+  switch (level & LOG_LEVEL_MASK) {
+    case log_debug:
+      color_str = blue;
+      level_str = "D";
+      break;
+    case log_info:
+      color_str = reset;
+      level_str = "I";
+      break;
+    case log_warn:
+      color_str = yellow;
+      level_str = "W";
+      break;
+    case log_error:
+      color_str = red;
+      level_str = "E";
+      break;
+    default:
+      color_str = red;
+      level_str = "?";
+      break;
+  }
+
+  if (use_colors == log_use_colors_yes)
+  {
+    fprintf(file, "%s", color_str);
+  }
+
+  fprintf(file, "%s: ", level_str);
+}
+
+void log_middle(log_level level, const char *format, ...)
+{
+  va_list args;
+  FILE *file;
+
+  if (level < filter_level)
+    return;
+
+  file = file_for_level(level);
+
+  va_start(args, format);
+  vfprintf(file, format, args);
+  va_end(args);
+}
+
+void log_vmiddle(log_level level, const char *format, va_list args)
+{
+  FILE *file;
+
+  if (level < filter_level)
+    return;
+
+  file = file_for_level(level);
+
+  vfprintf(file, format, args);
+}
+
+void log_end(log_level level)
+{
+  FILE *file;
+
+  if (level < filter_level)
+    return;
+
+  file = file_for_level(level);
+
+  if (use_colors == log_use_colors_yes)
+    {
+      fprintf(file, "%s\n", reset);
+    }
+  else
+    {
+      fprintf(file, "\n");
+    }
+}
diff --git a/log.h b/log.h
new file mode 100644
index 0000000..ec95d22
--- /dev/null
+++ b/log.h
@@ -0,0 +1,67 @@
+/*BINFMTC:
+ *  logging for cowdancer.
+ *  Copyright (C) 2016 James Clarke
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ */
+
+#ifndef __LOG_H__
+#define __LOG_H__
+
+#include <stdarg.h>
+#include <stdio.h>
+
+typedef enum log_level {
+  log_debug = 0,
+  log_info = 1,
+  log_warn = 2,
+  log_error = 3,
+  /* Do not use on its own - OR it in */
+  log_always_print = 0x100
+} log_level;
+
+#define LOG_LEVEL_MASK 0xff
+
+typedef enum log_use_colors {
+  log_use_colors_auto,
+  log_use_colors_no,
+  log_use_colors_yes
+} log_use_colors;
+
+log_level log_get_filter_level(void);
+
+void log_set_filter_level(log_level filter_level_new);
+
+log_use_colors log_get_use_colors(void);
+
+void log_set_use_colors(log_use_colors use_colors_new);
+
+void log_perror(const char *s);
+
+__attribute__((format(printf, 2, 3)))
+void log_printf(log_level level, const char *format, ...);
+
+void log_begin(log_level level);
+
+__attribute__((format(printf, 2, 3)))
+void log_middle(log_level level, const char *format, ...);
+
+__attribute__((format(printf, 2, 0)))
+void log_vmiddle(log_level level, const char *format, va_list args);
+
+void log_end(log_level level);
+
+#endif /* !__LOG_H__ */
diff --git a/parameter.c b/parameter.c
index 0ff3767..28a64f9 100644
--- a/parameter.c
+++ b/parameter.c
@@ -114,7 +114,41 @@ int load_config_file(const char* config, pbuilderconfig* pc)
 	{
 	  /* assuming config entry */
 	  *(delim++)=0;
-	  if (!strcmp(buf, "MIRRORSITE"))
+	  if (!strcmp(buf, "LOGLEVEL"))
+	    {
+	      if (!strcmp(delim, "D"))
+		{
+		  log_set_filter_level(log_debug);
+		}
+	      else if (!strcmp(delim, "I"))
+		{
+		  log_set_filter_level(log_info);
+		}
+	      else if (!strcmp(delim, "W"))
+		{
+		  log_set_filter_level(log_warn);
+		}
+	      else if (!strcmp(delim, "E"))
+		{
+		  log_set_filter_level(log_error);
+		}
+	    }
+	  else if (!strcmp(buf, "USECOLORS"))
+	    {
+	      if (!strcmp(delim, "auto"))
+		{
+		  log_set_use_colors(log_use_colors_auto);
+		}
+	      else if (!strcmp(delim, "no"))
+		{
+		  log_set_use_colors(log_use_colors_no);
+		}
+	      else if (!strcmp(delim, "yes"))
+		{
+		  log_set_use_colors(log_use_colors_yes);
+		}
+	    }
+	  else if (!strcmp(buf, "MIRRORSITE"))
 	    {
 	      pc->mirror=strdup_strip_quote(delim);
 	    }
@@ -223,13 +257,13 @@ int load_config_file(const char* config, pbuilderconfig* pc)
     }
 
   result = WEXITSTATUS( pclose(f) );
-  if(buf) {
+  if (buf) {
     // Don't warn of missing config files
-    if( result > 1 )
-      printf( "(exit %i) -> %s\n", result, buf );
+    if (result > 1)
+      log_printf(log_error, "(exit %i) -> %s", result, buf);
     free(buf);
   }
-  if(s) free(s);
+  if (s) free(s);
   return result;
 }
 
@@ -239,16 +273,38 @@ int cpbuilder_dumpconfig(pbuilderconfig* pc)
   /* dump configuration */
   int i;
 
-  printf("dump config\n");
+  log_printf(log_info, "start dump config");
 #define DUMPINT(S) printf("  "#S": %i\n", pc->S);
 #define DUMPSTR(S) printf("  "#S": %s\n", pc->S);
-#define DUMPSTRARRAY(S) i=0; \
-  while (pc->S[i]) \
+#define DUMPSTRARRAY(S) \
+  for (i = 0; pc->S[i]; ++i) \
     { \
       printf("  "#S"[%i]: %s\n", i, pc->S[i]); \
-      i++; \
     }
 
+#define DUMPLOGLEVEL(S) printf("  log_level: "S"\n");
+#define CASELOGLEVEL(L, S) case L: DUMPLOGLEVEL(S); break;
+  switch (log_get_filter_level()) {
+    CASELOGLEVEL(log_debug, "D");
+    CASELOGLEVEL(log_info,  "I");
+    CASELOGLEVEL(log_warn,  "W");
+    CASELOGLEVEL(log_error, "E");
+    default:
+      DUMPLOGLEVEL("?");
+      break;
+  }
+
+#define DUMPUSECOLORS(S) printf("  use_colors: "S"\n");
+#define CASEUSECOLORS(S) case log_use_colors_##S: DUMPUSECOLORS(#S); break;
+  switch (log_get_use_colors()) {
+    CASEUSECOLORS(auto);
+    CASEUSECOLORS(no);
+    CASEUSECOLORS(yes);
+    default:
+      DUMPUSECOLORS("?");
+      break;
+  }
+
   DUMPINT(mountproc);
   DUMPINT(mountdev);
   DUMPINT(mountdevpts);
@@ -280,6 +336,8 @@ int cpbuilder_dumpconfig(pbuilderconfig* pc)
   DUMPSTR(initrd);
   DUMPINT(memory_megs);
   DUMPSTR(arch);
+
+  log_printf(log_info, "end dump config");
   return 0;
 }
 
@@ -396,18 +454,18 @@ int parse_parameter(int ac, char** av,
 	    {
 	      if (mkdir(optarg, 0777)<0)
 		{
-		  perror("mkdir");
+		  log_perror("mkdir");
 		  return 1;
 		}
 	    }
 	  else if (!pc.operation)
 	    {
-	      fprintf(stderr, "need to specify operation before --basepath option\n");
+	      log_printf(log_error, "need to specify operation before --basepath option");
 	      return 1;
 	    }
 	  if (!(pc.basepath = canonicalize_file_name(optarg)))
 	    {
-	      fprintf(stderr, "cannot canonicalize filename %s, does not exist\n", optarg);
+	      log_printf(log_error, "cannot canonicalize filename %s, does not exist", optarg);
 	      return 1;
 	    }
 	  break;
@@ -422,7 +480,7 @@ int parse_parameter(int ac, char** av,
 	  if (0>asprintf(&cmdstr, "--%s", long_options[index_point].name))
 	    {
 	      /* error */
-	      fprintf(stderr, "out of memory constructing command-line options\n");
+	      log_printf(log_error, "out of memory constructing command-line options");
 	      exit (1);
 	    }
 	  PASS_TO_PBUILDER_WITH_PARAM
@@ -431,7 +489,7 @@ int parse_parameter(int ac, char** av,
 	  if (0>asprintf(&cmdstr, "--%s", long_options[index_point].name))
 	    {
 	      /* error */
-	      fprintf(stderr, "out of memory constructing command-line options\n");
+	      log_printf(log_error, "out of memory constructing command-line options");
 	      exit (1);
 	    }
 	  PASS_TO_PBUILDER_WITH_PARAM
@@ -440,7 +498,7 @@ int parse_parameter(int ac, char** av,
 	  if (0>asprintf(&cmdstr, "--%s", long_options[index_point].name))
 	    {
 	      /* error */
-	      fprintf(stderr, "out of memory constructing command-line options\n");
+	      log_printf(log_error, "out of memory constructing command-line options");
 	      exit (1);
 	    }
 	  PBUILDER_ADD_PARAM(cmdstr);
@@ -456,7 +514,7 @@ int parse_parameter(int ac, char** av,
 	  if (0>asprintf(&cmdstr, "--%s", long_options[index_point].name))
 	    {
 	      /* error */
-	      fprintf(stderr, "out of memory constructing command-line options\n");
+	      log_printf(log_error, "out of memory constructing command-line options");
 	      exit (1);
 	    }
 
@@ -498,7 +556,7 @@ int parse_parameter(int ac, char** av,
 	      pc.inputfile[size_of_ntarray(pc.inputfile)]=strdup(optarg);
 	      if (size_of_ntarray(pc.inputfile) >= MAX_CUSTOM_FILES)
 		{
-		  fprintf(stderr, "too many inputfile options\n");
+		  log_printf(log_error, "too many inputfile options");
 		  exit (1);
 		}
 	      PASS_TO_PBUILDER_WITH_PARAM
@@ -508,7 +566,7 @@ int parse_parameter(int ac, char** av,
 	      pc.inputfile[size_of_ntarray(pc.outputfile)]=strdup(optarg);
 	      if (size_of_ntarray(pc.outputfile) >= MAX_CUSTOM_FILES)
 		{
-		  fprintf(stderr, "too many outputfile options\n");
+		  log_printf(log_error, "too many outputfile options");
 		  exit (1);
 		}
 	    }
@@ -588,14 +646,14 @@ int parse_parameter(int ac, char** av,
 	  pc.operation=pbuilder_help;
 	  break;
 	default:
-	  fprintf(stderr, "Unhandled option\n");
+	  log_printf(log_error, "Unhandled option");
 	  /* Error case. */
 	  return 1;
 	}
     }
 
   if( 0 != config_ok ) {
-    printf( "Couldn't load any valid config file.\n" );
+    log_printf(log_error, "Couldn't load any valid config file.");
     exit( 6 );
   }
 
@@ -604,7 +662,7 @@ int parse_parameter(int ac, char** av,
     asprintf(&(pc.basepath), "/var/cache/pbuilder/base.%s", keyword);
   if (!pc.buildplace)
     {
-      fprintf(stderr, "E: BUILDPLACE is not set\n");
+      log_printf(log_error, "BUILDPLACE is not set");
       return 1;
     }
   else
@@ -651,7 +709,7 @@ int parse_parameter(int ac, char** av,
       if (!av[optind])
 	{
 	  /* parameter missing */
-	  fprintf(stderr, "E: parameter missing for build operation\n");
+	  log_printf(log_error, "parameter missing for build operation");
 	  return 1;
 	}
 
@@ -661,7 +719,7 @@ int parse_parameter(int ac, char** av,
       if (av[optind])
 	{
 	  /* extra parameter */
-	  fprintf(stderr, "E: too many parameters for create\n");
+	  log_printf(log_error, "too many parameters for create");
 	  return 1;
 	}
       return cpbuilder_create(&pc);
@@ -670,7 +728,7 @@ int parse_parameter(int ac, char** av,
       if (av[optind])
 	{
 	  /* extra parameter */
-	  fprintf(stderr, "E: too many parameters for update\n");
+	  log_printf(log_error, "too many parameters for update");
 	  return 1;
 	}
       return cpbuilder_update(&pc);
@@ -682,7 +740,7 @@ int parse_parameter(int ac, char** av,
       if (!av[optind])
 	{
 	  /* parameter missing */
-	  fprintf(stderr, "E: parameter missing for execute operation\n");
+	  log_printf(log_error, "parameter missing for execute operation");
 	  return 1;
 	}
       return cpbuilder_execute(&pc, &av[optind]);
@@ -694,7 +752,7 @@ int parse_parameter(int ac, char** av,
       return cpbuilder_dumpconfig(&pc);
 
     default:
-      fprintf (stderr, "E: No operation specified\n");
+      log_printf(log_error, "No operation specified");
       return 1;
     }
 
diff --git a/parameter.h b/parameter.h
index 71077ca..ec9e94a 100644
--- a/parameter.h
+++ b/parameter.h
@@ -20,12 +20,15 @@
 
 #ifndef __PARAMETER_H__
 #define __PARAMETER_H__
+#include "log.h"
 
 #define MAX_CUSTOM_FILES 32
 
 typedef struct pbuilderconfig
 {
   /* if you edit here, please add to parameter.c: dumpconfig */
+  log_level log_level;
+  int use_colors;
   int mountproc;
   int mountdev;
   int mountdevpts;
@@ -107,7 +110,7 @@ PBUILDER_ADD_PARAM(NULL);
  if(offset<(MAXPBUILDERCOMMANDLINE-1)) \
  {pbuildercommandline[offset++]=a;} \
  else \
- {pbuildercommandline[offset]=NULL; fprintf(stderr, "pbuilder-command-line: Max command-line exceeded\n");}
+ {pbuildercommandline[offset]=NULL; log_printf(log_error, "pbuilder-command-line: Max command-line exceeded\n");}
 extern char* pbuildercommandline[MAXPBUILDERCOMMANDLINE];
 extern int offset;
 
diff --git a/qemuarch.c b/qemuarch.c
index 952365c..8351e9c 100644
--- a/qemuarch.c
+++ b/qemuarch.c
@@ -80,7 +80,7 @@ const int qemu_create_arch_devices(const char* basedir, const char* arch)
   asprintf(&s, "%s/%s", basedir, "dev");
   if (-1==mkdir(s, 0777))
     {
-      perror("mkdir chroot-/dev");
+      log_perror("mkdir chroot-/dev");
       ret=1;
     }
   free(s);
diff --git a/qemubuilder.c b/qemubuilder.c
index 8bc65c6..aa2fd83 100755
--- a/qemubuilder.c
+++ b/qemubuilder.c
@@ -176,10 +176,10 @@ static FILE* create_script(const char* mountpoint, const char* relative_path)
       *c = 0;
       if (mkdir(s, 0777) && errno != EEXIST)
 	{
-	  fprintf(stderr,
-		  "E: Could not create directory '%s': %s\n",
-		  s,
-		  strerror(errno));
+	  log_printf(log_error,
+              "Could not create directory '%s': %s",
+              s,
+              strerror(errno));
 	  goto fail;
 	}
       *c = '/';
@@ -229,8 +229,8 @@ static int copy_file_contents_to_temp(const char* orig,
   ret=copy_file(orig, temppath);
   if (ret == -1)
     {
-      fprintf(stderr, "E: Copy file error in %s to %s\n",
-	      orig, temppath);
+      log_printf(log_error, "Copy file error in %s to %s",
+          orig, temppath);
       goto out;
     }
 out:
@@ -269,10 +269,10 @@ static int copy_file_contents_through_temp(FILE* f,
 		 "%s/input",
 		 tempdir))
     {
-      fprintf(stderr,
-	      "E: failed to allocate string for '%s/input': %s\n",
-	      tempdir,
-	      strerror(errno));
+      log_printf(log_error,
+	  "failed to allocate string for '%s/input': %s",
+	  tempdir,
+	  strerror(errno));
       ret = 1;
       goto out;
     }
@@ -281,20 +281,20 @@ static int copy_file_contents_through_temp(FILE* f,
 		 "input/%s",
 		 file_basename))
     {
-      fprintf(stderr,
-	      "E: failed to allocate string for 'input/%s': %s\n",
-	      file_basename,
-	      strerror(errno));
+      log_printf(log_error,
+	  "failed to allocate string for 'input/%s': %s",
+	  file_basename,
+	  strerror(errno));
       ret = 1;
       goto out;
     }
 
   if (mkdir(tempinput, 0777) && errno != EEXIST)
     {
-      fprintf(stderr,
-	      "E: failed to create directory '%s': %s\n",
-	      tempinput,
-	      strerror(errno));
+      log_printf(log_error,
+	  "failed to create directory '%s': %s",
+	  tempinput,
+	  strerror(errno));
       ret = 1;
       goto out;
     }
@@ -327,29 +327,29 @@ static int copy_hookdir(const char *hookdir, const char *tmp)
 		 "%s/hooks",
 		 tmp))
     {
-      fprintf(stderr,
-	      "Error allocating string for '%s/hooks': %s\n",
-	      tmp,
-	      strerror(errno));
+      log_printf(log_error,
+	  "Error allocating string for '%s/hooks': %s",
+	  tmp,
+	  strerror(errno));
       ret = 1;
       goto out;
     }
 
   if (mkdir(hookstmp,0777))
     {
-      fprintf(stderr,
-	      "Error creating directory for hooks: %s\n",
-	      strerror(errno));
+      log_printf(log_error,
+	  "Error creating directory for hooks: %s",
+	  strerror(errno));
       ret = 1;
       goto out;
     }
 
   if (hd == NULL)
     {
-      fprintf(stderr,
-	      "Error copying hooks from '%s': %s\n",
-	      hookdir,
-	      strerror(errno));
+      log_printf(log_error,
+	  "Error copying hooks from '%s': %s",
+	  hookdir,
+	  strerror(errno));
       ret = 1;
       goto out;
     }
@@ -364,20 +364,20 @@ static int copy_hookdir(const char *hookdir, const char *tmp)
 		     hookdir,
 		     dirp->d_name))
 	{
-	  fprintf(stderr,
-		  "Error allocating string for '%s/%s': %s\n",
-		  hookdir,
-		  dirp->d_name,
-		  strerror(errno));
+	  log_printf(log_error,
+	      "Error allocating string for '%s/%s': %s",
+	      hookdir,
+	      dirp->d_name,
+	      strerror(errno));
 	  ret = 1;
 	  goto out;
 	}
       if (0>stat(src, &st))
 	{
-	  fprintf(stderr,
-		  "Error calling stat '%s': %s\n",
-		  src,
-		  strerror(errno));
+	  log_printf(log_error,
+	      "Error calling stat '%s': %s",
+	      src,
+	      strerror(errno));
 	  free(src);
 	  ret = 1;
 	  goto out;
@@ -466,7 +466,7 @@ static int fork_qemu(const char* hda, const char* hdb, const struct pbuilderconf
 	  if (0<waitpid(child, &status, WNOHANG))
 	    {
 	      /* child has exited */
-	      printf("\n   -> qemu exited unexpectedly: %d\n", status);
+	      log_printf(log_error, "qemu exited unexpectedly: %d", status);
 	      break;
 	    }
 	  FD_SET(sp[0],&readfds);
@@ -488,19 +488,19 @@ static int fork_qemu(const char* hda, const char* hdb, const struct pbuilderconf
 				       qemu_keyword, strlen(qemu_keyword)))!=0)
 		    {
 		      exit_code = atoi(matchptr + strlen(qemu_keyword));
-		      printf("\n  -> received termination message from inside qemu with exit-code %i, killing child process (qemu:%i)\n",
-			     exit_code,
-			     child);
+		      log_printf(log_info, "received termination message from inside qemu with exit-code %i, killing child process (qemu:%i)",
+			  exit_code,
+			  child);
 
 		      assert(child != 0);assert(child > 0);
 
 		      if (!kill(child, SIGTERM))
-			printf("   -> successfully killed qemu\n");
+			log_printf(log_info, "successfully killed qemu");
 		      else
-			perror("   -> failed to kill qemu? :");
+			log_perror("failed to kill qemu?");
 		      if (-1==waitpid(child, &status, 0))
 			{
-			  perror("qemubuilder: waitpid");
+			  log_perror("qemubuilder: waitpid");
 			}
 		      break;
 		    }
@@ -509,7 +509,7 @@ static int fork_qemu(const char* hda, const char* hdb, const struct pbuilderconf
 	    }
 	  else
 	    {
-	      perror("select");
+	      log_perror("select");
 	      break;
 	    }
 	}
@@ -543,12 +543,12 @@ static int fork_qemu(const char* hda, const char* hdb, const struct pbuilderconf
 	term = "dumb";
 
       if (qemu == NULL || machine == NULL) {
-	fprintf(stderr, "Your architecture %s does not seem to be supported\n", pc->arch);
+	log_printf(log_error, "Your architecture %s does not seem to be supported", pc->arch);
 	exit(1);
       }
 
       if (kernel_image == NULL || !strcmp(kernel_image, "")) {
-	fprintf(stderr, "No KERNEL_IMAGE defined in pbuilderrc\n");
+	log_printf(log_error, "No KERNEL_IMAGE defined in pbuilderrc");
 	exit(1);
       }
 
@@ -556,13 +556,13 @@ static int fork_qemu(const char* hda, const char* hdb, const struct pbuilderconf
 
       if (hda_format == NULL)
 	{
-	  fprintf(stderr, "Unknown format for disk image %s\n", hda);
+	  log_printf(log_error, "Unknown format for disk image %s", hda);
 	  exit(1);
 	}
 
       if (hdb_format == NULL)
 	{
-	  fprintf(stderr, "Unknown format for disk image %s\n", hdb);
+	  log_printf(log_error, "Unknown format for disk image %s", hdb);
 	  exit(1);
 	}
 
@@ -640,20 +640,24 @@ static int fork_qemu(const char* hda, const char* hdb, const struct pbuilderconf
       argv[argc]=NULL;
       assert(argc < MAX_ARGS);
 
-      printf("  forking qemu: ");
+      log_begin(log_info);
+      log_middle(log_info, "forking qemu: ");
       for (i=0; i<argc; ++i)
 	{
-	  printf("%s ", argv[i]);
+	  if (i == 0)
+	    log_middle(log_info, "'%s'", argv[i]);
+	  else
+	    log_middle(log_info, " '%s'", argv[i]);
 	}
-      printf("\n");
+      log_end(log_info);
 
       execvp(argv[0], argv);
-      perror("fork_qemu");
+      log_perror("fork_qemu");
       exit (1);
     }
   else
     {
-      perror("fork");
+      log_perror("fork");
       return -1;
     }
 
@@ -696,7 +700,7 @@ static void write_first_stage(FILE *f, const struct pbuilderconfig* pc)
   fprintf(f,
 	  "#!/bin/bash\n"
 	  "echo \n"
-	  "echo ' -> qemu-pbuilder first-stage' \n"
+	  "echo 'I: qemu-pbuilder first-stage' \n"
 	  "export PBUILDER_INIT_VERSION="XSTR(PBUILDER_INIT_VERSION)"\n"
 	  "export PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'\n"
 	  "stty sane\n"
@@ -750,7 +754,7 @@ static int run_second_stage_script
   if (mkdir(pc->buildplace,0777))
     {
       /* could not create the buildplace here. */
-      perror("mkdir");
+      log_perror("mkdir");
       goto out;
     }
 
@@ -771,7 +775,7 @@ static int run_second_stage_script
 	  "sync\n"
 	  "sync\n"
 	  "sleep 1s\n"		/* sleep before sending dying message */
-	  "echo ' -> qemu-pbuilder %s'\"$1\"\n"
+	  "echo 'I: qemu-pbuilder %s'\"$1\"\n"
 	  "sleep 1s\n"
 	  "halt -f -p\n"	/* just halt myself if possible */
 	  "}\n",
@@ -780,7 +784,7 @@ static int run_second_stage_script
   fprintf(f,
 	  /* main code */
 	  "echo \n"
-	  "echo ' -> qemu-pbuilder second-stage' \n"
+	  "echo 'I: qemu-pbuilder second-stage' \n"
 	  // Remove compatibility symlink
 	  "rm \"$BUILDDIR\"/pbuilder-run\n"
 	  //"mount -n /proc /proc -t proc\n" // this is done in first stage.
@@ -792,9 +796,9 @@ static int run_second_stage_script
 	  "    echo \"E: qemubuilder init script is newer than expected (${PBUILDER_INIT_VERSION:-0} < "XSTR(PBUILDER_INIT_VERSION)")\"\n"
 	  "    exit_from_qemu 1\n"
 	  "fi\n"
-	  "echo '  -> setting time to %s' \n"
+	  "echo 'I: setting time to %s' \n"
 	  "date --set=\"%s\"\n"
-	  "echo '  -> configuring network' \n"
+	  "echo 'I: configuring network' \n"
 	  "ifconfig -a\n"
 	  "export IFNAME=`/sbin/ifconfig -a | grep eth | head -n1 | awk '{print $1}'`\n"
 	  "dhclient $IFNAME\n"
@@ -817,17 +821,17 @@ static int run_second_stage_script
 		   "%s/pbuilder-run",
 		   pc->buildplace))
       {
-	fprintf(stderr,
-	        "E: Failed to allocate string for compatibility symlink path '%s/pbuilder-run': %s\n",
-		pc->buildplace,
-		strerror(errno));
+	log_printf(log_error,
+	    "Failed to allocate string for compatibility symlink path '%s/pbuilder-run': %s",
+	    pc->buildplace,
+	    strerror(errno));
 	goto out;
       }
     if (symlink("input/pbuilder-run", compat_symlink))
       {
-	fprintf(stderr,
-		"E: Failed to create compatibility symlink: %s\n",
-		strerror(errno));
+	log_printf(log_error,
+	    "Failed to create compatibility symlink: %s",
+	    strerror(errno));
 	free(compat_symlink);
 	goto out;
       }
@@ -854,7 +858,7 @@ static int run_second_stage_script
 
   if(hostcommand1)
     {
-      printf("running host command: %s\n", hostcommand1);
+      log_printf(log_info, "running host command: %s", hostcommand1);
       system(hostcommand1);
     }
 
@@ -876,7 +880,7 @@ static int run_second_stage_script
   /* commit the change here */
   if (save_result)
     {
-      printf(" -> commit change to qemu image\n");
+      log_printf(log_info, "committing changes to qemu image");
       ret=forkexeclp("qemu-img", "qemu-img",
 		     "commit",
 		     cowdevpath,
@@ -885,15 +889,15 @@ static int run_second_stage_script
 
   /* after-run */
   loop_mount(workblockdevicepath, pc->buildplace);
-  printf(" -> running post-run process\n");
+  log_printf(log_info, "running post-run process");
   if(hostcommand2)
     {
-      printf("running host command: %s\n", hostcommand2);
+      log_printf(log_info, "running host command: %s", hostcommand2);
       system(hostcommand2);
     }
   loop_umount(pc->buildplace);
   rmdir(pc->buildplace);
-  printf(" -> clean up COW device files\n");
+  log_printf(log_info, "clean up COW device files");
   unlink(workblockdevicepath);
   unlink(cowdevpath);
   ret=0;
@@ -999,7 +1003,7 @@ int cpbuilder_create(const struct pbuilderconfig* pc)
     {
       /* could not create the buildplace here. */
       ret=1;
-      perror("mkdir");
+      log_perror("mkdir");
       goto out;
     }
 
@@ -1009,7 +1013,7 @@ int cpbuilder_create(const struct pbuilderconfig* pc)
       goto out;
     }
 
-  printf(" -> Invoking debootstrap\n");
+  log_printf(log_info, "Invoking debootstrap");
   ret=forkexeclp("debootstrap", "debootstrap",
 		 "--arch",
 		 pc->arch,
@@ -1020,8 +1024,7 @@ int cpbuilder_create(const struct pbuilderconfig* pc)
 		 NULL);
   if (ret)
     {
-      fprintf(stderr, "debootstrap failed with %i\n",
-	      ret);
+      log_printf(log_error, "debootstrap failed with %i", ret);
       goto umount_out;
     }
 
@@ -1034,7 +1037,7 @@ int cpbuilder_create(const struct pbuilderconfig* pc)
      we'll need think of other ways to work with them.
 
    */
-  printf(" -> Doing architecture-specific /dev population\n");
+  log_printf(log_info, "Doing architecture-specific /dev population");
 
   qemu_create_arch_devices(pc->buildplace, pc->arch);
 
@@ -1081,7 +1084,7 @@ int cpbuilder_create(const struct pbuilderconfig* pc)
 	  "sync\n"
 	  "sync\n"
 	  "sleep 1s\n"		/* sleep before sending dying message */
-	  "echo ' -> qemu-pbuilder %s$1'\n"
+	  "echo 'I: qemu-pbuilder %s$1'\n"
 	  "sleep 1s\n"
 	  "halt -f -p\n"	/* just halt myself if possible */
 	  "}\n",
@@ -1092,10 +1095,10 @@ int cpbuilder_create(const struct pbuilderconfig* pc)
 	  /* start of main code */
 	  "export RET=0\n"
 	  "echo \n"
-	  "echo ' -> qemu-pbuilder second-stage' \n"
-	  "echo '  -> setting time to %s' \n"
+	  "echo 'I: qemu-pbuilder second-stage' \n"
+	  "echo 'I: setting time to %s' \n"
 	  "date --set=\"%s\"\n"
-	  "echo '  -> Running debootstrap second-stage script' \n"
+	  "echo 'I: Running debootstrap second-stage script' \n"
 	  "touch /etc/udev/disabled\n" // work-around for #520742
 	  "/debootstrap/debootstrap --second-stage || ( "
 	  "  echo dumping debootstrap log\n"
@@ -1211,7 +1214,7 @@ int cpbuilder_build(const struct pbuilderconfig* pc, const char* dscfile)
 	   "ALLOWUNTRUSTED=%s /usr/lib/pbuilder/pbuilder-satisfydepends --control $BUILDDIR/*.dsc --internal-chrootexec 'chroot . ' %s \n"
 	   "apt-get install %s -y %s\n"
 	   "cd $BUILDDIR; /usr/bin/dpkg-source -x $(basename %s) \n"
-	   "echo ' -> Building the package'\n"
+	   "echo 'I: Building the package'\n"
 	   EXECUTE_HOOKS("A")
 	   "if ! (\n"
 	   "    cd $BUILDDIR/*-*/\n"
@@ -1317,28 +1320,26 @@ int cpbuilder_update(const struct pbuilderconfig* pc)
   ret = do_fsck(pc->basepath);
   if (ret)
     {
-      fprintf(stderr,
-	      "E: Failed fsck '%s'\n",
-	      pc->basepath);
+      log_printf(log_error, "Failed fsck '%s'", pc->basepath);
       return ret;
     }
 
   if (mkdir(pc->buildplace,0777))
     {
-      fprintf(stderr,
-	      "E: Could not create directory '%s': %s\n",
-	      pc->buildplace,
-	      strerror(errno));
+      log_printf(log_error,
+	  "Could not create directory '%s': %s",
+	  pc->buildplace,
+	  strerror(errno));
       return 1;
     }
 
   ret = loop_mount(pc->basepath, pc->buildplace);
   if (ret)
     {
-      fprintf(stderr,
-	      "E: Could not mount '%s' on '%s'\n",
-	      pc->basepath,
-	      pc->buildplace);
+      log_printf(log_error,
+	  "Could not mount '%s' on '%s'",
+	  pc->basepath,
+	  pc->buildplace);
       return ret;
     }
   FILE *g = create_script(pc->buildplace, "pbuilder-run");
@@ -1347,17 +1348,17 @@ int cpbuilder_update(const struct pbuilderconfig* pc)
   ret = loop_umount(pc->buildplace);
   if (ret)
     {
-      fprintf(stderr,
-	      "E: Could not unmount '%s'\n",
-	      pc->buildplace);
+      log_printf(log_error,
+	  "Could not unmount '%s'",
+	  pc->buildplace);
       return ret;
     }
   ret = rmdir(pc->buildplace);
   if (ret)
     {
-      fprintf(stderr,
-	      "E: Could not rmdir '%s'\n",
-	      pc->buildplace);
+      log_printf(log_error,
+	  "Could not rmdir '%s'",
+	  pc->buildplace);
       return ret;
     }
 
@@ -1379,7 +1380,7 @@ int cpbuilder_update(const struct pbuilderconfig* pc)
 		 , pc->allow_untrusted?"--force-yes":""
 		 , pc->extrapackages?pc->extrapackages:""))
     {
-      fprintf(stderr, "qemubuilder: out of memory.\n");
+      log_printf(log_error, "qemubuilder: out of memory.");
       return 1;
     }
 
diff --git a/qemuipsanitize.c b/qemuipsanitize.c
index 6c150d3..951ef67 100644
--- a/qemuipsanitize.c
+++ b/qemuipsanitize.c
@@ -8,6 +8,7 @@
 #include <netdb.h>
 #include <regex.h>
 #include "qemuipsanitize.h"
+#include "log.h"
 
 const char* sanitize_ipaddress(const char*addr)
 {
@@ -52,12 +53,12 @@ char* sanitize_mirror(const char*addr)
   if((e=regcomp(&r, "^([^:]*://)([^:/]*)(:[0-9]+)?(.*)$", REG_EXTENDED)))
     {
       /* error */
-      fprintf(stderr, "failed compiling regexp: %i\n", e);
+      log_printf(log_error, "failed compiling regexp: %i", e);
       return strdup(addr);
     }
   if((e=regexec(&r, addr, 5, m, 0)))
     {
-      fprintf(stderr, "failed regexp match: %i\n", e);
+      log_printf(log_error, "failed regexp match: %i", e);
       return strdup(addr);
     }
   asprintf(&buf,"%s%s%s%s",
diff --git a/test_cowbuilder.c b/test_cowbuilder.c
index 92750ce..1033433 100755
--- a/test_cowbuilder.c
+++ b/test_cowbuilder.c
@@ -1,4 +1,4 @@
-/*BINFMTC: cowbuilder.c parameter.c forkexec.c ilistcreate.c cowbuilder_util.c
+/*BINFMTC: cowbuilder.c parameter.c forkexec.c ilistcreate.c cowbuilder_util.c log.c -lncurses
  */
 
 #define _GNU_SOURCE
diff --git a/test_cowbuilder_util.c b/test_cowbuilder_util.c
index 4ec9e01..755f281 100755
--- a/test_cowbuilder_util.c
+++ b/test_cowbuilder_util.c
@@ -1,4 +1,4 @@
-/*BINFMTC: cowbuilder_util.c
+/*BINFMTC: cowbuilder_util.c log.c -lncurses
  */
 #include "cowbuilder_util.h"
 
diff --git a/test_file.c b/test_file.c
index 212a68d..a9ed5de 100755
--- a/test_file.c
+++ b/test_file.c
@@ -1,4 +1,4 @@
-/*BINFMTC: file.c forkexec.c
+/*BINFMTC: file.c forkexec.c log.c -lncurses
  */
 
 #define _GNU_SOURCE
diff --git a/test_forkexec.c b/test_forkexec.c
index 3de30a0..77c378d 100755
--- a/test_forkexec.c
+++ b/test_forkexec.c
@@ -1,4 +1,4 @@
-/*BINFMTC: forkexec.c
+/*BINFMTC: forkexec.c log.c -lncurses
  */
 #include <stdlib.h>
 #include <stdio.h>
diff --git a/test_ilistcreate.c b/test_ilistcreate.c
index 76624f4..53709c7 100755
--- a/test_ilistcreate.c
+++ b/test_ilistcreate.c
@@ -1,4 +1,4 @@
-/*BINFMTC: ilistcreate.c
+/*BINFMTC: ilistcreate.c log.c -lncurses
  test code for ilistcreate.c
  */
 #include <stdlib.h>
diff --git a/test_parameter.c b/test_parameter.c
index 5d38d44..135c237 100755
--- a/test_parameter.c
+++ b/test_parameter.c
@@ -1,4 +1,4 @@
-/*BINFMTC: parameter.c
+/*BINFMTC: parameter.c log.c -lncurses
 
  */
 #include <stdio.h>
diff --git a/test_qemuarch.c b/test_qemuarch.c
index e4deaba..d108f4b 100755
--- a/test_qemuarch.c
+++ b/test_qemuarch.c
@@ -1,4 +1,4 @@
-/*BINFMTC: qemuarch.c file.c
+/*BINFMTC: qemuarch.c file.c log.c -lncurses
  * test qemubuilder code
  */
 
diff --git a/test_qemuipsanitize.c b/test_qemuipsanitize.c
index 02b2a7c..797b0ed 100755
--- a/test_qemuipsanitize.c
+++ b/test_qemuipsanitize.c
@@ -1,4 +1,4 @@
-/*BINFMTC: qemuipsanitize.c
+/*BINFMTC: qemuipsanitize.c log.c -lncurses
  * test qemubuilder code
  */
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pbuilder/cowdancer.git



More information about the Pbuilder-maint mailing list