Home Download News FAQ / Knowledge Base Screenshots Documentation Support Site map
philosophical imaginary

This is an old revision of the document!


Table of Contents

Featured Projects

The Uncensored Communication Group contributes to other Opensource Projects too. Feel free to provide feedback via Uncensored! BBS

libical

LibIcal is maintained by the Citadel Staff. Its Page-Content is maintained in the Citadel.org libical page.

dokuwiki NROFF Syntax Plugin

As the Citadel Project uses the Dokuwiki, it has use in extending its functionality. To unify our Documentation needs, we've created a Dokuwiki plugin to render Manpages, the NROFF plugin.

use it like that:

curl 'http://www.citadel.org/doku.php/documentation:cmdman:webserver?do=export_nroff&sec tion=1' > webserver.1

note that 'section' controls the man-section which it should live in.

Get the plugin here: nroff.tgz

Maybe you'd like to create a template with a dummy manpage for your users.

Strace alike with Backtrace

We all like & use tools like the grand master flash valgrind or GDB but sometimes all of them just don't cut it, and you have to craft your own tool.

Now since citadel started using LibEv the possible number of simultaneusly open file descriptors grew enormously, it is like sitting down backwards onto a circular saw, and afterwards find out which tooth bite you.

You may already have heard about execinfo which enables you to fetch stack traces from within your running program to aid online debugging; certain library errormessages from citadel and webcit are able to show where they are called from this way.

So we now need to find out, whats going on with filedescriptors, who opens and closes them. strace is a nice tool for this job, however it doesn't utilize execinfo, so you only see FDs opening, closing, reading & writing, but no info from where within your program this was done.

This tiny .so can be preloaded via

LD_PRELOAD=libbacktrace.so

and will output many open / close / connect calls into a logfile so you can see what was going on. Its not all complete, but it already did its job and found my bug - so I'd like to share it with you:

/*
 * gcc  -Wall -nostartfiles -fpic -shared -olibbacktrace.so  backtrace_open.c 
 */
#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
#define _LARGEFILE_SOURCE
 
#include <dlfcn.h>
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
 
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/socket.h>
 
#include <netinet/in.h>
#include <arpa/inet.h>
 
#include <errno.h>
#include <time.h>
 
#include <execinfo.h>
 
 
/* XXX: do parallel support for open AND open64 by #undef open etc .. */
 
 
#define RESOLVE(x)	if (!o_##x && !(o_##x = dlsym(RTLD_NEXT, #x))) { fprintf(stderr, #x"() not found!\n"); exit(-1); }
 
#define min(x,y) ( (x)<(y)?(x):(y) )
#define max(x,y) ( (x)>(y)?(x):(y) )
 
#define N_FRAMES 50
 
/* XXX: need to handle this differently .. linked list? */
#define HIGHEST_FD 256
#define FEAT_RANGE_SUPPORT 1
 
static int (*o_open64)(const char *, int, ...);
static int (*o_close)(int);
 
