Ejemplo n.º 1
0
int main(int argc, char **argv)
{
	//static const char OPTIONS[] = "hvlpsjPr:g:f::A:Ww:m:d:e:b:T:t:o:a:c:O:i:";
	static const char OPTIONS[] = "A:a:b:c:D:d:E:e:F:f:g:hi:jlm:no:O:Ppr:sT:t:vWw:x:y:";
	__sighandler_t sigint_original;
	char * const *file_names = NULL;
	size_t n_files = 0;
	int dither_mode = 0;
	int keep_power_on = 0;
	const char *waveform_id_str = "2";
	int waveform_id = 2;
	int do_enumerate_waveforms = 0;
	int do_log_info = 0;
	int do_wait_power_off = 0;
	int do_synchro = 0;
	int do_infinite_loop = 0;
	int cfa = -1;
	int display_enable = 0;
	int do_fill = 0;
	int fill_color = 0xFF;
	int do_auto_rotate = 0;
	int rotation_angle = -1;
	int do_partial_update = 0;
	int use_manual_temperature = 0;
	int manual_temperature = 25;
	unsigned long pause_ms = 2000;
	const char *mode = NULL;
	const char *fbdev = NULL;
	const char *epdev = NULL;
	const char *background = NULL;
	struct plep_point offset = { 0, 0 };
	enum epdoc_align_h align_h = EPDOC_ALIGN_H_NONE;
	enum epdoc_align_v align_v = EPDOC_ALIGN_V_NONE;
	struct plep_rect crop = { { 0, 0 }, { INT_MAX, INT_MAX } };
	const char *doc_type = NULL;
	const char *conf_file = NULL;
	struct plep *plep;
	struct pldraw *pldraw;
	int onoff = -1;
	int c;
	int ret;
	int use_alternative_vsource = 0;
	while ((c = getopt(argc, argv, OPTIONS)) != -1) {
		switch (c) {
		case 'A':
			if (!strcmp(optarg, "l")) {
			use_alternative_vsource = 1;
			}else if (!strcmp(optarg, "h")) {
			use_alternative_vsource = 2;
			}else if (!strcmp(optarg, "lh")) {
			use_alternative_vsource = 3;
			}else if (!strcmp(optarg, "hl")) {
			use_alternative_vsource = 3;
			}else{
				LOG("invalid alternative VSOURCE selection");
				print_usage();
				exit(EXIT_FAILURE);
			}
			break;
		case 'h':
			print_usage();
			exit(EXIT_SUCCESS);
			break;

		case 'v':
			printf("%s v%s - %s\n%s\n%s\n", APP_NAME, VERSION,
			       DESCRIPTION, COPYRIGHT, LICENSE);
			exit(EXIT_SUCCESS);
			break;

		case 'l':
			do_log_info = 1;
			break;
		case 'P':
			do_partial_update = 1;
			break;

		case 'p':
			do_wait_power_off = 1;
			break;

		case 's':
			do_synchro = 1;
			break;

		case 'j':
			do_infinite_loop = 1;
			break;

		case 'r':
			if (!strcmp(optarg, "auto")) {
				do_auto_rotate = 1;
			} else {
				unsigned long raw_angle;

				if (str2ul(optarg, &raw_angle) < 0) {
					LOG("failed to parse rotation angle");
					print_usage();
					exit(EXIT_FAILURE);
				}

				if ((raw_angle > 270) || (raw_angle % 90)) {
					LOG("invalid rotation angle");
					print_usage();
					exit(EXIT_FAILURE);
				}

				rotation_angle = raw_angle;
			}
			break;

		case 'g':
			if (str2ul(optarg, &pause_ms) < 0) {
				LOG("failed to parse pause duration");
				print_usage();
				exit(EXIT_FAILURE);
			}
			break;

		case 'f':
			if (optarg == NULL) {
				cfa = PLDRAW_CFA_GR_BW;
			} else {
				cfa = pldraw_get_cfa_id(optarg);

				if (cfa < 0) {
					LOG("Invalid CFA identifier: %s",
					    optarg);
					print_usage();
					exit(EXIT_FAILURE);
				}
			}
			break;
		
		case 'F':{
			char* str = optarg;
			if (optarg == NULL) {
				// set color to white (0xFF)
				do_fill = 1;
			} else {
				do_fill = 1;
				if(!strncmp(optarg, "0x", 2) || !strncmp(optarg, "0X", 2)){
					fill_color = strtoul(optarg, NULL, 16);
				}else{
					fill_color = atoi(optarg);
				}
			}
			break;
		}
		case 'T':
			manual_temperature = atoi(optarg);
			use_manual_temperature = 1;
			break;
		case 'W':
			do_enumerate_waveforms = 1;
			break;
		case 'i':
			waveform_id_str = NULL;
			waveform_id = atoi(optarg);
			break;
		case 'w':
			waveform_id_str = optarg;
			break;

		case 'm':
			mode = optarg;
			break;

		case 'd':
			fbdev = optarg;
			break;

		case 'e':
			epdev = optarg;
			break;

		case 'b':
			background = optarg;
			break;

		case 't':
			doc_type = optarg;
			break;

		case 'o':
			if (parse_offset(&offset, optarg) < 0) {
				print_usage();
				exit(EXIT_FAILURE);
			}
			break;

		case 'a':
			if (parse_alignment(&align_h, &align_v, optarg) < 0) {
				print_usage();
				exit(EXIT_FAILURE);
			}
			break;

		case 'c':
			if (parse_crop(&crop, optarg) < 0) {
				print_usage();
				exit(EXIT_FAILURE);
			}
			break;
		case 'O':
			conf_file = optarg;
			if (access(conf_file, F_OK)) {
				LOG_ERRNO("Configuration file");
				exit(EXIT_FAILURE);
			}
			break;
		case 'x':{
			onoff = atoi(optarg);
			break;
		}	
		case 'E':{
			//Enable Display N
			display_enable = atoi(optarg);
			if(display_enable > 3){
				LOG("Invalid arguments");
				exit(EXIT_FAILURE);
			}
			break;
		}
		case 'D':{
			//disable Display N
			display_enable -= atoi(optarg);
			if(display_enable < -3){
				LOG("Invalid arguments");
				exit(EXIT_FAILURE);
			}
			break;
		}
		case 'y':
			dither_mode = atoi(optarg);
			LOG("dither_mode %i", dither_mode);
			if(display_enable < 0 || display_enable > 3){
				LOG("Invalid arguments");
				exit(EXIT_FAILURE);
			}
			break;
		case 'n':{
			keep_power_on = 1;
			break;
		}	
		case '?':
		default:
			LOG("Invalid arguments");
			print_usage();
			exit(EXIT_FAILURE);
			break;
		}
	}

	if (optind < argc) {
		file_names = &argv[optind];
		n_files = argc - optind;
	}

	LOG("%s v%s", APP_NAME, VERSION);

	plep = plep_init(epdev, mode, conf_file);

	if (plep == NULL) {
		LOG("failed to initialise ePDC");
		goto error_plep;
	}

	pldraw = pldraw_init(fbdev, conf_file);

	if (pldraw == NULL) {
		LOG("failed to initialise pldraw");
		goto error_pldraw;
	}

	pldraw_set_plep(pldraw, plep);
	
	if(waveform_id_str){
		waveform_id = plep_get_wfid(plep, waveform_id_str);

		if (waveform_id < 0) {
			LOG("Invalid waveform path: %s", waveform_id_str);
			goto error_pldraw;
		}
	}
	
	if (cfa >= 0)
		pldraw_set_cfa(pldraw, cfa);
	else
		cfa = pldraw_get_cfa(pldraw);

	if (cfa != PLDRAW_CFA_NONE)
		LOG("CFA: %s", pldraw_cfa_name[cfa]);

	if (rotation_angle < 0)
		rotation_angle = pldraw_get_rotation(pldraw);

	if (rotation_angle)
		LOG("rotation: %d", rotation_angle);

	if (do_log_info)
		pldraw_log_info(pldraw);

	sigint_original = signal(SIGINT, sigint_abort);

	if(onoff != -1){
		LOG("POWER ONOFF:%i\n", onoff);
		if(onoff)
			plep_powerup(plep);
		else
			plep_powerdown(plep);
		exit(EXIT_SUCCESS);
	}
	if(display_enable != 0){
		//LOG("DISPLAY ENABLE:%i\n", display_enable);
		if(display_enable>0){
			plep_enable_display(plep, display_enable);
		}else{
			plep_disable_display(plep, display_enable);
		}
		exit(EXIT_SUCCESS);
	}
	if (do_enumerate_waveforms) {
		ret = enumerate_waveforms(plep);
	} else {
		struct epdoc_opt opt;

		plep_set_opt(plep, PLEP_SYNC_UPDATE, do_synchro);

		if (do_wait_power_off)
			plep_set_opt(plep, PLEP_WAIT_POWER_OFF, 1);

		if(do_partial_update){
			plep_set_opt(plep, PLEP_PARTIAL, 1);
		}
		
		if(use_manual_temperature){
			plep_set_opt(plep, PLEP_TEMPERATURE, 1);
			plep_set_hw_opt(plep, PLEP_TEMPERATURE, manual_temperature);
		}else{
			plep_set_opt(plep, PLEP_TEMPERATURE_AUTO, 1);
		}
		opt.dither_mode = dither_mode;
		opt.keep_power_on = keep_power_on;
		opt.do_auto_rotate = do_auto_rotate;
		opt.rotation_angle = rotation_angle;
		opt.wfid = waveform_id;
		opt.offset.x = offset.x;
		opt.offset.y = offset.y;
		opt.align_h = align_h;
		opt.align_v = align_v;
		memcpy(&opt.crop, &crop, sizeof opt.crop);
		opt.doc_type = doc_type;
		opt.use_alternative_vsource = use_alternative_vsource;
		
		if(do_fill){
			pldraw_fill_rect(pldraw, pldraw_get_grey(pldraw, fill_color), &crop);
			plep_update_screen(plep, opt.wfid);
		}else{
		
			ret = show_contents(pldraw, file_names, n_files, &opt,
				    pause_ms, do_infinite_loop, background);
		}
	}

	signal(SIGINT, sigint_original);
	pldraw_free(pldraw);
	plep_free(plep);

	exit((ret < 0) ? EXIT_FAILURE : EXIT_SUCCESS);

error_pldraw:
	plep_free(plep);
error_plep:
	exit(EXIT_FAILURE);
}
Ejemplo n.º 2
0
/* WARNING: all parameters MUST be valid,
 *          NULL pointers lead to a crash.
 */