static FILE *(*o_fopen64)(const char *, const char *);
static FILE *(*o_fdopen)(int fd, const char *mode);
static int (*o_fclose)(FILE *);
static int (*o_socket)(int domain, int type, int protocol);
static int (*o_connect)(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
static int (*o_creat)(const char *pathname, mode_t mode);
static int (*o_dup)(int oldfd);
static int (*o_dup2)(int oldfd, int newfd);
static int (*o_dup3)(int oldfd, int newfd, int flags);
 
FILE *myfd = NULL;
 
 
void _init(void)
{
	RESOLVE(fopen64);
	RESOLVE(open64);
	RESOLVE(fdopen);
	RESOLVE(socket);
	RESOLVE(connect);
	RESOLVE(fopen64);
	RESOLVE(close);
	RESOLVE(fclose);
	RESOLVE(creat);
	RESOLVE(dup);
	RESOLVE(dup2);
	RESOLVE(dup3);
 
	/* CRASH! if you load us uninitialized, your process deserves to die! */
	myfd = o_fopen64(getenv("DEBUG_FILENAME"), "a+");
 
	fprintf(myfd, "%d: my filedescriptor.\n", fileno(myfd));
	fprintf(myfd, "%d: my pid\n", getpid());
}
 
 
void oneline_backtrace(const char* CallName, const char *str1, long nFD)
{
 
	static const long sizeofstr =
		N_FRAMES *3 + // 0x,
		sizeof(void*) * N_FRAMES * 4 + // hex number
		N_FRAMES * 64 + // function string version
		256;
	void *stack_frames[N_FRAMES];
	char addresslist[sizeofstr]; 
	size_t size, i;
	long offset = 0;
	char **strings;
 
	addresslist [0] = '\0';
//	fprintf(myfd, "\n%ld: [", nFD);
 
//	fprintf(myfd, "\n%s: [", CallName);
	offset = sprintf(addresslist, "\n%ld: [%s][", nFD, CallName);
 
	size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
///	fprintf(myfd, "\n%ld: [", size);
	strings = backtrace_symbols(stack_frames, size);
	if (size > 0)
	{
		if (N_FRAMES < size)
			size = N_FRAMES;
 
		// skip first two frames, its just us.
		for (i = 2; i < size; i++) {
//			fprintf(myfd, "\t%ld - %p\n", i, strings[i]);
			if ((strings != NULL) && (strings[i] != NULL))
			{
//				fprintf(myfd, "\t%s\n", strings[i]);
				offset += snprintf(addresslist + offset, sizeofstr - offset, "\t%s\n", strings[i]);
			}
			else
			{
//				fprintf(myfd, "%p;", stack_frames[i]);
				offset += snprintf(addresslist + offset, sizeofstr - offset, "%p;", stack_frames[i]);
			}
			if (sizeofstr < offset + 64)
				break;
		}
	}
	offset += snprintf(addresslist + offset, sizeofstr - offset, "]\n\t%s", 
			   str1);
 
	fwrite(addresslist, 1, offset, myfd);
 
}
 
 
int open64(const char *pathname, int flag, ...)
{
	int ret;
 
	ret = o_open64(pathname, flag);
	oneline_backtrace (__FUNCTION__, pathname, ret);
 
	return ret;
}
 
int creat(const char *pathname, mode_t mode)
{
	int ret;
 
	ret = o_creat(pathname, mode);
	oneline_backtrace (__FUNCTION__, pathname, ret);
 
	return ret;
}
 
int dup(int oldfd)
{
	int ret;
	char buf[32];
 
	ret = o_dup(oldfd);
	sprintf(buf, "%d", oldfd);
	oneline_backtrace (__FUNCTION__, buf, ret);
 
	return ret;
}
 
int dup2(int oldfd, int newfd)
{
	int ret;
	char buf[64];
 
	ret = o_dup2(oldfd, newfd);
	sprintf(buf, "Old: %d, new: %d, ret: %d", 
		oldfd, newfd, ret);
	oneline_backtrace (__FUNCTION__, buf, ret);
 
	return ret;
}
 
int dup3(int oldfd, int newfd, int flags)
{
	int ret;
	char buf[64];
 
	ret = o_dup3(oldfd, newfd, flags);
	sprintf(buf, "Old: %d, new: %d, ret: %d", 
		oldfd, newfd, ret);
	oneline_backtrace (__FUNCTION__, buf, ret);
 
	return ret;
}
 
FILE *fopen64(const char *pathname, const char *mode)
{
	FILE *Ret;
	Ret = o_fopen64(pathname, mode);
 
	oneline_backtrace (__FUNCTION__, pathname, fileno(Ret));
 
	return Ret;
}
 
 
FILE *fdopen(int fd, const char *mode)
{
	FILE *Ret;
	Ret = o_fdopen(fd, mode);
 
	oneline_backtrace (__FUNCTION__, mode, fd);
 
	return Ret;
}
 
int socket(int domain, int type, int protocol)
{
	int ret;
	char buf[128];
 
	ret = o_socket(domain, type, protocol);
	snprintf(buf, sizeof(buf), "t: %d p:%d %s", 
		 type, protocol, strerror(errno));
 
	oneline_backtrace (__FUNCTION__, buf, ret);
	return ret;
}
 
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
	char what[64];
	char netbuf[64];
	int ret;
 
	if (addrlen == sizeof(struct sockaddr_in6))
	{
		inet_ntop(AF_INET6,
			  addr,
			  netbuf,
			  sizeof(netbuf));
 
		sprintf(what, "ipv6[%s]", netbuf);
	}
	else if (addrlen == sizeof(struct sockaddr_in))
	{
 
		inet_ntop(AF_INET,
			  addr,
			  netbuf,
			  sizeof(netbuf));
		sprintf(what, "ipv4[%s]", netbuf);
	}
	else
	{
		sprintf(what, " WTF? neither ipv4 nor 6? ");
 
	}
 
	ret = o_connect(sockfd, addr, addrlen);
 
	oneline_backtrace (__FUNCTION__, what, sockfd);
 
	return ret;
}
 
 
int close(int fd)
{
	oneline_backtrace (__FUNCTION__, "", fd);
 
	return o_close(fd);
}
 
int fclose(FILE *stream)
{
	int fd;
	int ret;
 
	fd = fileno(stream);
	ret = o_fclose(stream);
 
	oneline_backtrace (__FUNCTION__, strerror(errno), fd);
 
	return ret;
}
Copyright © 1987-2014 Uncensored Communications Group. All rights reserved.     Login (site admin)