ret_t
cherokee_socket_writev (cherokee_socket_t  *socket,
			const struct iovec *vector,
			uint16_t            vector_len,
			size_t             *pcnt_written)
{
	int    re;
	int    i;
	ret_t  ret;
	size_t cnt;

	*pcnt_written = 0;

	/* There must be something to send, otherwise behaviour is undefined
	 * and as we don't want this case, we have to enforce assertions.
	 */
	return_if_fail (vector != NULL && vector_len > 0, ret_error);

	if (likely (socket->is_tls != TLS))
	{
#ifdef _WIN32
		int i;
		size_t total;

		for (i = 0, re = 0, total = 0; i < vector_len; i++) {
			if (vector[i].iov_len == 0)
				continue;
			re = send (SOCKET_FD(socket), vector[i].iov_base, vector[i].iov_len, 0);
			if (re < 0)
				break;

			total += re;

			/* if it is a partial send, then stop sending data
			 */
			if (re != vector[i].iov_len)
				break;
		}
		*pcnt_written = total;

		/* if we have sent at least one byte,
		 * then return OK.
		 */
		if (likely (total > 0))
			return ret_ok;

		if (re == 0) {
			int err = SOCK_ERRNO();
			if (i == vector_len)
				return ret_ok;
			/* Retry later.
			 */
			return ret_eagain;
		}

#else	/* ! WIN32 */

		re = writev (SOCKET_FD(socket), vector, vector_len);

		if (likely (re > 0)) {
			*pcnt_written = (size_t) re;
			return ret_ok;
		}
		if (re == 0) {
			int i;
			/* Find out whether there was something to send or not.
			 */
			for (i = 0; i < vector_len; i++) {
				if (vector[i].iov_base != NULL && vector[i].iov_len > 0)
					break;
			}
			if (i < vector_len)
				return ret_eagain;
			/* No, nothing to send, so return ok.
			 */
			return ret_ok;
		}
#endif
		if (re < 0) {
			int err = SOCK_ERRNO();

			switch (err) {
#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
			case EWOULDBLOCK:
#endif
			case EAGAIN:
			case EINTR:
				return ret_eagain;

			case EPIPE:
#ifdef ENOTCONN
			case ENOTCONN:
#endif
			case ECONNRESET:
				socket->status = socket_closed;
			case ETIMEDOUT:
			case EHOSTUNREACH:
				return ret_error;
			}

			LOG_ERRNO (errno, cherokee_err_error,
				   CHEROKEE_ERROR_SOCKET_WRITEV, SOCKET_FD(socket));
		}
		return ret_error;

	}

	/* TLS connection: Here we don't worry about sparing a few CPU
	 * cycles, so we reuse the single send case for TLS.
	 */
	for (i = 0; i < vector_len; i++) {
		if ((vector[i].iov_len == 0) ||
		    (vector[i].iov_base == NULL))
			continue;

		cnt = 0;
		ret = cherokee_socket_write (socket, vector[i].iov_base, vector[i].iov_len, &cnt);
		if (ret != ret_ok) {
			return ret;
		}

		*pcnt_written += cnt;
		if (cnt == vector[i].iov_len)
			continue;

		/* Unfinished */
		return ret_ok;
	}

	/* Did send everything */
	return ret_ok;
}
Ejemplo n.º 3
0
int main(int argc, char **argv)
{
    struct dt_dentry *probe;
    struct cfwk_dir curdir;
    int full = 0;
    int lookup = 0;
    char *host;
    int i;
    char *oldtree = NULL;
    FILE *oldfile;
    char *port = NULL;
    char *server_cp = NULL;
    CURLcode rcode;

    for (i = 1; i < argc; i++) {
        if (argv[i][0] != '-')
            break;
        if (argv[i][1] == '-' && argv[i][2] == 0) {
            i++;
            break;
        }
        switch (argv[i][1]) {
            case 'f':
                full = 1;
                break;
            case 'p':
                port = &argv[i][2];
                break;
            case 'l':
                lookup = 1;
                break;
            case 'C':
                i++;
                if (i >= argc)
                    usage(argv[0], ESTAT_FAILURE);
                server_cp = argv[i];
                break;
            case 'u':
                i++;
                if (i >= argc)
                    usage(argv[0], ESTAT_FAILURE);
                oldtree = argv[i];
                break;
            case 'h':
                usage(argv[0], ESTAT_SUCCESS);
            default:
                usage(argv[0], ESTAT_FAILURE);
        }
    }
    
    if (i + 1 != argc)
        usage(argv[0], ESTAT_FAILURE);

    if ((rcode = curl_global_init(CURL_GLOBAL_NOTHING)) != CURLE_OK) {
        LOG_ERR("curl_global_init() returned non-zero: %s\n",
                curl_easy_strerror(rcode));
        exit(ESTAT_FAILURE);
    }

    host = argv[i];

    if (cfwk_open(&curdir, host, port, server_cp) < 0)
        exit(ESTAT_NOCONNECT);

    if (lookup) {
        probe = cfwk_walker.readdir(&curdir);
        cfwk_close(&curdir);
        if (probe != NULL) {
            dt_free(probe);
            exit(ESTAT_SUCCESS);
        }
        else
            exit(ESTAT_FAILURE);
    }

    if (full)
        dt_full(&cfwk_walker, &curdir);
    else if (oldtree) {
        if ((oldfile = fopen(oldtree, "r")) == NULL) {
            LOG_ERRNO("Can't open file %s\n", oldtree);
            exit(ESTAT_FAILURE);
        }
        dt_diff(oldfile, &cfwk_walker, &curdir);
        fclose(oldfile);
    } else
        dt_reverse(&cfwk_walker, &curdir);

    cfwk_close(&curdir);
    curl_global_cleanup();

    return ESTAT_SUCCESS;
}
Ejemplo n.º 4
0
/* WARNING: all parameters MUST be valid,
 *          NULL pointers lead to a crash.
 */
ret_t
cherokee_socket_write (cherokee_socket_t *socket,
		       const char        *buf,
		       int                buf_len,
		       size_t            *pcnt_written)
{
	ret_t   ret;
	ssize_t len;

	*pcnt_written = 0;

	/* There must be something to send, otherwise behaviour is undefined
	 * and as we don't want this case, we have to enforce assertions.
	 */
	return_if_fail (buf != NULL && buf_len > 0, ret_error);

	if (likely (socket->is_tls != TLS)) {
		len = send (SOCKET_FD(socket), buf, buf_len, 0);
		if (likely (len > 0) ) {
			/* Return n. of bytes sent.
			 */
			*pcnt_written = len;
			return ret_ok;
		}
		if (len == 0) {
			/* Very strange, socket is ready but nothing
			 * has been written, retry later.
			 */
			return ret_eagain;
		}
		/* else len < 0 */
		{
			int err = SOCK_ERRNO();

			switch (err) {
#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
			case EWOULDBLOCK:
#endif
			case EAGAIN:
			case EINTR:
				return ret_eagain;

			case EPIPE:
#ifdef ENOTCONN
			case ENOTCONN:
#endif
			case ECONNRESET:
				socket->status = socket_closed;
			case ETIMEDOUT:
			case EHOSTUNREACH:
				return ret_error;
			}

			LOG_ERRNO (errno, cherokee_err_error,
				   CHEROKEE_ERROR_SOCKET_WRITE, SOCKET_FD(socket));
		}
		return ret_error;

	} else if (socket->cryptor != NULL) {
		ret = cherokee_cryptor_socket_write (socket->cryptor,
						     (char *)buf, buf_len, pcnt_written);
		switch (ret) {
		case ret_ok:
		case ret_error:
		case ret_eagain:
			return ret;
		case ret_eof:
			socket->status = socket_closed;
			return ret_eof;
		default:
			RET_UNKNOWN(ret);
			return ret;
		}
	}

	return ret_error;
}
Ejemplo n.º 5
0
/* WARNING: all parameters MUST be valid,
 *          NULL pointers lead to a crash.
 */
ret_t
cherokee_socket_read (cherokee_socket_t *socket,
		      char              *buf,
		      int                buf_size,
		      size_t            *pcnt_read)
{
	ret_t   ret;
	ssize_t len;

	*pcnt_read = 0;

	/* There must be something to read, otherwise behaviour is undefined
	 * and as we don't want this case, we have to enforce assertions.
	 */
	return_if_fail (buf != NULL && buf_size > 0, ret_error);

	if (unlikely (socket->status == socket_closed)) {
		TRACE(ENTRIES, "Reading a closed socket: fd=%d (TLS=%d)\n", SOCKET_FD(socket), (socket->is_tls == TLS));
		return ret_eof;
	}

	if (likely (socket->is_tls != TLS)) {
		/* Plain read
		 */
		len = recv (SOCKET_FD(socket), buf, buf_size, 0);

		if (likely (len > 0)) {
			*pcnt_read = len;
			return ret_ok;
		}

		if (len == 0) {
			socket->status = socket_closed;
			return ret_eof;
		}

		{	/* len < 0 */
			int err = SOCK_ERRNO();

			TRACE(ENTRIES",read", "Socket read error fd=%d: '%s'\n",
			      SOCKET_FD(socket), strerror(errno));

			switch (err) {
#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
			case EWOULDBLOCK:
#endif
			case EINTR:
			case EAGAIN:
				return ret_eagain;

			case EPIPE:
#ifdef ENOTCONN
			case ENOTCONN:
#endif
			case ECONNRESET:
				socket->status = socket_closed;
			case ETIMEDOUT:
			case EHOSTUNREACH:
				return ret_error;
			}

			LOG_ERRNO (errno, cherokee_err_error,
				   CHEROKEE_ERROR_SOCKET_READ, SOCKET_FD(socket));
		}
		return ret_error;

	} else if (socket->cryptor != NULL) {
		ret = cherokee_cryptor_socket_read (socket->cryptor,
						    buf, buf_size, pcnt_read);
		switch (ret) {
		case ret_ok:
		case ret_error:
		case ret_eagain:
			return ret;
		case ret_eof:
			socket->status = socket_closed;
			return ret_eof;
		default:
			RET_UNKNOWN(ret);
			return ret;
		}
	}

	return ret_error;
}
Ejemplo n.º 6
0
ret_t
cherokee_socket_set_cork (cherokee_socket_t *socket, cherokee_boolean_t enable)
{
	int re;
	int tmp = 0;
	int fd  = socket->socket;

	if (enable) {
		tmp = 0;
		do {
			re = setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof(tmp));
		} while ((re == -1) && (errno == EINTR));

		if (unlikely (re < 0)) {
			LOG_ERRNO (errno, cherokee_err_error,
				   CHEROKEE_ERROR_SOCKET_RM_NODELAY, fd);
			return ret_error;
		}

		TRACE(ENTRIES",cork,nodelay", "Set TCP_NODELAY on fd %d\n", fd);

#ifdef TCP_CORK
		tmp = 1;
		do {
			re = setsockopt (fd, IPPROTO_TCP, TCP_CORK, &tmp, sizeof(tmp));
		} while ((re == -1) && (errno == EINTR));

		if (unlikely (re < 0)) {
			LOG_ERRNO (errno, cherokee_err_error,
				   CHEROKEE_ERROR_SOCKET_SET_CORK, fd);
			return ret_error;
		}

		TRACE(ENTRIES",cork", "Set TCP_CORK on fd %d\n", fd);
#endif

		return ret_ok;
	}

#ifdef TCP_CORK
	tmp = 0;
	do {
		re = setsockopt (fd, IPPROTO_TCP, TCP_CORK, &tmp, sizeof(tmp));
	} while ((re == -1) && (errno == EINTR));
	if (unlikely (re < 0)) {
		LOG_ERRNO (errno, cherokee_err_error,
			   CHEROKEE_ERROR_SOCKET_RM_CORK, fd);
		return ret_error;
	}

	TRACE(ENTRIES",cork", "Removed TCP_CORK on fd %d\n", fd);
#endif

	tmp = 1;
	do {
		re = setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof(tmp));
	} while ((re == -1) && (errno == EINTR));
	if (unlikely (re < 0)) {
		LOG_ERRNO (errno, cherokee_err_error,
			   CHEROKEE_ERROR_SOCKET_SET_NODELAY, fd);
		return ret_error;
	}

	TRACE(ENTRIES",cork,nodelay", "Removed TCP_NODELAY on fd %d\n", fd);
	return ret_ok;
}
Ejemplo n.º 7
0
ret_t
cherokee_socket_accept_fd (cherokee_socket_t   *server_socket,
			   int                 *new_fd,
			   cherokee_sockaddr_t *sa)
{
	ret_t     ret;
	socklen_t len;
	int       new_socket;

	/* Get the new connection
	 */
	len = sizeof (cherokee_sockaddr_t);

	do {
		new_socket = accept (server_socket->socket, &sa->sa, &len);
	} while ((new_socket == -1) && (errno == EINTR));

	if (new_socket < 0) {
		return ret_error;
	}

#if 0 /* DISABLED */

	/* Deal with the FIN_WAIT2 state
	 */
	re = 1;
	re = setsockopt (new_socket, SOL_SOCKET, SO_KEEPALIVE, &re, sizeof(re));
	if (re == -1) {
		LOG_ERRNO (errno, cherokee_err_warning,
			   CHEROKEE_ERROR_SOCKET_SET_KEEPALIVE, new_socket);
	}

	linger.l_onoff  = 1;
	linger.l_linger = SECONDS_TO_LINGER;

	re = setsockopt (new_socket, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
	if (re == -1) {
		LOG_ERRNO (errno, cherokee_err_warning,
			   CHEROKEE_ERROR_SOCKET_SET_LINGER, new_socket);
	}
#endif

	/* Close-on-exec: Child processes won't inherit this fd
	 */
	cherokee_fd_set_closexec (new_socket);

	/* Enables nonblocking I/O.
	 */
	ret = cherokee_fd_set_nonblocking (new_socket, true);
	if (ret != ret_ok) {
		LOG_WARNING (CHEROKEE_ERROR_SOCKET_NON_BLOCKING, new_socket);

		cherokee_fd_close (new_socket);
		return ret_error;
	}

	/* Disable Nagle's algorithm for this connection
	 * so that there is no delay involved when sending data
	 * which don't fill up a full IP datagram.
	 */
	ret = cherokee_fd_set_nodelay (new_socket, true);
	if (ret != ret_ok) {
		LOG_WARNING_S (CHEROKEE_ERROR_SOCKET_RM_NAGLES);

		cherokee_fd_close (new_socket);
		return ret_error;
	}

	*new_fd = new_socket;
	return ret_ok;
}
Ejemplo n.º 8
0
ret_t
fdpoll_epoll_new (cherokee_fdpoll_t **fdp, int sys_fd_limit, int fd_limit)
{
	int                re;
	cherokee_fdpoll_t *nfd;
	CHEROKEE_CNEW_STRUCT (1, n, fdpoll_epoll);

	nfd = FDPOLL(n);

	/* Init base class properties
	 */
	nfd->type          = cherokee_poll_epoll;
	nfd->nfiles        = fd_limit;
	nfd->system_nfiles = sys_fd_limit;
	nfd->npollfds      = 0;

	/* Init base class virtual methods
	 */
	nfd->free          = (fdpoll_func_free_t) _free;
	nfd->add           = (fdpoll_func_add_t) _add;
	nfd->del           = (fdpoll_func_del_t) _del;
	nfd->reset         = (fdpoll_func_reset_t) _reset;
	nfd->set_mode      = (fdpoll_func_set_mode_t) _set_mode;
	nfd->check         = (fdpoll_func_check_t) _check;
	nfd->watch         = (fdpoll_func_watch_t) _watch;

	/* Look for max fd limit
	 */
	n->ep_fd = -1;
	n->ep_nrevents  = 0;
	n->ep_events    = (struct epoll_event *) calloc (nfd->nfiles, sizeof(struct epoll_event));
	n->epoll_fd2idx = (int *) calloc (nfd->system_nfiles, sizeof(int));

	/* If anyone fails free all and return ret_nomem
	 */
	if (n->ep_events == NULL || n->epoll_fd2idx == NULL) {
		_free(n);
		return ret_nomem;
	}

	for (re = 0; re < nfd->system_nfiles; re++) {
		n->epoll_fd2idx[re] = -1;
	}

	n->ep_fd = epoll_create (nfd->nfiles);
	if (n->ep_fd < 0) {
		/* It may fail here if the glibc library supports epoll,
		 * but the kernel doesn't.
		 */
#if 0
		LOG_ERRNO (errno, cherokee_err_error,
			   CHEROKEE_ERROR_FDPOLL_EPOLL_CREATE, nfd->nfiles+1);
#endif
		_free (n);
		return ret_error;
	}

	re = fcntl (n->ep_fd, F_SETFD, FD_CLOEXEC);
	if (re < 0) {
		LOG_ERRNO (errno, cherokee_err_error,
			   CHEROKEE_ERROR_FDPOLL_EPOLL_CLOEXEC);
		_free (n);
		return ret_error;
	}

	/* Return the object
	 */
	*fdp = nfd;
	return ret_ok;
}
Ejemplo n.º 9
0
netif_init_bpf(netif_t *netif, const char *name, uint16_t port, struct sock_filter *filter, int filter_len)
#endif
{
    bool                        result = true;
    struct ifaddrs             *ifas;
    struct ifaddrs             *ifa;

#if __FreeBSD__
    struct ifreq                ifr;            /* ioctl call to get VID */
    struct vlanreq              vreq;           /* ioctl call to get VID */
#elif __linux__
    struct ifreq                ifr;            /* ioctl call to get MAC address*/
    struct rtnl_link_stats     *stats;
    struct vlan_ioctl_args      ifv;            /* ioctl call to get VID */
    struct sockaddr_ll          addr;           /* to bind packet socket to interface */
    struct sockaddr_in          dummy_addr;     /* to bind dummy socket to interface */
    struct sock_fprog           prog;           /* to attach to filter */
#endif

    
    /* string copy name */
    strncpy(netif->name, name, NETIF_NAME_SIZE);
    
    /* set to zero */
    memcpy(netif->mac.addr, MAC_ADDRESS_NULL.addr, MAC_ADDRESS_LEN);
    netif->vlan = NULL;
    netif->ipv4 = NULL;
    netif->ipv6 = NULL;

    /*** get the index of the interface ***/
    netif->index = if_nametoindex(netif->name);

    if (netif->index == 0) {
        LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_ERROR, ("interface '%s' is not known", netif->name));
        return false;
    }
    
    /* create socket */
    if ((netif->socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) {
        LOG_ERRNO(LOG_NETWORK_INTERFACE, LOG_ERROR, errno, ("socket failed"));
        return false;
    }
    
    /* get interface addresses */
    if (getifaddrs(&ifas) != 0) {
         LOG_ERRNO(LOG_NETWORK_INTERFACE, LOG_ERROR, errno, ("getifaddrs failed"));
        return false;
    }
    
    for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
        if ((ifa->ifa_addr)           == NULL) continue;
        if ((ifa->ifa_flags & IFF_UP) == 0)    continue;
        
        
        /* network interface name matches */
        if (strcmp(name, ifa->ifa_name) == 0) {
            
            switch (ifa->ifa_addr->sa_family) {
                case AF_INET:   netif_add_ipv4_address(netif,      IPV4_ADDRESS(&(INADDR(ifa->ifa_addr)->sin_addr)),
                                                                   IPV4_ADDRESS(&(INADDR(ifa->ifa_netmask)->sin_addr)),
                                                                   IPV4_ADDRESS(&(INADDR(ifa->ifa_broadaddr)->sin_addr)),
                                                                   NULL);
                                break;
                
                case AF_INET6:  netif_add_ipv6_address(netif,      IPV6_ADDRESS(&(INADDR6(ifa->ifa_addr)->sin6_addr)),
                                                                   IPV6_ADDRESS(&(INADDR6(ifa->ifa_netmask)->sin6_addr)),
                                                                   IPV6_STATE_VALID);
                                break;

#if __FreeBSD__
                case AF_LINK:   netif_add_mac_address(netif,       MAC_ADDRESS(LLADDR(LADDR(ifa->ifa_addr))));
                                
                                bzero((char *) &ifr, sizeof(ifr));
                                bzero((char *) &vreq, sizeof(vreq));
                                strncpy(ifr.ifr_name, netif->name, NETIF_NAME_SIZE);
                                ifr.ifr_data = (caddr_t) &vreq;
                                if (ioctl(sockfd, SIOCGETVLAN, &ifr) != -1) {
                                    netif_add_vid(netif, vreq.vlr_tag);
                                }
                                break;
#elif __linux__
                case AF_PACKET: stats = ifa->ifa_data;
                                LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_DEBUG, ("tx packet: %" PRIu32 " rx packet: %" PRIu32 " tx bytes: %" PRIu32 " rx bytes: %" PRIu32,
                                                                               stats->tx_packets, stats->rx_packets, stats->tx_bytes, stats->rx_bytes));

                                /* get MAC address, see netdevice(7) */
                                bzero((char *) &ifr, sizeof(ifr));
                                strncpy(ifr.ifr_name, netif->name, NETIF_NAME_SIZE);
                                if (ioctl(netif->socket, SIOCGIFHWADDR, &ifr) != -1) {
                                    netif_add_mac_address(netif,   MAC_ADDRESS(LLADDR(LADDR(ifr.ifr_hwaddr.sa_data))));
                                    bzero((char *) &ifv, sizeof(ifv));
                                    ifv.cmd = GET_VLAN_VID_CMD;
                                    strncpy(ifv.device1, netif->name, sizeof(ifv.device1));
                                    if (ioctl(netif->socket, SIOCGIFVLAN, &ifv) != -1) {
                                        netif_add_vid(netif, ifv.u.VID);
                                    }
                                } else {
                                    LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_ERROR, ("couldn't get MAC address"));
                                    result = false;
                                    goto netif_init_exit;
                                }
                                break;
#endif
                default:        continue;
            }
        }
    }
    

    /* bind packet socket to interface */
    bzero(&addr, sizeof(addr));
    addr.sll_family   = AF_PACKET;
    addr.sll_protocol = htons(ETH_P_ALL);
    addr.sll_ifindex  = netif->index;

    if (bind(netif->socket, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
        close(netif->socket);
        LOG_ERRNO(LOG_NETWORK_INTERFACE, LOG_ERROR, errno, ("can't bind packet socket to interface"));
        return false;
    }


#if __FreeBSD__

#elif __linux__
    if (filter != NULL) {
        prog.filter = filter;
        prog.len    = filter_len;
        if (setsockopt(netif->socket, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0) {
            close(netif->socket);
            LOG_ERRNO(LOG_NETWORK_INTERFACE, LOG_ERROR, errno, ("can't add BPF filter"));
            return false;
        }
    }
#endif

    if (netif->ipv4 != NULL && port > 0) {
        /* create dummy socket ***/
        if ((netif->dummy_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
            close(netif->socket);
            LOG_ERRNO(LOG_NETWORK_INTERFACE, LOG_ERROR, errno, ("can't create dummy socket"));
            return false;
        }

        /* bind dummy socket to interface */
        bzero(&dummy_addr, sizeof(dummy_addr));
        dummy_addr.sin_family      = AF_INET;
        dummy_addr.sin_addr.s_addr = netif->ipv4->address.addr32;
        dummy_addr.sin_port        = htons(port);

        if (bind(netif->dummy_socket, (struct sockaddr *) &dummy_addr, sizeof(dummy_addr)) < 0) {
            close(netif->socket);
            close(netif->dummy_socket);
            LOG_ERRNO(LOG_NETWORK_INTERFACE, LOG_ERROR, errno, ("can't bind dummy socket to interface"));
            return false;
        }
    }

    /* clear receive buffer */
    if (!netif_clear_receive_buffer(netif)) {
        return false;
    }


netif_init_exit:
    freeifaddrs(ifas);
    
    return result;
}
Ejemplo n.º 10
0
ret_t
cherokee_source_connect (cherokee_source_t *src, cherokee_socket_t *sock)
{
	ret_t                    ret;
	cherokee_resolv_cache_t *resolv;

	/* Short path: it's already connecting
	 */
	if (sock->socket >= 0) {
		return cherokee_socket_connect (sock);
	}

	/* Create the new socket and set the target IP info
	 */
	if (! cherokee_buffer_is_empty (&src->unix_socket)) {

		/* Create the socket descriptor
		 */
		ret = cherokee_socket_create_fd (sock, AF_UNIX);
		if (unlikely (ret != ret_ok)) {
			return ret;
		}

		ret = cherokee_socket_gethostbyname (sock, &src->unix_socket);
		if (unlikely (ret != ret_ok)) {
			return ret;
		}
	} else {
		cherokee_boolean_t     tested_all;
		const struct addrinfo *addr;
		const struct addrinfo *addr_info = NULL;

		/* Query the resolv cache
		 */
		ret = cherokee_resolv_cache_get_default (&resolv);
		if (unlikely (ret!=ret_ok)) {
			return ret;
		}

		ret = cherokee_resolv_cache_get_addrinfo (resolv, &src->host, &addr_info);
		if ((ret != ret_ok) || (addr_info == NULL)) {
			return ret_error;
		}

		/* Current address
		 */
		if (src->addr_current) {
			tested_all = false;
			addr = src->addr_current;
		} else {
			tested_all = true;
			addr = addr_info;
		}

		/* Create the fd for the address family
		 *
		 * Iterates through the different addresses of the
		 * host and stores a pointer to the first one with
		 * a supported family.
		 */
		while (addr != NULL) {
			ret = cherokee_socket_create_fd (sock, addr->ai_family);

#ifdef TRACE_ENABLED
			if (cherokee_trace_is_tracing()) {
				ret_t ret2;
				char ip[46];

				ret2 = cherokee_ntop (addr->ai_family, addr->ai_addr, ip, sizeof(ip));
				if (ret2 == ret_ok) {
					TRACE (ENTRIES, "Connecting to %s, ret=%d\n", ip, ret);
				}
			}
#endif

			if (ret == ret_ok) {
				src->addr_current = addr;
				break;
			}

			addr = addr->ai_next;
			if (addr == NULL) {
				if (tested_all) {
					return ret_error;
				}

				tested_all = true;
				src->addr_current = NULL;
				addr = addr_info;
				continue;
			}

			cherokee_socket_close(sock);
		}

		/* Update the new socket with the address info
		 */
		switch (src->addr_current->ai_family) {
		case AF_INET:
			SOCKET_ADDR_IPv4(sock)->sin_port = htons(src->port);
			break;
		case AF_INET6:
			SOCKET_ADDR_IPv6(sock)->sin6_port = htons(src->port);
			break;
		default:
			SHOULDNT_HAPPEN;
			return ret_error;
		}

		ret = cherokee_socket_update_from_addrinfo (sock, src->addr_current, 0);
		if (unlikely (ret != ret_ok)) {
			return ret_error;
		}
	}

	/* Set non-blocking */
	ret = cherokee_fd_set_nonblocking (sock->socket, true);
	if (unlikely (ret != ret_ok)) {
		LOG_ERRNO (errno, cherokee_err_error, CHEROKEE_ERROR_SOURCE_NONBLOCK, sock->socket);
	}

	/* Set close-on-exec and reuse-address */
	cherokee_fd_set_closexec  (sock->socket);
	cherokee_fd_set_reuseaddr (sock->socket);

	return cherokee_socket_connect (sock);
}
Ejemplo n.º 11
0
static void init_seccomp(uint32_t def_action, bool main)
{
	scmp_filter_ctx ctx = seccomp_init(def_action);
	if (ctx == NULL) {
			libreswan_log("seccomp_init() failed!");
			exit_pluto(PLUTO_EXIT_SECCOMP_FAIL);
	}

	/*
	 * read() and wait4() take the vast majority of syscall time
	 * So we place these at the head of the list for performance
	 * example strace -c -f output if pluto:
	 *
	 * % time     seconds  usecs/call     calls    errors syscall
	 * ------ ----------- ----------- --------- --------- ----------------
	 *   73.70   41.137940        1202     34232       343 read
	 *   20.77   11.595734        3549      3267      1176 wait4
	 *    1.47    0.819570         709      1156           epoll_wait
	 *    0.60    0.332147           1    319902           rt_sigprocmask
	 *    0.55    0.307552           5     61578           mmap
	 *    0.41    0.230820           6     37788      2877 open
	 *    [...]
	 */
	LSW_SECCOMP_ADD(ctx, read);
	if (main) {
		LSW_SECCOMP_ADD(ctx, wait4);
	}

#ifdef USE_EFENCE
	LSW_SECCOMP_ADD(ctx, madvise);
#endif

	/* needed for pluto and updown, not helpers */
	if (main) {
		LSW_SECCOMP_ADD(ctx, accept);
		LSW_SECCOMP_ADD(ctx, access);
		LSW_SECCOMP_ADD(ctx, bind);
		LSW_SECCOMP_ADD(ctx, brk);
		LSW_SECCOMP_ADD(ctx, chdir);
		LSW_SECCOMP_ADD(ctx, clone);
		LSW_SECCOMP_ADD(ctx, close);
		LSW_SECCOMP_ADD(ctx, connect);
		LSW_SECCOMP_ADD(ctx, dup);
		LSW_SECCOMP_ADD(ctx, dup2);
		LSW_SECCOMP_ADD(ctx, epoll_create);
		LSW_SECCOMP_ADD(ctx, epoll_ctl);
		LSW_SECCOMP_ADD(ctx, epoll_wait);
		LSW_SECCOMP_ADD(ctx, epoll_pwait);
		LSW_SECCOMP_ADD(ctx, execve);
		LSW_SECCOMP_ADD(ctx, faccessat);
		LSW_SECCOMP_ADD(ctx, fadvise64);
		LSW_SECCOMP_ADD(ctx, fcntl);
		LSW_SECCOMP_ADD(ctx, getcwd);
		LSW_SECCOMP_ADD(ctx, getdents);
		LSW_SECCOMP_ADD(ctx, getegid);
		LSW_SECCOMP_ADD(ctx, geteuid);
		LSW_SECCOMP_ADD(ctx, getgid);
		LSW_SECCOMP_ADD(ctx, getgroups);
		LSW_SECCOMP_ADD(ctx, getpgrp);
		LSW_SECCOMP_ADD(ctx, getpid);
		LSW_SECCOMP_ADD(ctx, getppid);
		LSW_SECCOMP_ADD(ctx, getrlimit);
		LSW_SECCOMP_ADD(ctx, getsockname);
		LSW_SECCOMP_ADD(ctx, getsockopt);
		LSW_SECCOMP_ADD(ctx, getuid);
		LSW_SECCOMP_ADD(ctx, ioctl);
		LSW_SECCOMP_ADD(ctx, lstat);
		LSW_SECCOMP_ADD(ctx, mkdir);
		LSW_SECCOMP_ADD(ctx, munmap);
		LSW_SECCOMP_ADD(ctx, newfstatat);
		LSW_SECCOMP_ADD(ctx, open);
		LSW_SECCOMP_ADD(ctx, openat);
		LSW_SECCOMP_ADD(ctx, pipe);
		LSW_SECCOMP_ADD(ctx, pipe2);
		LSW_SECCOMP_ADD(ctx, poll);
		LSW_SECCOMP_ADD(ctx, prctl);
		LSW_SECCOMP_ADD(ctx, pread64);
		LSW_SECCOMP_ADD(ctx, prlimit64);
		LSW_SECCOMP_ADD(ctx, readlink);
		LSW_SECCOMP_ADD(ctx, recvfrom);
		LSW_SECCOMP_ADD(ctx, recvmsg);
		LSW_SECCOMP_ADD(ctx, select);
		LSW_SECCOMP_ADD(ctx, sendmsg);
		LSW_SECCOMP_ADD(ctx, set_robust_list);
		LSW_SECCOMP_ADD(ctx, setsockopt);
		LSW_SECCOMP_ADD(ctx, socket);
		LSW_SECCOMP_ADD(ctx, socketcall);
		LSW_SECCOMP_ADD(ctx, socketpair);
		LSW_SECCOMP_ADD(ctx, sysinfo);
		LSW_SECCOMP_ADD(ctx, uname);
		LSW_SECCOMP_ADD(ctx, unlink);
		LSW_SECCOMP_ADD(ctx, unlinkat);
	}

	/* common to pluto and helpers */

	LSW_SECCOMP_ADD(ctx, arch_prctl);
	LSW_SECCOMP_ADD(ctx, exit_group);
	LSW_SECCOMP_ADD(ctx, gettid);
	LSW_SECCOMP_ADD(ctx, gettimeofday);
	LSW_SECCOMP_ADD(ctx, fstat);
	LSW_SECCOMP_ADD(ctx, futex);
	LSW_SECCOMP_ADD(ctx, lseek);
	LSW_SECCOMP_ADD(ctx, mmap);
	LSW_SECCOMP_ADD(ctx, mprotect);
	LSW_SECCOMP_ADD(ctx, nanosleep);
	LSW_SECCOMP_ADD(ctx, rt_sigaction);
	LSW_SECCOMP_ADD(ctx, rt_sigprocmask);
	LSW_SECCOMP_ADD(ctx, rt_sigreturn);
	LSW_SECCOMP_ADD(ctx, sched_setparam);
	LSW_SECCOMP_ADD(ctx, sendto);
	LSW_SECCOMP_ADD(ctx, set_tid_address);
	LSW_SECCOMP_ADD(ctx, sigaltstack);
	LSW_SECCOMP_ADD(ctx, sigreturn);
	LSW_SECCOMP_ADD(ctx, stat);
	LSW_SECCOMP_ADD(ctx, statfs);
	LSW_SECCOMP_ADD(ctx, clock_gettime);
	LSW_SECCOMP_ADD(ctx, waitpid);
	LSW_SECCOMP_ADD(ctx, write);

	int rc = seccomp_load(ctx);
	if (rc < 0) {
		LOG_ERRNO(-rc, "seccomp_load() failed!");
		seccomp_release(ctx);
		exit_pluto(PLUTO_EXIT_SECCOMP_FAIL);
	}

	libreswan_log("seccomp security enabled");
}
Ejemplo n.º 12
0
int main(int argc, char **argv)
{
    struct dt_dentry *probe;
    struct wdwk_dir curdir;
    int full = 0;
    int lookup = 0;
    char *host;
    int i;
    char *oldtree = NULL;
    FILE *oldfile;
    int port = 0;

    for (i = 1; i < argc; i++) {
        if (argv[i][0] != '-')
            break;
        if (argv[i][1] == '-' && argv[i][2] == 0) {
            i++;
            break;
        }
        switch (argv[i][1]) {
            case 'f':
                full = 1;
                break;
            case 'p':
                port = atoi(&argv[i][2]);
                break;
            case 'l':
                lookup = 1;
                break;
            case 'u':
                i++;
                if (i >= argc)
                    usage(argv[0], ESTAT_FAILURE);
                oldtree = argv[i];
                break;
            case 'h':
                usage(argv[0], ESTAT_SUCCESS);
            default:
                usage(argv[0], ESTAT_FAILURE);
        }
    }
    
    if (i + 1 != argc)
        usage(argv[0], ESTAT_FAILURE);

    ne_debug_init(stderr, 0);
    
    if (ne_sock_init()) {
        LOG_ERR("ne_sock_init() returned non-zero\n");
        exit(ESTAT_NOCONNECT);
    }

    host = argv[i];

    if (wdwk_open(&curdir, host, port) < 0)
        exit(ESTAT_NOCONNECT);

    if (lookup) {
        probe = wdwk_walker.readdir(&curdir);
        wdwk_close(&curdir);
        if (probe != NULL) {
            dt_free(probe);
            exit(ESTAT_SUCCESS);
        }
        else
            exit(ESTAT_FAILURE);
    }

    if (full)
        dt_full(&wdwk_walker, &curdir);
    else if (oldtree) {
        if ((oldfile = fopen(oldtree, "r")) == NULL) {
            LOG_ERRNO("Can't open file %s\n", oldtree);
            exit(ESTAT_FAILURE);
        }
        dt_diff(oldfile, &wdwk_walker, &curdir);
        fclose(oldfile);
    } else
        dt_reverse(&wdwk_walker, &curdir);

    wdwk_close(&curdir);
    ne_sock_exit();

    return ESTAT_SUCCESS;
}
Ejemplo n.º 13
0
ret_t
fdpoll_port_new (cherokee_fdpoll_t **fdp, int sys_limit, int limit)
{
	int                re;
	cuint_t            i;
	cherokee_fdpoll_t *nfd;
	CHEROKEE_CNEW_STRUCT (1, n, fdpoll_port);

	nfd = FDPOLL(n);

	/* Init base class properties
	 */
	nfd->type          = cherokee_poll_port;
	nfd->nfiles        = limit;
	nfd->system_nfiles = sys_limit;
	nfd->npollfds      = 0;

	/* Init base class virtual methods
	 */
	nfd->free          = (fdpoll_func_free_t) _free;
	nfd->add           = (fdpoll_func_add_t) _add;
	nfd->del           = (fdpoll_func_del_t) _del;
	nfd->reset         = (fdpoll_func_reset_t) _reset;
	nfd->set_mode      = (fdpoll_func_set_mode_t) _set_mode;
	nfd->check         = (fdpoll_func_check_t) _check;
	nfd->watch         = (fdpoll_func_watch_t) _watch;

	/* Allocate data
	 */
	n->port = -1;
	n->port_readyfds = 0;
	n->port_events   = (port_event_t *) calloc(nfd->nfiles, sizeof(port_event_t));
	n->port_activefd = (int *) calloc(nfd->system_nfiles, sizeof(int));

	if ( n->port_events == NULL || n->port_activefd == NULL ) {
		_free( n );
		return ret_nomem;
	}

	for (i=0; i < nfd->system_nfiles; i++) {
		n->port_activefd[i] = -1;
	}

	n->port = port_create();
	if (n->port == -1 ) {
		_free( n );
		return ret_error;
	}

	re = fcntl (n->port, F_SETFD, FD_CLOEXEC);
	if (re < 0) {
		LOG_ERRNO (errno, cherokee_err_error,
			   CHEROKEE_ERROR_FDPOLL_EPOLL_CLOEXEC);
		_free (n);
		return ret_error;
	}

	/* Return the object
	 */
	*fdp = nfd;
	return ret_ok;
}
Ejemplo n.º 14
0
int main(int argc, char **argv)
{
	static const char OPTIONS[] = "hvlpsjr:g:f::Ww:m:d:e:b:t:o:a:c:O:";
	__sighandler_t sigint_original;
	char * const *file_names = NULL;
	size_t n_files = 0;
	const char *waveform_id_str = NULL;
	int waveform_id;
	int do_enumerate_waveforms = 0;
	int do_log_info = 0;
	int do_wait_power_off = 0;
	int do_synchro = 0;
	int do_infinite_loop = 0;
	int cfa = -1;
	int do_auto_rotate = 0;
	int rotation_angle = -1;
	unsigned long pause_ms = 2000;
	const char *mode = NULL;
	const char *fbdev = NULL;
	const char *epdev = NULL;
	const char *background = NULL;
	struct plep_point offset = { 0, 0 };
	enum epdoc_align_h align_h = EPDOC_ALIGN_H_NONE;
	enum epdoc_align_v align_v = EPDOC_ALIGN_V_NONE;
	struct plep_rect crop = { { 0, 0 }, { INT_MAX, INT_MAX } };
	const char *doc_type = NULL;
	const char *conf_file = NULL;
	struct plep *plep;
	struct pldraw *pldraw;
	int c;
	int ret;

	while ((c = getopt(argc, argv, OPTIONS)) != -1) {
		switch (c) {
		case 'h':
			print_usage();
			exit(EXIT_SUCCESS);
			break;

		case 'v':
			printf("%s v%s - %s\n%s\n%s\n", APP_NAME, VERSION,
			       DESCRIPTION, COPYRIGHT, LICENSE);
			exit(EXIT_SUCCESS);
			break;

		case 'l':
			do_log_info = 1;
			break;

		case 'p':
			do_wait_power_off = 1;
			break;

		case 's':
			do_synchro = 1;
			break;

		case 'j':
			do_infinite_loop = 1;
			break;

		case 'r':
			if (!strcmp(optarg, "auto")) {
				do_auto_rotate = 1;
			} else {
				unsigned long raw_angle;

				if (str2ul(optarg, &raw_angle) < 0) {
					LOG("failed to parse rotation angle");
					print_usage();
					exit(EXIT_FAILURE);
				}

				if ((raw_angle > 270) || (raw_angle % 90)) {
					LOG("invalid rotation angle");
					print_usage();
					exit(EXIT_FAILURE);
				}

				rotation_angle = raw_angle;
			}
			break;

		case 'g':
			if (str2ul(optarg, &pause_ms) < 0) {
				LOG("failed to parse pause duration");
				print_usage();
				exit(EXIT_FAILURE);
			}
			break;

		case 'f':
			if (optarg == NULL) {
				cfa = PLDRAW_CFA_GR_BW;
			} else {
				cfa = pldraw_get_cfa_id(optarg);

				if (cfa < 0) {
					LOG("Invalid CFA identifier: %s",
					    optarg);
					print_usage();
					exit(EXIT_FAILURE);
				}
			}
			break;

		case 'W':
			do_enumerate_waveforms = 1;
			break;

		case 'w':
			waveform_id_str = optarg;
			break;

		case 'm':
			mode = optarg;
			break;

		case 'd':
			fbdev = optarg;
			break;

		case 'e':
			epdev = optarg;
			break;

		case 'b':
			background = optarg;
			break;

		case 't':
			doc_type = optarg;
			break;

		case 'o':
			if (parse_offset(&offset, optarg) < 0) {
				print_usage();
				exit(EXIT_FAILURE);
			}
			break;

		case 'a':
			if (parse_alignment(&align_h, &align_v, optarg) < 0) {
				print_usage();
				exit(EXIT_FAILURE);
			}
			break;

		case 'c':
			if (parse_crop(&crop, optarg) < 0) {
				print_usage();
				exit(EXIT_FAILURE);
			}
			break;

		case 'O':
			conf_file = optarg;
			if (access(conf_file, F_OK)) {
				LOG_ERRNO("Configuration file");
				exit(EXIT_FAILURE);
			}
			break;

		case '?':
		default:
			LOG("Invalid arguments");
			print_usage();
			exit(EXIT_FAILURE);
			break;
		}
	}

	if (optind < argc) {
		file_names = &argv[optind];
		n_files = argc - optind;
	}

	LOG("%s v%s", APP_NAME, VERSION);

	plep = plep_init(epdev, mode, conf_file);

	if (plep == NULL) {
		LOG("failed to initialise ePDC");
		goto error_plep;
	}

	pldraw = pldraw_init(fbdev, conf_file);

	if (pldraw == NULL) {
		LOG("failed to initialise pldraw");
		goto error_pldraw;
	}

	pldraw_set_plep(pldraw, plep);

	waveform_id = plep_get_wfid(plep, waveform_id_str);

	if (waveform_id < 0) {
		LOG("Invalid waveform path: %s", waveform_id_str);
		goto error_pldraw;
	}

	if (cfa >= 0)
		pldraw_set_cfa(pldraw, cfa);
	else
		cfa = pldraw_get_cfa(pldraw);

	if (cfa != PLDRAW_CFA_NONE)
		LOG("CFA: %s", pldraw_cfa_name[cfa]);

	if (rotation_angle < 0)
		rotation_angle = pldraw_get_rotation(pldraw);

	if (rotation_angle)
		LOG("rotation: %d", rotation_angle);

	if (do_log_info)
		pldraw_log_info(pldraw);

	sigint_original = signal(SIGINT, sigint_abort);

	if (do_enumerate_waveforms) {
		ret = enumerate_waveforms(plep);
	} else {
		struct epdoc_opt opt;

		plep_set_opt(plep, PLEP_SYNC_UPDATE, do_synchro);

		if (do_wait_power_off)
			plep_set_opt(plep, PLEP_WAIT_POWER_OFF, 1);

		opt.do_auto_rotate = do_auto_rotate;
		opt.rotation_angle = rotation_angle;
		opt.wfid = waveform_id;
		opt.offset.x = offset.x;
		opt.offset.y = offset.y;
		opt.align_h = align_h;
		opt.align_v = align_v;
		memcpy(&opt.crop, &crop, sizeof opt.crop);
		opt.doc_type = doc_type;

		ret = show_contents(pldraw, file_names, n_files, &opt,
				    pause_ms, do_infinite_loop, background);
	}

	signal(SIGINT, sigint_original);
	pldraw_free(pldraw);
	plep_free(plep);

	exit((ret < 0) ? EXIT_FAILURE : EXIT_SUCCESS);

error_pldraw:
	plep_free(plep);
error_plep:
	exit(EXIT_FAILURE);
}