Пример #1
0
/*
 * Traverse the file system in the level-order way.  The description
 * and example is in the header file.
 */
int
traverse_level(struct fs_traverse *ftp)
{
	char path[PATH_MAX + 1];	/* full path name of the current dir */
	char nm[NAME_MAX + 1];	/* directory entry name */
	char *lp;		/* last position on the path */
	int next_dir, rv;
	int pl, el;		/* path and directory entry length */

	cstack_t *sp;
	fs_fhandle_t pfh, efh;
	struct stat64 pst, est;
	traverse_state_t *tsp;
	struct fst_node pn, en;  /* parent and entry nodes */
	dent_arg_t darg;

	if (!ftp || !ftp->ft_path || !*ftp->ft_path || !ftp->ft_callbk) {
		NDMP_LOG(LOG_DEBUG, "Invalid argument");
		errno = EINVAL;
		return (-1);
	}
	/* set the default log function if it's not already set */
	if (!ftp->ft_logfp) {
		ftp->ft_logfp = (ft_log_t)syslog;
		NDMP_LOG(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
	}
	if (!ftp->ft_lpath) {
		NDMP_LOG(LOG_DEBUG,
		    "report the same paths \"%s\"", ftp->ft_path);
		ftp->ft_lpath = ftp->ft_path;
	}

	pl = strlen(ftp->ft_lpath);
	if (pl + 1 > PATH_MAX) { /* +1 for the '/' */
		NDMP_LOG(LOG_DEBUG, "lpath too long \"%s\"", ftp->ft_path);
		errno = ENAMETOOLONG;
		return (-1);
	}
	(void) strcpy(path, ftp->ft_lpath);
	(void) memset(&pfh, 0, sizeof (pfh));
	rv = fs_getstat(ftp->ft_lpath, &pfh, &pst);
	if (rv != 0) {
		NDMP_LOG(LOG_DEBUG,
		    "Error %d on fs_getstat(%s)", rv, ftp->ft_path);
		return (-1);
	}

	en.tn_path = NULL;
	en.tn_fh = NULL;
	en.tn_st = NULL;
	if (!S_ISDIR(pst.st_mode)) {
		pn.tn_path = ftp->ft_lpath;
		pn.tn_fh = &pfh;
		pn.tn_st = &pst;
		rv = CALLBACK(&pn, &en);
		if (VERBOSE(ftp))
			NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);

		free(pfh.fh_fpath);
		return (rv);
	}

	sp = cstack_new();
	if (!sp) {
		free(pfh.fh_fpath);
		errno = ENOMEM;
		return (-1);
	}
	tsp = new_tsp(path);
	if (!tsp) {
		cstack_delete(sp);
		free(pfh.fh_fpath);
		errno = ENOMEM;
		return (-1);
	}

	darg.da_buf = ndmp_malloc(MAX_DENT_BUF_SIZE);
	if (!darg.da_buf) {
		cstack_delete(sp);
		free(pfh.fh_fpath);
		free(tsp);
		errno = ENOMEM;
		return (-1);
	}
	darg.da_size = MAX_DENT_BUF_SIZE;

	tsp->ts_ent = tsp->ts_end;
	tsp->ts_fh = pfh;
	tsp->ts_st = pst;
	pn.tn_path = path;
	pn.tn_fh = &tsp->ts_fh;
	pn.tn_st = &tsp->ts_st;

	/* call the callback function on the path itself */
	traverse_stats.fss_dir_calls++;
	rv = CALLBACK(&pn, &en);
	if (rv < 0) {
		free(tsp);
		goto end;
	}
	if (rv == FST_SKIP) {
		traverse_stats.fss_dir_skipped++;
		free(tsp);
		rv = 0;
		goto end;
	}

	rv = 0;
	next_dir = 1;
	do {
		if (next_dir) {
			traverse_stats.fss_newdirs++;

			*tsp->ts_end = '\0';
			if (VERBOSE(ftp))
				NDMP_LOG(LOG_DEBUG, "pl %d \"%s\"", pl, path);

			rv = traverse_level_nondir(ftp, tsp, &pn, &darg);
			if (rv < 0) {
				NEGATE(rv);
				free(tsp->ts_fh.fh_fpath);
				free(tsp);
				break;
			}
			/*
			 * If skipped by the callback function or
			 * error happened reading the information
			 */
			if (rv == FST_SKIP || rv == SKIP_ENTRY) {
				/*
				 * N.B. next_dir should be set to 0 as
				 * well. This prevents the infinite loop.
				 * If it's not set the same directory will
				 * be poped from the stack and will be
				 * scanned again.
				 */
				next_dir = 0;
				rv = 0;
				goto skip_dir;
			}

			/* re-start reading entries of the directory */
			tsp->ts_dpos = 0;
		}

		next_dir = 0;
		do {
			el = NAME_MAX;
			rv = fs_readdir(&tsp->ts_fh, pn.tn_path,
			    &tsp->ts_dpos, nm, &el, &efh,
			    &est);
			if (rv != 0) {
				traverse_stats.fss_readdir_err++;

				NDMP_LOG(LOG_DEBUG,
				    "Error %d on readdir(%s) pos %d",
				    rv, path, tsp->ts_dpos);
				if (STOP_ONERR(ftp))
					break;
				rv = SKIP_ENTRY;
				continue;
			}

			/* done with this directory */
			if (el == 0)
				break;

			nm[el] = '\0';

			if (rootfs_dot_or_dotdot(nm)) {
				free(efh.fh_fpath);
				continue;
			}

			if (VERBOSE(ftp))
				NDMP_LOG(LOG_DEBUG, "%u dname: \"%s\"",
				    tsp->ts_dpos, nm);

			if (pl + 1 + el > PATH_MAX) {
				/*
				 * The long paths were already encountered
				 * when processing non-dir entries in.
				 * traverse_level_nondir.
				 * We don't increase fss_longpath_err
				 * counter for them again here.
				 */
				NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
				    path, nm);
				if (STOP_ONLONG(ftp))
					rv = ENAMETOOLONG;
				free(efh.fh_fpath);
				continue;
			}

			if (!S_ISDIR(est.st_mode))
				continue;

			/*
			 * Call the callback function for the new
			 * directory found, then push the current
			 * directory on to the stack.  Then dive
			 * into the entry found.
			 */
			traverse_stats.fss_dir_calls++;
			en.tn_path = nm;
			en.tn_fh = &efh;
			en.tn_st = &est;
			rv = CALLBACK(&pn, &en);

			if (rv < 0) {
				NEGATE(rv);
				free(efh.fh_fpath);
				break;
			}
			if (rv == FST_SKIP) {
				traverse_stats.fss_dir_skipped++;
				free(efh.fh_fpath);
				rv = 0;
				continue;
			}

			/*
			 * Push the current directory on to the stack and
			 * dive into the entry found.
			 */
			if (cstack_push(sp, tsp, 0)) {
				rv = ENOMEM;
			} else {
				traverse_stats.fss_pushes++;

				lp = tsp->ts_end;
				*tsp->ts_end = '/';
				(void) strcpy(tsp->ts_end + 1, nm);

				tsp = new_tsp(path);
				if (!tsp)
					rv = ENOMEM;
				else {
					next_dir = 1;
					pl += el + 1;
					tsp->ts_fh = efh;
					tsp->ts_st = est;
					tsp->ts_ent = lp;
					pn.tn_fh = &tsp->ts_fh;
					pn.tn_st = &tsp->ts_st;
				}
			}
			break;

		} while (rv == 0);

		/*
		 * A new directory must be processed, go to the start of
		 * the loop, open it and process it.
		 */
		if (next_dir)
			continue;
skip_dir:
		if (tsp) {
			free(tsp->ts_fh.fh_fpath);
			free(tsp);
		}

		if (rv == SKIP_ENTRY)
			rv = 0;

		if (rv == 0) {
			if (cstack_pop(sp, (void **)&tsp, (int *)NULL))
				break;

			traverse_stats.fss_pops++;

			if (VERBOSE(ftp))
				NDMP_LOG(LOG_DEBUG,
				    "Poped pl %d \"%s\"", pl, path);

			*tsp->ts_end = '\0';
			pl = tsp->ts_end - path;
			pn.tn_fh = &tsp->ts_fh;
			pn.tn_st = &tsp->ts_st;
		}
	} while (rv == 0);

	/*
	 * Pop and free all the remaining entries on the stack.
	 */
	while (!cstack_pop(sp, (void **)&tsp, (int *)NULL)) {
		traverse_stats.fss_stack_residue++;

		free(tsp->ts_fh.fh_fpath);
		free(tsp);
	}
end:
	free(darg.da_buf);
	cstack_delete(sp);
	return (rv);
}
Пример #2
0
long GalleryUtil::GetNaturalRotation(const QString &filePathString)
{
    long rotateAngle = 0;
#ifdef EXIF_SUPPORT
    QByteArray filePathBA = filePathString.toLocal8Bit();
    const char *filePath = filePathBA.constData();

    try
    {
        char *exifvalue = new char[1024];
        ExifData *data = exif_data_new_from_file (filePath);
        if (data)
        {
            for (int i = 0; i < EXIF_IFD_COUNT; i++)
            {
                ExifEntry *entry = exif_content_get_entry (data->ifd[i],
                                                        EXIF_TAG_ORIENTATION);
                ExifByteOrder byteorder = exif_data_get_byte_order (data);

                if (entry)
                {
                    ExifShort v_short = exif_get_short (entry->data, byteorder);
                    VERBOSE(VB_GENERAL|VB_EXTRA, QString("Exif entry=%1").arg(v_short));
                    /* See http://sylvana.net/jpegcrop/exif_orientation.html*/
                    if (v_short == 8)
                    {
                        rotateAngle = -90;
                    }
                    else if (v_short == 6)
                    {
                        rotateAngle = 90;
                    }
                    break;
                }
            }
            exif_data_free(data);
        }
        else
        {
            VERBOSE(VB_FILE, LOC_ERR +
                    QString("Could not load exif data from '%1'")
                    .arg(filePath));
        }
        
        delete [] exifvalue;
        
#if 0
        Exiv2::ExifData exifData;
        int rc = exifData.read(filePath);
        if (!rc)
        {
            Exiv2::ExifKey key = Exiv2::ExifKey("Exif.Image.Orientation");
            Exiv2::ExifData::iterator pos = exifData.findKey(key);
            if (pos != exifData.end())
            {
                long orientation = pos->toLong();
                switch (orientation)
                {
                    case 6:
                        rotateAngle = 90;
                        break;
                    case 8:
                        rotateAngle = -90;
                        break;
                    default:
                        rotateAngle = 0;
                        break;
                }
            }
        }
#endif
    }
    catch (...)
    {
        VERBOSE(VB_IMPORTANT, LOC_ERR +
                QString("Failed to extract EXIF headers from '%1'")
                .arg(filePathString));
    }

#else
    // Shut the compiler up about the unused argument
    (void)filePathString;
#endif // EXIF_SUPPORT
    return rotateAngle;
}
Пример #3
0
int main (int argc, char **argv)
{
#ifdef CC_HAVE_WIN_UTF8
    // UTF8 argv. g_win_utf8_enabled affects cc_fopen and cc_fprintf
    argv = win_utf8_argv(argc, argv, &g_win_utf8_enabled);
#endif

    int rv = 1;
    int needs_usage_on_err = 1;

    int opt_verbose = 0;
    int opt_overwrite = 0;
    int opt_progress = 0;
    int opt_dummy = 0;

    char *in_name = NULL;
    char *out_name = NULL;
    FILE *in_file = NULL;
    FILE *out_file = NULL;

    int i = 0;

    opterr = 0; // suppress getopt error prints, we're handling them.
    int c;
    while (1) {
        // This is weird. GNU getopt can be made to work in POSIX compliant mode,
        // but in a way which breaks POSIX compliance...
        // We want to use getopt in standard posix mode, where it doesn't
        // permute argv, and returns -1 when it encounters a non-option.
        // GNU getopt doesn't default to posix mode. It uses posix mode either
        // when the env POSIXLY_CORRECT is set, or when optstring starts with +.
        // But + prefix is a GNU extension - proper posix getopt don't recognize
        // it as an indicator, therefore interpreting it as a valid option char.
        // So to cover both variants, we use the '+' to make GNU posix compliant,
        // but also expect it and then and reject it as an unknown option on posix getopt.
        if ((c = getopt (argc, argv, "+hdvfpo:")) != -1) {
            switch (c) {
                case 'h': help();
                          exit(0);

                case 'v': opt_verbose = 1;
                          break;

                case 'f': opt_overwrite = 1;
                          break;

                case 'p': opt_progress = 1;
                          break;

                case 'd': opt_dummy = 1;
                          break;

                case 'o': out_name = optarg;
                          // Will also exit the while loop and start the ranges
                          break;

                case '+': optopt = '+'; // fallthrough - proper POSIX (bsd, OS X, ...)
                case '?': if (optopt == 'o')
                              ERR_EXIT("-o: missing output file name");
                          ERR_EXIT("unknown option -%c%s", optopt,
                                   (optopt >= '0' && optopt <= '9') ?
                                      " (missing -o OUT_FILE before the ranges?)" : "");

                default : ERR_EXIT("(Internal) getopt - unexpected code %d", c);
            }

        } else if (optind < argc) { // still more arguments, so it's a value
            if (!in_name) {
                // still no input file, so this is it.
                in_name = argv[optind];
                optind++; // skip the value and continue parsing.

            } else {
                ERR_EXIT("unexpected '%s' (missing -o OUT_FILE before the ranges?)", argv[optind]);
            }

        } else { // no more arguments to parse
            break;
        }

        if (out_name)  // Once we got the output file, the rest should be ranges
            break;
    }
    // from here onwards, optind should point to the first range in argv

    VERBOSE("- Verbose mode enabled.\n");

    if (opt_overwrite)
        VERBOSE("- Force overwrite output file if exists.\n");

    if (opt_progress)
        VERBOSE("- Progress display enabled.\n");

    if (opt_dummy)
        VERBOSE("- Dummy mode enabled.\n");

    if (!in_name)
        ERR_EXIT("missing input file name");

    if (!out_name)
        ERR_EXIT("missing output file name");

    if (optind == argc)
        ERR_EXIT("no ranges defined, must have at least one range");

    // Input file - verify, open and read size
    cc_off_t in_size = fsize(in_name);
    in_file = cc_fopen(in_name, "rb");
    if (in_size < 0 || !in_file)
        ERR_EXIT("input file '%s' cannot be opened", in_name);
    VERBOSE("-   Input file: '%s', size: %lld\n", in_name, (long long)in_size);

    // verify ranges and calculate expected output size
    cc_off_t expected_output_size = 0;
    cc_off_t prev_to = 0;
    for (i = optind; i < argc; i++) {
        range_t range;
        if (!get_range(in_size, prev_to, argv[i], &range))
            ERR_EXIT("invalid range '%s'", argv[i]);
        expected_output_size += range.to - range.from;
        prev_to = range.to;
        VERBOSE("-   Range #%d: '%s' -> [%lld, %lld) -> %lld bytes\n",
                i - optind + 1,
                argv[i],
                (long long)range.from,
                (long long)range.to,
                (long long)(range.to - range.from)
                );
    }

    if (opt_dummy) {
        VERBOSE("- Done - dummy mode - skipped copying %lld bytes to '%s'%s.\n",
                (long long)expected_output_size, out_name,
                strcmp(out_name, "-") ? "" : " (stdout)");
        rv = 0;
        goto exit_L;
    }

    // open/setup output
    if (!strcmp(out_name, "-")) {
        out_file = stdout;

#ifdef _WIN32
        // change stdout to binary mode, or else it messes with EOL chars
        if (_setmode(_fileno(stdout), O_BINARY) == -1)
            ERR_EXIT("cannot set stdout to binary mode");
#endif

    } else {
        FILE *tmp = cc_fopen(out_name, "r");
        if (tmp) {
            fclose(tmp);
            if (!opt_overwrite)
                ERR_EXIT("output file '%s' exists, use -f to force overwrite", out_name);
        }

        out_file = cc_fopen(out_name, "wb");
        if (!out_file)
            ERR_EXIT("output file '%s' cannot be created", out_name);
    }


    // args are valid, input file is valid, output file created. Start copy
    needs_usage_on_err = 0;
    VERBOSE("- About to copy overall %lld bytes to '%s'%s ...\n",
            (long long)expected_output_size, out_name,
            strcmp(out_name, "-") ? "" : " (stdout)");

    char buf[RW_BUFFSIZE];
    cc_off_t total_processed = 0;
    prev_to = 0;

    for (i = optind; (i < argc) && expected_output_size; i++) {
        range_t range;
        if (!get_range(in_size, prev_to, argv[i], &range))
            ERR_EXIT("(Internal): range became invalid?! '%s'", argv[i]);
        prev_to = range.to;

        if (cc_fseek(in_file, range.from, SEEK_SET))
            ERR_EXIT("cannot seek input file to offset %lld", (long long)range.from);

        cc_off_t toread = range.to - range.from;
        while (toread) {
            size_t single_read = (size_t)(cc_min(toread, (cc_off_t)RW_BUFFSIZE));
            size_t got = fread(buf, 1, single_read, in_file);
            if (ferror(in_file) || got != single_read)
                ERR_EXIT("cannot read from input file");

            if (got != fwrite(buf, 1, got, out_file))
                ERR_EXIT("cannot write to output file");

            toread -= got;
            total_processed += got;

            if (opt_progress) {
                int percent = (int)((double)total_processed / expected_output_size * 100);
                int prev_percent = (int)((double)(total_processed - got) / expected_output_size * 100);

                if (percent / PROGRESS_PER != prev_percent / PROGRESS_PER)
                    cc_fprintf(stderr, " %d%% ", percent);
                else if (percent / PROGRESS_DOT != prev_percent / PROGRESS_DOT)
                    cc_fprintf(stderr, ".");
            }
        }
    }

    if (opt_progress) {
        if (!expected_output_size)
            cc_fprintf(stderr, " %d%% ", 100);
        cc_fprintf(stderr, "\n");
    }

    // success
    VERBOSE("- Done.\n");
    rv = 0;

exit_L:
    if (in_file)
        fclose(in_file);
    if (out_file && out_file != stdout)
        fclose(out_file);

    if (rv && needs_usage_on_err) {
        cc_fprintf(stderr, "\n");
        usage();
    }

#ifdef CC_HAVE_WIN_UTF8
    if (g_win_utf8_enabled)
        free_argvutf8(argc, argv);
#endif

    return rv;
}
/*
 * Read a directory, using filldir to fill the dirent memory.
 * smb_proc_readdir does the actual reading from the smb server.
 *
 * The cache code is almost directly taken from ncpfs
 */
static int 
smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
	struct dentry *dentry = filp->f_dentry;
	struct inode *dir = dentry->d_inode;
	struct smb_sb_info *server = server_from_dentry(dentry);
	union  smb_dir_cache *cache = NULL;
	struct smb_cache_control ctl;
	struct page *page = NULL;
	int result;

	ctl.page  = NULL;
	ctl.cache = NULL;

	VERBOSE("reading %s/%s, f_pos=%d\n",
		DENTRY_PATH(dentry),  (int) filp->f_pos);

	result = 0;

	lock_kernel();

	switch ((unsigned int) filp->f_pos) {
	case 0:
		if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0)
			goto out;
		filp->f_pos = 1;
		/* fallthrough */
	case 1:
		if (filldir(dirent, "..", 2, 1, parent_ino(dentry), DT_DIR) < 0)
			goto out;
		filp->f_pos = 2;
	}

	/*
	 * Make sure our inode is up-to-date.
	 */
	result = smb_revalidate_inode(dentry);
	if (result)
		goto out;


	page = grab_cache_page(&dir->i_data, 0);
	if (!page)
		goto read_really;

	ctl.cache = cache = kmap(page);
	ctl.head  = cache->head;

	if (!PageUptodate(page) || !ctl.head.eof) {
		VERBOSE("%s/%s, page uptodate=%d, eof=%d\n",
			 DENTRY_PATH(dentry), PageUptodate(page),ctl.head.eof);
		goto init_cache;
	}

	if (filp->f_pos == 2) {
		if (jiffies - ctl.head.time >= SMB_MAX_AGE(server))
			goto init_cache;

		/*
		 * N.B. ncpfs checks mtime of dentry too here, we don't.
		 *   1. common smb servers do not update mtime on dir changes
		 *   2. it requires an extra smb request
		 *      (revalidate has the same timeout as ctl.head.time)
		 *
		 * Instead smbfs invalidates its own cache on local changes
		 * and remote changes are not seen until timeout.
		 */
	}

	if (filp->f_pos > ctl.head.end)
		goto finished;

	ctl.fpos = filp->f_pos + (SMB_DIRCACHE_START - 2);
	ctl.ofs  = ctl.fpos / SMB_DIRCACHE_SIZE;
	ctl.idx  = ctl.fpos % SMB_DIRCACHE_SIZE;

	for (;;) {
		if (ctl.ofs != 0) {
			ctl.page = find_lock_page(&dir->i_data, ctl.ofs);
			if (!ctl.page)
				goto invalid_cache;
			ctl.cache = kmap(ctl.page);
			if (!PageUptodate(ctl.page))
				goto invalid_cache;
		}
		while (ctl.idx < SMB_DIRCACHE_SIZE) {
			struct dentry *dent;
			int res;

			dent = smb_dget_fpos(ctl.cache->dentry[ctl.idx],
					     dentry, filp->f_pos);
			if (!dent)
				goto invalid_cache;

			res = filldir(dirent, dent->d_name.name,
				      dent->d_name.len, filp->f_pos,
				      dent->d_inode->i_ino, DT_UNKNOWN);
			dput(dent);
			if (res)
				goto finished;
			filp->f_pos += 1;
			ctl.idx += 1;
			if (filp->f_pos > ctl.head.end)
				goto finished;
		}
		if (ctl.page) {
			kunmap(ctl.page);
			SetPageUptodate(ctl.page);
			unlock_page(ctl.page);
			page_cache_release(ctl.page);
			ctl.page = NULL;
		}
		ctl.idx  = 0;
		ctl.ofs += 1;
	}
invalid_cache:
	if (ctl.page) {
		kunmap(ctl.page);
		unlock_page(ctl.page);
		page_cache_release(ctl.page);
		ctl.page = NULL;
	}
	ctl.cache = cache;
init_cache:
	smb_invalidate_dircache_entries(dentry);
	ctl.head.time = jiffies;
	ctl.head.eof = 0;
	ctl.fpos = 2;
	ctl.ofs = 0;
	ctl.idx = SMB_DIRCACHE_START;
	ctl.filled = 0;
	ctl.valid  = 1;
read_really:
	result = server->ops->readdir(filp, dirent, filldir, &ctl);
	if (result == -ERESTARTSYS && page)
		ClearPageUptodate(page);
	if (ctl.idx == -1)
		goto invalid_cache;	/* retry */
	ctl.head.end = ctl.fpos - 1;
	ctl.head.eof = ctl.valid;
finished:
	if (page) {
		cache->head = ctl.head;
		kunmap(page);
		if (result != -ERESTARTSYS)
			SetPageUptodate(page);
		unlock_page(page);
		page_cache_release(page);
	}
	if (ctl.page) {
		kunmap(ctl.page);
		SetPageUptodate(ctl.page);
		unlock_page(ctl.page);
		page_cache_release(ctl.page);
	}
out:
	unlock_kernel();
	return result;
}
Пример #5
0
int main()
{

	int an_int;
	SQLUSMALLINT num_cols;
	float a_float;
	SQLCHAR buf1[MAX_LEN];
	SQLCHAR buf2[MAX_LEN];

	SQLUSMALLINT col;
	SQLSMALLINT col_len;
	SQLSMALLINT type;
	SQLUINTEGER sz;
	SQLSMALLINT scale;
	SQLSMALLINT can_null;

	GET_LOGIN_VARS();

	VERBOSE("calling SQLAllocHandle(EnvHandle) \n");

	rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &EnvHandle);
	assert(rc == SQL_SUCCESS);
	assert(EnvHandle != (SQLHANDLE) NULL);

	rc = SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION,
			   (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

	assert(rc == SQL_SUCCESS);

	VERBOSE("calling SQLAllocHandle(ConHandle) \n");

	rc = SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle, &ConHandle);
	assert(ConHandle != (SQLHANDLE) NULL);
	assert(rc == SQL_SUCCESS);

	if (dsn[0])
		rc = SQLDriverConnect(ConHandle, NULL, dsn,
				      SQL_NTS, NULL, 0, NULL,
				      SQL_DRIVER_NOPROMPT);
	else
		rc = SQLConnect(ConHandle, twoTask, SQL_NTS,
				(SQLCHAR *) userName, SQL_NTS, (SQLCHAR *) pswd,
				SQL_NTS);
	assert(rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO);

	VERBOSE("connected to  database %s\n", twoTask);
	VERBOSE("allocing handle\n");

	rc = SQLAllocStmt(ConHandle, &StmtHandle);
	assert(rc == SQL_SUCCESS);

	sprintf(SQLStmt, "select max(an_int) from some_types");

	VERBOSE("executing %s\n", SQLStmt);

	rc = SQLExecDirect(StmtHandle, SQLStmt, SQL_NTS);
	assert(rc == SQL_SUCCESS);

	rc = SQLNumResultCols(StmtHandle, &num_cols);
	assert(rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO);
	assert(num_cols == 1);

	for (col = 1; col <= num_cols; col++) {
		rc = SQLDescribeCol(StmtHandle, col, buf1, MAX_LEN, &col_len,
				    &type, &sz, &scale, &can_null);

		assert(rc == SQL_SUCCESS);

		VERBOSE
		    ("col=%d name:%s len=%d type=%d size=%d scale=%d nullable=%d\n",
		     col, buf1, col_len, type, sz, scale, can_null);

		/*
		   if(col==1)assert(type==SQL_INTEGER);
		   if(col==2)assert(type==SQL_C_DOUBLE);
		   if(col==3)assert(type==SQL_VARCHAR);
		 */

		rc = SQLColAttribute(StmtHandle, col, SQL_DESC_NAME,
				     buf2, sizeof(buf2), &type, NULL);

		assert(rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO);
		assert(strcmp(buf1, buf2) == 0);

	}

	rc = SQLBindCol(StmtHandle, 1, SQL_C_SLONG,
			&an_int, sizeof(an_int), NULL);
	assert(rc == SQL_SUCCESS);

	do {
		rc = SQLFetch(StmtHandle);
		VERBOSE("an_int=%d \n", an_int);
	} while (rc == SQL_SUCCESS);

	assert(rc == SQL_NO_DATA);
	assert(an_int > 0);

	rc = SQLDisconnect(ConHandle);
	assert(rc == SQL_SUCCESS);
	VERBOSE("disconnected from  database\n");

	VERBOSE("calling SQLFreeHandle(ConHandle) \n");

	assert(ConHandle != (SQLHANDLE) NULL);
	rc = SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);
	assert(rc == SQL_SUCCESS);

	VERBOSE("calling SQLFreeHandle(EnvHandle) \n");

	assert(EnvHandle != (SQLHANDLE) NULL);
	rc = SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);
	assert(rc == SQL_SUCCESS);

	return (rc);
}
Пример #6
0
bool AudioOutputPulseAudio::ConnectPlaybackStream(void)
{
    QString fn_log_tag = "ConnectPlaybackStream, ";
    pstream = pa_stream_new(pcontext, "MythTV playback", &sample_spec,
                            &channel_map);
    if (!pstream)
    {
        VBERROR(fn_log_tag + QString("failed to create new playback stream"));
        return false;
    }
    pa_stream_set_state_callback(pstream, StreamStateCallback, this);
    pa_stream_set_write_callback(pstream, WriteCallback, this);
    pa_stream_set_overflow_callback(pstream, BufferFlowCallback, (char*)"over");
    pa_stream_set_underflow_callback(pstream, BufferFlowCallback,
                                     (char*)"under");
    if (set_initial_vol)
    {
        int volume = gCoreContext->GetNumSetting("MasterMixerVolume", 80);
        pa_cvolume_set(&volume_control, channels,
                       (float)volume * (float)PA_VOLUME_NORM / 100.0f);
    }
    else
        pa_cvolume_reset(&volume_control, channels);

    fragment_size = (samplerate * 25 * output_bytes_per_frame) / 1000;

    buffer_settings.maxlength = (uint32_t)-1;
    buffer_settings.tlength = fragment_size * 4;
    buffer_settings.prebuf = (uint32_t)-1;
    buffer_settings.minreq = (uint32_t)-1;

    int flags = PA_STREAM_INTERPOLATE_TIMING
        | PA_STREAM_ADJUST_LATENCY
        | PA_STREAM_AUTO_TIMING_UPDATE
        | PA_STREAM_NO_REMIX_CHANNELS;

    pa_stream_connect_playback(pstream, NULL, &buffer_settings,
                               (pa_stream_flags_t)flags, &volume_control, NULL);

    pa_context_state_t cstate;
    pa_stream_state_t sstate;
    bool connected = false, failed = false;

    while (!(connected || failed))
    {
        switch (cstate = pa_context_get_state(pcontext))
        {
            case PA_CONTEXT_FAILED:
            case PA_CONTEXT_TERMINATED:
                VERBOSE(VB_IMPORTANT, LOC_ERR + fn_log_tag +
                        QString("context is stuffed, %1")
                        .arg(pa_strerror(pa_context_errno(
                                             pcontext))));
                failed = true;
                break;
            default:
                switch (sstate = pa_stream_get_state(pstream))
                {
                    case PA_STREAM_READY:
                        connected = true;
                        break;
                    case PA_STREAM_FAILED:
                    case PA_STREAM_TERMINATED:
                        VBERROR(fn_log_tag +
                                QString("stream failed or was terminated, "
                                        "context state %1, stream state %2")
                                .arg(cstate).arg(sstate));
                        failed = true;
                        break;
                    default:
                        pa_threaded_mainloop_wait(mainloop);
                        break;
                }
        }
    }

    const pa_buffer_attr *buf_attr = pa_stream_get_buffer_attr(pstream);
    fragment_size = buf_attr->tlength >> 2;
    soundcard_buffer_size = buf_attr->maxlength;

    VBAUDIO(fn_log_tag + QString("fragment size %1, soundcard buffer size %2")
                         .arg(fragment_size).arg(soundcard_buffer_size));

    return (connected && !failed);
}
Пример #7
0
/**
 * Process a sentence with xml annotation
 * Xml tags may specifiy additional/replacing translation options
 * and reordering constraints
 *
 * \param line in: sentence, out: sentence without the xml
 * \param res vector with translation options specified by xml
 * \param reorderingConstraint reordering constraint zones specified by xml
 * \param walls reordering constraint walls specified by xml
 */
bool TreeInput::ProcessAndStripXMLTags(string &line, std::vector<XMLParseOutput> &sourceLabels, std::vector<XmlOption*> &xmlOptions)
{
    //parse XML markup in translation line

    // no xml tag? we're done.
    if (line.find_first_of('<') == string::npos) {
        return true;
    }

    // hack. What pt should XML trans opt be assigned to?
    PhraseDictionary *firstPt = NULL;
    if (PhraseDictionary::GetColl().size() == 0) {
        firstPt = PhraseDictionary::GetColl()[0];
    }

    // break up input into a vector of xml tags and text
    // example: (this), (<b>), (is a), (</b>), (test .)
    vector<string> xmlTokens = TokenizeXml(line);

    // we need to store opened tags, until they are closed
    // tags are stored as tripled (tagname, startpos, contents)
    typedef pair< string, pair< size_t, string > > OpenedTag;
    vector< OpenedTag > tagStack; // stack that contains active opened tags

    string cleanLine; // return string (text without xml)
    size_t wordPos = 0; // position in sentence (in terms of number of words)

    // keep this handy for later
    const vector<FactorType> &outputFactorOrder = StaticData::Instance().GetOutputFactorOrder();
    // const string &factorDelimiter = StaticData::Instance().GetFactorDelimiter();

    // loop through the tokens
    for (size_t xmlTokenPos = 0 ; xmlTokenPos < xmlTokens.size() ; xmlTokenPos++) {
        // not a xml tag, but regular text (may contain many words)
        if(!isXmlTag(xmlTokens[xmlTokenPos])) {
            // add a space at boundary, if necessary
            if (cleanLine.size()>0 &&
                    cleanLine[cleanLine.size() - 1] != ' ' &&
                    xmlTokens[xmlTokenPos][0] != ' ') {
                cleanLine += " ";
            }
            cleanLine += xmlTokens[xmlTokenPos]; // add to output
            wordPos = Tokenize(cleanLine).size(); // count all the words
        }

        // process xml tag
        else {
            // *** get essential information about tag ***

            // strip extra boundary spaces and "<" and ">"
            string tag =  Trim(TrimXml(xmlTokens[xmlTokenPos]));
            VERBOSE(3,"XML TAG IS: " << tag << std::endl);

            if (tag.size() == 0) {
                TRACE_ERR("ERROR: empty tag name: " << line << endl);
                return false;
            }

            // check if unary (e.g., "<wall/>")
            bool isUnary = ( tag[tag.size() - 1] == '/' );

            // check if opening tag (e.g. "<a>", not "</a>")g
            bool isClosed = ( tag[0] == '/' );
            bool isOpen = !isClosed;

            if (isClosed && isUnary) {
                TRACE_ERR("ERROR: can't have both closed and unary tag <" << tag << ">: " << line << endl);
                return false;
            }

            if (isClosed)
                tag = tag.substr(1); // remove "/" at the beginning
            if (isUnary)
                tag = tag.substr(0,tag.size()-1); // remove "/" at the end

            // find the tag name and contents
            string::size_type endOfName = tag.find_first_of(' ');
            string tagName = tag;
            string tagContent = "";
            if (endOfName != string::npos) {
                tagName = tag.substr(0,endOfName);
                tagContent = tag.substr(endOfName+1);
            }

            // *** process new tag ***

            if (isOpen || isUnary) {
                // put the tag on the tag stack
                OpenedTag openedTag = make_pair( tagName, make_pair( wordPos, tagContent ) );
                tagStack.push_back( openedTag );
                VERBOSE(3,"XML TAG " << tagName << " (" << tagContent << ") added to stack, now size " << tagStack.size() << endl);
            }

            // *** process completed tag ***

            if (isClosed || isUnary) {
                // pop last opened tag from stack;
                if (tagStack.size() == 0) {
                    TRACE_ERR("ERROR: tag " << tagName << " closed, but not opened" << ":" << line << endl);
                    return false;
                }
                OpenedTag openedTag = tagStack.back();
                tagStack.pop_back();

                // tag names have to match
                if (openedTag.first != tagName) {
                    TRACE_ERR("ERROR: tag " << openedTag.first << " closed by tag " << tagName << ": " << line << endl );
                    return false;
                }

                // assemble remaining information about tag
                size_t startPos = openedTag.second.first;
                string tagContent = openedTag.second.second;
                size_t endPos = wordPos;

                // span attribute overwrites position
                string span = ParseXmlTagAttribute(tagContent,"span");
                if (! span.empty()) {
                    vector<string> ij = Tokenize(span, "-");
                    if (ij.size() != 1 && ij.size() != 2) {
                        TRACE_ERR("ERROR: span attribute must be of the form \"i-j\" or \"i\": " << line << endl);
                        return false;
                    }
                    startPos = atoi(ij[0].c_str());
                    if (ij.size() == 1) endPos = startPos + 1;
                    else endPos = atoi(ij[1].c_str()) + 1;
                }

                VERBOSE(3,"XML TAG " << tagName << " (" << tagContent << ") spanning " << startPos << " to " << (endPos-1) << " complete, commence processing" << endl);

                if (startPos == endPos) {
                    TRACE_ERR("WARNING: tag " << tagName << " span is empty. Ignoring: " << line << endl);
                    continue;
                } else if (startPos > endPos) {
                    TRACE_ERR("ERROR: tag " << tagName << " startPos > endPos: " << line << endl);
                    return false;
                }

                // may be either a input span label ("label"), or a specified output translation "translation"
                string label = ParseXmlTagAttribute(tagContent,"label");
                string translation = ParseXmlTagAttribute(tagContent,"translation");

                // specified label
                if (translation.length() == 0 && label.length() > 0) {
                    Range range(startPos,endPos-1); // really?
                    XMLParseOutput item(label, range);
                    sourceLabels.push_back(item);
                }

                // specified translations -> vector of phrases, separated by "||"
                if (translation.length() > 0 && StaticData::Instance().GetXmlInputType() != XmlIgnore) {
                    vector<string> altTexts = TokenizeMultiCharSeparator(translation, "||");
                    vector<string> altLabel = TokenizeMultiCharSeparator(label, "||");
                    vector<string> altProbs = TokenizeMultiCharSeparator(ParseXmlTagAttribute(tagContent,"prob"), "||");
                    //TRACE_ERR("number of translations: " << altTexts.size() << endl);
                    for (size_t i=0; i<altTexts.size(); ++i) {
                        // set target phrase
                        TargetPhrase targetPhrase(firstPt);
                        // targetPhrase.CreateFromString(Output, outputFactorOrder,altTexts[i],factorDelimiter, NULL);
                        targetPhrase.CreateFromString(Output, outputFactorOrder,altTexts[i], NULL);

                        // set constituent label
                        string targetLHSstr;
                        if (altLabel.size() > i && altLabel[i].size() > 0) {
                            targetLHSstr = altLabel[i];
                        } else {
                            const UnknownLHSList &lhsList = StaticData::Instance().GetUnknownLHS();
                            UnknownLHSList::const_iterator iterLHS = lhsList.begin();
                            targetLHSstr = iterLHS->first;
                        }
                        Word *targetLHS = new Word(true);
                        targetLHS->CreateFromString(Output, outputFactorOrder, targetLHSstr, true);
                        UTIL_THROW_IF2(targetLHS->GetFactor(0) == NULL,
                                       "Null factor left-hand-side");
                        targetPhrase.SetTargetLHS(targetLHS);

                        // not tested
                        Phrase sourcePhrase = this->GetSubString(Range(startPos,endPos-1));

                        // get probability
                        float probValue = 1;
                        if (altProbs.size() > i && altProbs[i].size() > 0) {
                            probValue = Scan<float>(altProbs[i]);
                        }
                        // convert from prob to log-prob
                        float scoreValue = FloorScore(TransformScore(probValue));
                        targetPhrase.SetXMLScore(scoreValue);
                        targetPhrase.EvaluateInIsolation(sourcePhrase);

                        // set span and create XmlOption
                        Range range(startPos+1,endPos);
                        XmlOption *option = new XmlOption(range,targetPhrase);
                        assert(option);
                        xmlOptions.push_back(option);

                        VERBOSE(2,"xml translation = [" << range << "] " << targetLHSstr << " -> " << altTexts[i] << " prob: " << probValue << endl);
                    }
                    altTexts.clear();
                    altProbs.clear();
                }
            }
        }
    }
    // we are done. check if there are tags that are still open
    if (tagStack.size() > 0) {
        TRACE_ERR("ERROR: some opened tags were never closed: " << line << endl);
        return false;
    }

    // return de-xml'ed sentence in line
    line = cleanLine;
    return true;
}
Пример #8
0
int handle_command(const MythCommandLineParser &cmdline)
{
    QString eventString = cmdline.GetEventString();
    if (!eventString.isEmpty())
    {
        if (gCoreContext->ConnectToMasterServer())
        {
            if (eventString.startsWith("SYSTEM_EVENT"))
            {
                eventString += QString(" SENDER %1")
                    .arg(gCoreContext->GetHostName());
            }

            RemoteSendMessage(eventString);
            return GENERIC_EXIT_OK;
        }
        return GENERIC_EXIT_NO_MYTHCONTEXT;
    }

    if (cmdline.WantUPnPRebuild())
    {
        VERBOSE(VB_GENERAL, "Rebuilding UPNP Media Map is no longer supported.  Rescan videos using MythVideo.");

        return GENERIC_EXIT_OK;
    }

    if (cmdline.SetVerbose())
    {
        if (gCoreContext->ConnectToMasterServer())
        {
            QString message = "SET_VERBOSE ";
            message += cmdline.GetNewVerbose();

            RemoteSendMessage(message);
            VERBOSE(VB_IMPORTANT, QString("Sent '%1' message").arg(message));
            return GENERIC_EXIT_OK;
        }
        else
        {
            VERBOSE(VB_IMPORTANT,
                    "Unable to connect to backend, verbose level unchanged ");
            return GENERIC_EXIT_CONNECT_ERROR;
        }
    }

    if (cmdline.ClearSettingsCache())
    {
        if (gCoreContext->ConnectToMasterServer())
        {
            RemoteSendMessage("CLEAR_SETTINGS_CACHE");
            VERBOSE(VB_IMPORTANT, "Sent CLEAR_SETTINGS_CACHE message");
            return GENERIC_EXIT_OK;
        }
        else
        {
            VERBOSE(VB_IMPORTANT, "Unable to connect to backend, settings "
                    "cache will not be cleared.");
            return GENERIC_EXIT_CONNECT_ERROR;
        }
    }

    if (cmdline.IsPrintScheduleEnabled() ||
        cmdline.IsTestSchedulerEnabled())
    {
        sched = new Scheduler(false, &tvList);
        if (!cmdline.IsTestSchedulerEnabled() &&
            gCoreContext->ConnectToMasterServer())
        {
            cout << "Retrieving Schedule from Master backend.\n";
            sched->FillRecordListFromMaster();
        }
        else
        {
            cout << "Calculating Schedule from database.\n" <<
                    "Inputs, Card IDs, and Conflict info may be invalid "
                    "if you have multiple tuners.\n";
            sched->FillRecordListFromDB();
        }

        print_verbose_messages |= VB_SCHEDULE;
        sched->PrintList(true);
        return GENERIC_EXIT_OK;
    }

    if (cmdline.Reschedule())
    {
        bool ok = false;
        if (gCoreContext->ConnectToMasterServer())
        {
            VERBOSE(VB_IMPORTANT, "Connected to master for reschedule");
            ScheduledRecording::signalChange(-1);
            ok = true;
        }
        else
            VERBOSE(VB_IMPORTANT, "Cannot connect to master for reschedule");

        return (ok) ? GENERIC_EXIT_OK : GENERIC_EXIT_CONNECT_ERROR;
    }

    if (cmdline.ScanVideos())
    {
        bool ok = false;
        if (gCoreContext->ConnectToMasterServer())
        {
            gCoreContext->SendReceiveStringList(QStringList() << "SCAN_VIDEOS");
            VERBOSE(VB_IMPORTANT, "Requested video scan");
            ok = true;
        }
        else
            VERBOSE(VB_IMPORTANT, "Cannot connect to master for video scan");

        return (ok) ? GENERIC_EXIT_OK : GENERIC_EXIT_CONNECT_ERROR;
    }

    if (!cmdline.GetPrintExpire().isEmpty())
    {
        expirer = new AutoExpire();
        expirer->PrintExpireList(cmdline.GetPrintExpire());
        return GENERIC_EXIT_OK;
    }

    // This should never actually be reached..
    return GENERIC_EXIT_OK;
}
Пример #9
0
int connect_to_master(void)
{
    MythSocket *tempMonitorConnection = new MythSocket();
    if (tempMonitorConnection->connect(
            gCoreContext->GetSetting("MasterServerIP", "127.0.0.1"),
            gCoreContext->GetNumSetting("MasterServerPort", 6543)))
    {
        if (!gCoreContext->CheckProtoVersion(tempMonitorConnection))
        {
            VERBOSE(VB_IMPORTANT, "Master backend is incompatible with "
                    "this backend.\nCannot become a slave.");
            return GENERIC_EXIT_CONNECT_ERROR;
        }

        QStringList tempMonitorDone("DONE");

        QStringList tempMonitorAnnounce("ANN Monitor tzcheck 0");
        tempMonitorConnection->writeStringList(tempMonitorAnnounce);
        tempMonitorConnection->readStringList(tempMonitorAnnounce);
        if (tempMonitorAnnounce.empty() ||
            tempMonitorAnnounce[0] == "ERROR")
        {
            tempMonitorConnection->DownRef();
            tempMonitorConnection = NULL;
            if (tempMonitorAnnounce.empty())
            {
                VERBOSE(VB_IMPORTANT, LOC_ERR +
                        "Failed to open event socket, timeout");
            }
            else
            {
                VERBOSE(VB_IMPORTANT, LOC_ERR +
                        "Failed to open event socket" +
                        ((tempMonitorAnnounce.size() >= 2) ?
                         QString(", error was %1").arg(tempMonitorAnnounce[1]) :
                         QString(", remote error")));
            }
        }

        QStringList tzCheck("QUERY_TIME_ZONE");
        if (tempMonitorConnection)
        {
            tempMonitorConnection->writeStringList(tzCheck);
            tempMonitorConnection->readStringList(tzCheck);
        }
        if (tzCheck.size() && !checkTimeZone(tzCheck))
        {
            // Check for different time zones, different offsets, different
            // times
            VERBOSE(VB_IMPORTANT, "The time and/or time zone settings on "
                    "this system do not match those in use on the master "
                    "backend. Please ensure all frontend and backend "
                    "systems are configured to use the same time zone and "
                    "have the current time properly set.");
            VERBOSE(VB_IMPORTANT,
                    "Unable to run with invalid time settings. Exiting.");
            tempMonitorConnection->writeStringList(tempMonitorDone);
            tempMonitorConnection->DownRef();
            return GENERIC_EXIT_INVALID_TIMEZONE;
        }
        else
        {
            VERBOSE(VB_IMPORTANT,
                    QString("Backend is running in %1 time zone.")
                    .arg(getTimeZoneID()));
        }
        if (tempMonitorConnection)
            tempMonitorConnection->writeStringList(tempMonitorDone);
    }
    if (tempMonitorConnection)
        tempMonitorConnection->DownRef();

    return GENERIC_EXIT_OK;
}
Пример #10
0
void CVideoDecoder::ThreadEntry ()
{
    CDemux* pDemux 					= mpDemux;
    AVStream* pStream 				= mpStream;
    CVideoStubRender* pVStubRender 	= (CVideoStubRender*)mpStubRender;
    CMasterClock* pClock 			= mpClock;
    int Ret 						= ERR_NONE;
    int bFrameFinished				= 0;
    AVCodecContext *pCodecContext	= NULL;
    AVPacket AVPkt;
    int64_t  PTS;

    if (pDemux == NULL || pStream == NULL || pVStubRender == NULL || pStream->codec == NULL)
    {
        ERROR ("mpDecoder || mpStream || mpStubRender || mpStream->codec== NULL!");
        return;
    }
    pCodecContext = pStream->codec;

    memset((void*)&AVPkt,0,sizeof(AVPacket));

    DEBUG ("start video decoder loop!");

    for(;;)
    {
        if(mbQuit)
        {
            INFO("mbQuit");
            PlayCore::GetInstance()->avcodec_flush_buffers(pCodecContext);
            break;
        }

        if(pDemux->GetSyncPTS()>=0.0)//已经设定了SyncPTS
        {
            if(!pDemux->IsSynced())//没有被音频流Sync
            {
                DEBUG("NO FOUND SYNCED !!");
                usleep(25*1000);
                continue;
            }
            else if(!pClock->IsRun())//已经设定SyncPTs并且被其他流sync并且当前状态不是播放状态
            {
                usleep(1*1000);//Reduce CPU usage
                continue;
            }
        }
        else
        {
            DEBUG("TRY SHOW FIRST KEY VIDEO FRAME mbFirstKeyFrame %s",mbFirstKeyFrame?"true":"false");
        }

        if(mbNextFrame)
        {
            AVPkt = pDemux->GetVideoPacket ();
            if (AVPkt.data == 0 || AVPkt.size == 0)
            {
                INFO ("get NULL packet! continue! must be end of pStream!!! stop thread!");
                break;
            }

            //如果A/V已经同步,但此时视频时间戳严重落后于系统时钟
            if(pDemux->IsSynced()&&mbNeedReSync)
            {
                double CurClock = pClock->GetCurrentClock ();
                double FramePTS = AVPkt.pts * av_q2d (pStream->time_base);
                double Diff = FramePTS - CurClock;
                DEBUG ("V:SyncOut CurClock=%f, FramePTS=%f, Diff=%f", CurClock, FramePTS, Diff);

                if (Diff >= CMasterClock::AVThresholdSync)
                {
                    DEBUG ("V:Sync CurClock=%f, FramePTS=%f, Diff=%f", CurClock, FramePTS, Diff);
                }
                else
                {
                    PlayCore::GetInstance()->av_free_packet (&AVPkt);
                    memset((void*)&AVPkt,0,sizeof(AVPacket));
                    continue;
                }

            }

            int len = CVideoDecoderImp::Decode (pCodecContext, mpFrame, &bFrameFinished, &AVPkt, &PTS);

            if (len < 0 || bFrameFinished == 0)
            {
                WARN ("CVideoDecoderImp::Decode fail! continue to next packet!");
                PlayCore::GetInstance()->av_free_packet (&AVPkt);
                memset((void*)&AVPkt,0,sizeof(AVPacket));
                continue;
            }

            DEBUG("mbFirstKeyFrame %d,key_frame %d,pict_type %d mbNeedReSync %d AV_PICTURE_TYPE_I %d",mbFirstKeyFrame,mpFrame->key_frame,mpFrame->pict_type,mbNeedReSync,AV_PICTURE_TYPE_I);
            //需要关键帧
            if(!pDemux->IsSynced())
            {
                //不是关键帧continue
                if(!(mpFrame->key_frame && mpFrame->pict_type == AV_PICTURE_TYPE_I))
                {
                    DEBUG("Not Key frame continue");
                    PlayCore::GetInstance()->av_free_packet (&AVPkt);
                    memset((void*)&AVPkt,0,sizeof(AVPacket));
                    continue;
                }
                else //第一次音视频Sync
                {
                    INFO("First Sync after opened");
                    mbFirstKeyFrame = true;
                }

            }
            else if(mbNeedReSync) //视频时间戳严重落后于系统时钟,第一个合适的关键帧
            {
                if(!(mpFrame->key_frame && mpFrame->pict_type == AV_PICTURE_TYPE_I))
                {
                    DEBUG("Not Key frame continue");
                    PlayCore::GetInstance()->av_free_packet (&AVPkt);
                    memset((void*)&AVPkt,0,sizeof(AVPacket));
                    continue;
                }
                else
                {
                    INFO("mbNeedReSync %d",mbNeedReSync);
                    mbNeedReSync 	= false;
                    mbFirstKeyFrame = false;
                }
            }
            else//pDemux go on
            {
                mbFirstKeyFrame = false;
            }
        }
        if (pClock)
        {
            double FramePTS = PTS * av_q2d (pStream->time_base);
            //渲染视频首个关键帧并且不是播放过程中视频解码落后于系统时钟。设定音频同步时间点
            if(mbFirstKeyFrame)
            {
                Ret = pVStubRender->ShowPicture (mpFrame);

                INFO("IS Key frame mbFirstKeyFrame %d FramePTS %f ShowPicture Ret %d",mbFirstKeyFrame,FramePTS,Ret);

                //成功渲染视频
                if(Ret>=0 || Ret == ERR_DEVICE_NOSET)
                {
                    //得到同步时间点,
                    double SyncPTS = pDemux->GetSyncPTS();
                    INFO("pDemux->GetSyncPTS() %f",SyncPTS);
                    if(SyncPTS<0.0)
                    {
                        //设定同步时间点
                        pDemux->SetSyncPTS(FramePTS);
                        //设定时钟的起始时间点
                        pClock->SetOriginClock (FramePTS);

                        //surface fixed
                        pVStubRender->ShowPicture (mpFrame);

                        //如果没有音频数据流设定为Synced;
                        if(pDemux->GetAudioStreamIndex()<0)
                        {
                            pDemux->SetSynced(true);
                        }

                        mbFirstKeyFrame = false;
                        mbNextFrame = true;
                    }
                }
            }
            else
            {
                double CurClock = pClock->GetCurrentClock ();
                double Diff = FramePTS - CurClock;

                DEBUG ("V:CurClock=%f, FramePTS=%f, Diff=%f", CurClock, FramePTS, Diff);

                if (fabs(Diff) < CMasterClock::AVThresholdNoSync)
                {
                    mbNextFrame = true;

                    if (Diff <= 0)
                    {
                        VERBOSE ("show it at once.");
                    }
                    else
                    {
                        unsigned int usec = Diff * 1000 * 1000;
                        VERBOSE ("wait %d usec", usec);
                        usleep (usec);
                    }

                    Ret = pVStubRender->ShowPicture (mpFrame);
                }
                else
                {
                    if (Diff < 0)
                    {
                        mbNextFrame = true;

                        //如果系统时钟是以视频时钟为基准的,调整系统时钟
                        if(pClock->GetClockType()==CMasterClock::CLOCK_VIDEO)
                        {
                            WARN("we reset master timer to video FramePTS");
                            double ClockTime = PlayCore::GetInstance()->av_gettime() / 1000000.0;
                            pClock->SetOriginClock (FramePTS, ClockTime);
                            Ret = pVStubRender->ShowPicture (mpFrame);
                        }
                        else//否则是以其他(音频,系统时间)为系统时钟,此时视频严重落后于同步的时间范围值,
                        {   //对于直播不需要设定需要查找最近的关键帧标识

                            DEBUG("we need ReSync video FramePTS Diff %f",Diff);
                        }
                    }
                    else
                    {
                        WARN ("video FramePTS far early than curr_pts Diff %f",Diff);
                        unsigned int usec = Diff * 1000 * 1000;
                        mbNextFrame  = false;
                        usleep (1*1000);
                    }
                }
                DEBUG("ShowPicture Ret %d",Ret);
            }
        }
        else
        {
            ERROR ("you have not set Master Clock!!! will not show pictures!");
        }

        PlayCore::GetInstance()->av_free_packet (&AVPkt);
        memset((void*)&AVPkt,0,sizeof(AVPacket));
    }

    Reset();

    if (AVPkt.data != 0)
    {
        PlayCore::GetInstance()->av_free_packet (&AVPkt);
    }
    DEBUG ("end of video out thread!");
}
Пример #11
0
KRB5Context::~KRB5Context()
{
    VERBOSE("Destroying Kerberos Context");
    krb5_free_context(m_context);
}
Пример #12
0
int DVBRecorder::OpenFilterFd(uint pid, int pes_type, uint stream_type)
{
    if (_open_pid_filters >= _max_pid_filters)
        return -1;

    // bits per millisecond
    uint bpms = (StreamID::IsVideo(stream_type)) ? 19200 : 500;
    // msec of buffering we want
    uint msec_of_buffering = max(POLL_WARNING_TIMEOUT + 50, 1500);
    // actual size of buffer we need
    uint pid_buffer_size = ((bpms*msec_of_buffering + 7) / 8);
    // rounded up to the nearest page
    pid_buffer_size = ((pid_buffer_size + 4095) / 4096) * 4096;

    VERBOSE(VB_RECORD, LOC + QString("Adding pid 0x%1 size(%2)")
            .arg(pid,0,16).arg(pid_buffer_size));

    // Open the demux device
    QString dvbdev = CardUtil::GetDeviceName(
        DVB_DEV_DEMUX, _card_number_option);
    QByteArray dev = dvbdev.toAscii();

    int fd_tmp = open(dev.constData(), O_RDWR);
    if (fd_tmp < 0)
    {
        VERBOSE(VB_IMPORTANT, LOC_ERR + "Could not open demux device." + ENO);
        _max_pid_filters = _open_pid_filters;
        return -1;
    }

    // Try to make the demux buffer large enough to
    // allow for longish disk writes.
    uint sz    = pid_buffer_size;
    uint usecs = msec_of_buffering * 1000;
    while (ioctl(fd_tmp, DMX_SET_BUFFER_SIZE, sz) < 0 && sz > 1024*8)
    {
        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to set demux buffer size for "+
                QString("pid 0x%1 to %2").arg(pid,0,16).arg(sz) + ENO);

        sz    /= 2;
        sz     = ((sz+4095)/4096)*4096;
        usecs /= 2;
    }
    /*
    VERBOSE(VB_RECORD, LOC + "Set demux buffer size for " +
            QString("pid 0x%1 to %2,\n\t\t\twhich gives us a %3 msec buffer.")
            .arg(pid,0,16).arg(sz).arg(usecs/1000));
    */

    // Set the filter type
    struct dmx_pes_filter_params params;
    memset(&params, 0, sizeof(params));
    params.input    = DMX_IN_FRONTEND;
    params.output   = DMX_OUT_TS_TAP;
    params.flags    = DMX_IMMEDIATE_START;
    params.pid      = pid;
    params.pes_type = (dmx_pes_type_t) pes_type;
    if (ioctl(fd_tmp, DMX_SET_PES_FILTER, &params) < 0)
    {
        close(fd_tmp);

        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to set demux filter." + ENO);
        _max_pid_filters = _open_pid_filters;
        return -1;
    }

    _open_pid_filters++;
    return fd_tmp;
}
Пример #13
0
bool DVBPIDInfo::Open(const QString &dvb_dev, bool use_section_reader)
{
    if (filter_fd >= 0)
    {
        close(filter_fd);
        filter_fd = -1;
    }

    QString demux_fn = CardUtil::GetDeviceName(DVB_DEV_DEMUX, dvb_dev);
    QByteArray demux_ba = demux_fn.toAscii();

    VERBOSE(VB_RECORD, LOC + QString("Opening filter for pid 0x%1")
            .arg(_pid, 0, 16));

    int mux_fd = open(demux_ba.constData(), O_RDWR | O_NONBLOCK);
    if (mux_fd == -1)
    {
        VERBOSE(VB_IMPORTANT, LOC +
                QString("Failed to open demux device %1 "
                        "for filter on pid 0x%2")
                .arg(demux_fn).arg(_pid, 0, 16));
        return false;
    }

    if (!use_section_reader)
    {
        struct dmx_pes_filter_params pesFilterParams;
        memset(&pesFilterParams, 0, sizeof(struct dmx_pes_filter_params));
        pesFilterParams.pid      = (__u16) _pid;
        pesFilterParams.input    = DMX_IN_FRONTEND;
        pesFilterParams.output   = DMX_OUT_TS_TAP;
        pesFilterParams.flags    = DMX_IMMEDIATE_START;
        pesFilterParams.pes_type = DMX_PES_OTHER;

        if (ioctl(mux_fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0)
        {
            VERBOSE(VB_IMPORTANT, LOC_ERR +
                    QString("Failed to set TS filter (pid 0x%1)")
                    .arg(_pid, 0, 16));

            close(mux_fd);
            return false;
        }
    }
    else
    {
        struct dmx_sct_filter_params sctFilterParams;
        memset(&sctFilterParams, 0, sizeof(struct dmx_sct_filter_params));
        switch ( (__u16) _pid )
        {
            case 0x0: // PAT
                sctFilterParams.filter.filter[0] = 0;
                sctFilterParams.filter.mask[0]   = 0xff;
                break;
            case 0x0010: // assume this is for an NIT, NITo, PMT
                // This filter will give us table ids 0x00-0x03, 0x40-0x43
                // we expect to see table ids 0x02, 0x40 and 0x41 on this PID
                // NOTE: In theory, this will break with ATSC when PID 0x10
                //       is used for ATSC/MPEG tables. This is frowned upon,
                //       but PMTs have been seen on in the wild.
                sctFilterParams.filter.filter[0] = 0x00;
                sctFilterParams.filter.mask[0]   = 0xbc;
                break;
            case 0x0011: // assume this is for an SDT, SDTo, PMT
                // This filter will give us table ids 0x02, 0x06, 0x42 and 0x46
                // All but 0x06 are ones we want to see.
                // NOTE: In theory this will break with ATSC when pid 0x11
                //       is used for random ATSC tables. In practice only
                //       video data has been seen on 0x11.
                sctFilterParams.filter.filter[0] = 0x02;
                sctFilterParams.filter.mask[0]   = 0xbb;
                break;
            case 0x1ffb: // assume this is for various ATSC tables
                // MGT 0xC7, Terrestrial VCT 0xC8, Cable VCT 0xC9, RRT 0xCA,
                // STT 0xCD, DCCT 0xD3, DCCSCT 0xD4, Caption 0x86
                sctFilterParams.filter.filter[0] = 0x80;
                sctFilterParams.filter.mask[0]   = 0xa0;
                break;
            default:
                // otherwise assume it could be any table
                sctFilterParams.filter.filter[0] = 0x00;
                sctFilterParams.filter.mask[0]   = 0x00;
                break;
        }
        sctFilterParams.pid            = (__u16) _pid;
        sctFilterParams.timeout        = 0;
        sctFilterParams.flags          = DMX_IMMEDIATE_START;

        if (ioctl(mux_fd, DMX_SET_FILTER, &sctFilterParams) < 0)
        {
            VERBOSE(VB_IMPORTANT, LOC_ERR +
                    "Failed to set \"section\" filter " +
                    QString("(pid 0x%1) (filter %2)").arg(_pid, 0, 16)
                    .arg(sctFilterParams.filter.filter[0]));
            close(mux_fd);
            return false;
        }
    }

    filter_fd = mux_fd;

    return true;
}
Пример #14
0
/** \fn DVBStreamHandler::RunTS(void)
 *  \brief Uses TS filtering devices to read a DVB device for tables & data
 *
 *  This supports all types of MPEG based stream data, but is extreemely
 *  slow with DVB over USB 1.0 devices which for efficiency reasons buffer
 *  a stream until a full block transfer buffer full of the requested
 *  tables is available. This takes a very long time when you are just
 *  waiting for a PAT or PMT table, and the buffer is hundreds of packets
 *  in size.
 */
void DVBStreamHandler::RunTS(void)
{
    QByteArray dvr_dev_path = _dvr_dev_path.toAscii();
    int dvr_fd;
    for (int tries = 1; ; ++tries)
    {
        dvr_fd = open(dvr_dev_path.constData(), O_RDONLY | O_NONBLOCK);
        if (dvr_fd >= 0)
            break;

        VERBOSE(VB_IMPORTANT, LOC_WARN +
                QString("Opening DVR device %1 failed : %2")
                .arg(_dvr_dev_path).arg(strerror(errno)));

        if (tries >= 20 || (errno != EBUSY && errno != EAGAIN))
        {
            VERBOSE(VB_IMPORTANT, LOC +
                    QString("Failed to open DVR device %1 : %2")
                    .arg(_dvr_dev_path).arg(strerror(errno)));
            _error = true;
            return;
        }
        usleep(50000);
    }

    int remainder = 0;
    int buffer_size = TSPacket::kSize * 15000;
    unsigned char *buffer = new unsigned char[buffer_size];
    if (!buffer)
    {
        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to allocate memory");
        close(dvr_fd);
        _error = true;
        return;
    }
    bzero(buffer, buffer_size);

    DeviceReadBuffer *drb = NULL;
    if (_needs_buffering)
    {
        drb = new DeviceReadBuffer(this);
        if (!drb->Setup(_device, dvr_fd))
        {
            VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to allocate DRB buffer");
            delete drb;
            delete[] buffer;
            close(dvr_fd);
            _error = true;
            return;
        }

        drb->Start();
    }

    SetRunning(true, _needs_buffering, false);
    {
        QMutexLocker locker(&_start_stop_lock);
        _drb = drb;
    }

    VERBOSE(VB_RECORD, LOC + "RunTS(): begin");

    bool _error = false;
    fd_set fd_select_set;
    FD_ZERO(        &fd_select_set);
    FD_SET (dvr_fd, &fd_select_set);
    while (_running_desired && !_error)
    {
        RetuneMonitor();
        UpdateFiltersFromStreamData();

        ssize_t len = 0;

        if (drb)
        {
            len = drb->Read(
                &(buffer[remainder]), buffer_size - remainder);

            // Check for DRB errors
            if (drb->IsErrored())
            {
                VERBOSE(VB_IMPORTANT, LOC_ERR + "Device error detected");
                _error = true;
            }

            if (drb->IsEOF())
            {
                VERBOSE(VB_IMPORTANT, LOC_ERR + "Device EOF detected");
                _error = true;
            }
        }
        else
        {
            // timeout gets reset by select, so we need to create new one
            struct timeval timeout = { 0, 50 /* ms */ * 1000 /* -> usec */ };
            int ret = select(dvr_fd+1, &fd_select_set, NULL, NULL, &timeout);
            if (ret == -1 && errno != EINTR)
            {
                VERBOSE(VB_IMPORTANT, LOC_ERR + "select() failed" + ENO);
            }
            else
            {
                len = read(dvr_fd, &(buffer[remainder]),
                           buffer_size - remainder);
            }
        }

        if ((0 == len) || (-1 == len))
        {
            usleep(100);
            continue;
        }

        len += remainder;

        if (len < 10) // 10 bytes = 4 bytes TS header + 6 bytes PES header
        {
            remainder = len;
            continue;
        }

        _listener_lock.lock();

        if (_stream_data_list.empty())
        {
            _listener_lock.unlock();
            continue;
        }

        StreamDataList::const_iterator sit = _stream_data_list.begin();
        for (; sit != _stream_data_list.end(); ++sit)
            remainder = sit.key()->ProcessData(buffer, len);

        _listener_lock.unlock();

        if (remainder > 0 && (len > remainder)) // leftover bytes
            memmove(buffer, &(buffer[len - remainder]), remainder);
    }
    VERBOSE(VB_RECORD, LOC + "RunTS(): " + "shutdown");

    RemoveAllPIDFilters();

    {
        QMutexLocker locker(&_start_stop_lock);
        _drb = NULL;
    }

    if (drb)
    {
        if (drb->IsRunning())
            drb->Stop();
        delete drb;
    }

    close(dvr_fd);
    delete[] buffer;

    VERBOSE(VB_RECORD, LOC + "RunTS(): " + "end");

    SetRunning(false, _needs_buffering, false);
}
Пример #15
0
ULONG __stdcall IWaterMarkUI::AddRef()
{
    VERBOSE(DLLTEXT("IWaterMarkUI:AddRef entry.\r\n"));
    return InterlockedIncrement(&m_cRef) ;
}
Пример #16
0
bool setupTVs(bool ismaster, bool &error)
{
    error = false;
    QString localhostname = gCoreContext->GetHostName();

    MSqlQuery query(MSqlQuery::InitCon());

    if (ismaster)
    {
        // Hack to make sure recorded.basename gets set if the user
        // downgrades to a prior version and creates new entries
        // without it.
        if (!query.exec("UPDATE recorded SET basename = CONCAT(chanid, '_', "
                        "DATE_FORMAT(starttime, '%Y%m%d%H%i00'), '_', "
                        "DATE_FORMAT(endtime, '%Y%m%d%H%i00'), '.nuv') "
                        "WHERE basename = '';"))
            MythDB::DBError("Updating record basename",
                                 query.lastQuery());

        // Hack to make sure record.station gets set if the user
        // downgrades to a prior version and creates new entries
        // without it.
        if (!query.exec("UPDATE channel SET callsign=chanid "
                        "WHERE callsign IS NULL OR callsign='';"))
            MythDB::DBError("Updating channel callsign", query.lastQuery());

        if (query.exec("SELECT MIN(chanid) FROM channel;"))
        {
            query.first();
            int min_chanid = query.value(0).toInt();
            if (!query.exec(QString("UPDATE record SET chanid = %1 "
                                    "WHERE chanid IS NULL;").arg(min_chanid)))
                MythDB::DBError("Updating record chanid", query.lastQuery());
        }
        else
            MythDB::DBError("Querying minimum chanid", query.lastQuery());

        MSqlQuery records_without_station(MSqlQuery::InitCon());
        records_without_station.prepare("SELECT record.chanid,"
                " channel.callsign FROM record LEFT JOIN channel"
                " ON record.chanid = channel.chanid WHERE record.station='';");
        if (records_without_station.exec() && records_without_station.next())
        {
            MSqlQuery update_record(MSqlQuery::InitCon());
            update_record.prepare("UPDATE record SET station = :CALLSIGN"
                    " WHERE chanid = :CHANID;");
            do
            {
                update_record.bindValue(":CALLSIGN",
                        records_without_station.value(1));
                update_record.bindValue(":CHANID",
                        records_without_station.value(0));
                if (!update_record.exec())
                {
                    MythDB::DBError("Updating record station",
                            update_record.lastQuery());
                }
            } while (records_without_station.next());
        }
    }

    if (!query.exec(
            "SELECT cardid, hostname "
            "FROM capturecard "
            "ORDER BY cardid"))
    {
        MythDB::DBError("Querying Recorders", query);
        return false;
    }

    vector<uint>    cardids;
    vector<QString> hosts;
    while (query.next())
    {
        uint    cardid = query.value(0).toUInt();
        QString host   = query.value(1).toString();
        QString cidmsg = QString("Card %1").arg(cardid);

        if (host.isEmpty())
        {
            QString msg = cidmsg + " does not have a hostname defined.\n"
                "Please run setup and confirm all of the capture cards.\n";

            VERBOSE(VB_IMPORTANT, msg);
            gCoreContext->LogEntry("mythbackend", LP_CRITICAL,
                               "Problem with capture cards", msg);
            continue;
        }

        cardids.push_back(cardid);
        hosts.push_back(host);
    }

    for (uint i = 0; i < cardids.size(); i++)
    {
        if (hosts[i] == localhostname)
            new TVRec(cardids[i]);
    }

    for (uint i = 0; i < cardids.size(); i++)
    {
        uint    cardid = cardids[i];
        QString host   = hosts[i];
        QString cidmsg = QString("Card %1").arg(cardid);

        if (!ismaster)
        {
            if (host == localhostname)
            {
                TVRec *tv = TVRec::GetTVRec(cardid);
                if (tv && tv->Init())
                {
                    EncoderLink *enc = new EncoderLink(cardid, tv);
                    tvList[cardid] = enc;
                }
                else
                {
                    gCoreContext->LogEntry("mythbackend", LP_CRITICAL,
                                       "Problem with capture cards",
                                       cidmsg + " failed init");
                    delete tv;
                    // The master assumes card comes up so we need to
                    // set error and exit if a non-master card fails.
                    error = true;
                }
            }
        }
        else
        {
            if (host == localhostname)
            {
                TVRec *tv = TVRec::GetTVRec(cardid);
                if (tv && tv->Init())
                {
                    EncoderLink *enc = new EncoderLink(cardid, tv);
                    tvList[cardid] = enc;
                }
                else
                {
                    gCoreContext->LogEntry("mythbackend", LP_CRITICAL,
                                       "Problem with capture cards",
                                       cidmsg + "failed init");
                    delete tv;
                }
            }
            else
            {
                EncoderLink *enc = new EncoderLink(cardid, NULL, host);
                tvList[cardid] = enc;
            }
        }
    }

    if (tvList.empty())
    {
        VERBOSE(VB_IMPORTANT, LOC_WARN +
                "No valid capture cards are defined in the database.");

        gCoreContext->LogEntry("mythbackend", LP_WARNING,
                           "No capture cards are defined",
                           "This backend will not be used for recording.");
    }

    return true;
}
Пример #17
0
void RaceAnalyzerComm::writeConfig(RaceCaptureConfig *config, RaceAnalyzerCommCallback * callback){
	try{
		wxDateTime start = wxDateTime::UNow();
		CComm *serialPort = GetSerialPort();
		if (NULL==serialPort) throw CommException(CommException::OPEN_PORT_FAILED);

		int updateCount = 0;
		for (int i = 0; i < CONFIG_ANALOG_CHANNELS;i++){
			AnalogConfig &cfg = config->analogConfigs[i];
			wxString cmd = "setAnalogCfg";
			cmd = AppendIntParam(cmd, i);
			cmd = AppendChannelConfig(cmd, cfg.channelConfig);
			cmd = AppendIntParam(cmd, cfg.loggingPrecision);
			cmd = AppendIntParam(cmd, cfg.scalingMode);
			cmd = AppendFloatParam(cmd, cfg.linearScaling);
			ScalingMap &map = (cfg.scalingMap);
			for (int m=0; m < CONFIG_ANALOG_SCALING_BINS;m++){
				cmd = AppendIntParam(cmd, map.rawValues[m]);
			}
			for (int m=0; m < CONFIG_ANALOG_SCALING_BINS;m++){
				cmd = AppendFloatParam(cmd, map.scaledValue[m]);
			}
			wxString result = SendCommand(serialPort, cmd);
			CheckThrowResult(result);
			updateWriteConfigPct(++updateCount,callback);
		}
		for (int i = 0; i < CONFIG_TIMER_CHANNELS; i++){
			TimerConfig &cfg = config->timerConfigs[i];
			wxString cmd = "setTimerCfg";
			cmd = AppendIntParam(cmd, i);
			AppendChannelConfig(cmd, cfg.channelConfig);
			cmd = AppendIntParam(cmd, cfg.loggingPrecision);
			cmd = AppendIntParam(cmd, cfg.slowTimerEnabled);
			cmd = AppendIntParam(cmd, cfg.mode);
			cmd = AppendIntParam(cmd, cfg.pulsePerRev);
			cmd = AppendIntParam(cmd, cfg.timerDivider);
			cmd = AppendIntParam(cmd, cfg.scaling);
			wxString result = SendCommand(serialPort, cmd);
			CheckThrowResult(result);
			updateWriteConfigPct(++updateCount,callback);
		}
		for (int i = 0; i < CONFIG_ACCEL_CHANNELS; i++){
			AccelConfig &cfg = config->accelConfigs[i];
			wxString cmd = "setAccelCfg";
			cmd = AppendIntParam(cmd, i);
			cmd = AppendChannelConfig(cmd, cfg.channelConfig);
			cmd = AppendIntParam(cmd, cfg.mode);
			cmd = AppendIntParam(cmd, cfg.channel);
			cmd = AppendIntParam(cmd, cfg.zeroValue);
			wxString result = SendCommand(serialPort, cmd);
			CheckThrowResult(result);
			updateWriteConfigPct(++updateCount,callback);
		}
		for (int i = 0; i < CONFIG_ANALOG_PULSE_CHANNELS; i++){
			PwmConfig &cfg = config->pwmConfigs[i];
			wxString cmd = "setPwmCfg";
			cmd = AppendIntParam(cmd, i);
			cmd = AppendChannelConfig(cmd, cfg.channelConfig);
			cmd = AppendIntParam(cmd, cfg.loggingPrecision);
			cmd = AppendIntParam(cmd, cfg.outputMode);
			cmd = AppendIntParam(cmd, cfg.loggingMode);
			cmd = AppendIntParam(cmd, cfg.startupDutyCycle);
			cmd = AppendIntParam(cmd, cfg.startupPeriod);
			cmd = AppendFloatParam(cmd, cfg.voltageScaling);
			wxString result = SendCommand(serialPort, cmd);
			CheckThrowResult(result);
			updateWriteConfigPct(++updateCount,callback);
		}
		for (int i = 0; i < CONFIG_GPIO_CHANNELS; i++){
			GpioConfig &cfg = config->gpioConfigs[i];
			wxString cmd = "setGpioCfg";
			cmd = AppendIntParam(cmd,i);
			cmd = AppendChannelConfig(cmd, cfg.channelConfig);
			cmd = AppendIntParam(cmd, cfg.mode);
			wxString result = SendCommand(serialPort, cmd);
			CheckThrowResult(result);
			updateWriteConfigPct(++updateCount,callback);
		}
		{
			GpsConfig &cfg = config->gpsConfig;
			{
				wxString cmd = "setGpsCfg";
				cmd = AppendIntParam(cmd, cfg.gpsInstalled);
				cmd = AppendChannelConfig(cmd, cfg.latitudeCfg);
				cmd = AppendChannelConfig(cmd, cfg.longitudeCfg);
				cmd = AppendChannelConfig(cmd, cfg.speedCfg);
				cmd = AppendChannelConfig(cmd, cfg.timeCfg);
				cmd = AppendChannelConfig(cmd, cfg.satellitesCfg);
				wxString result = SendCommand(serialPort, cmd);
				CheckThrowResult(result);
				updateWriteConfigPct(++updateCount,callback);
			}
			{
				wxString cmd = "setStartFinishCfg";
				cmd = AppendChannelConfig(cmd, cfg.lapCountCfg);
				cmd = AppendChannelConfig(cmd, cfg.lapTimeCfg);
				cmd = AppendChannelConfig(cmd, cfg.splitTimeCfg);
				cmd = AppendFloatParam(cmd, cfg.startFinishTarget.latitude);
				cmd = AppendFloatParam(cmd, cfg.startFinishTarget.longitude);
				cmd = AppendFloatParam(cmd, cfg.startFinishTarget.targetRadius);
				cmd = AppendFloatParam(cmd, cfg.splitTarget.latitude);
				cmd = AppendFloatParam(cmd, cfg.splitTarget.longitude);
				cmd = AppendFloatParam(cmd, cfg.splitTarget.targetRadius);
				wxString result = SendCommand(serialPort, cmd);
				CheckThrowResult(result);
				updateWriteConfigPct(++updateCount,callback);
			}
		}
		{
			ConnectivityConfig &cfg = config->connectivityConfig;
			wxString cmd = "setOutputCfg";
			cmd = AppendIntParam(cmd, cfg.sdLoggingMode);
			cmd = AppendIntParam(cmd, cfg.connectivityMode);
			cmd = AppendUIntParam(cmd, cfg.p2pConfig.destinationAddrHigh);
			cmd = AppendUIntParam(cmd, cfg.p2pConfig.destinationAddrLow);
			cmd = AppendStringParam(cmd, cfg.telemetryConfig.telemetryServer);
			cmd = AppendStringParam(cmd, cfg.telemetryConfig.telemetryDeviceId);

			wxString result = SendCommand(serialPort, cmd);
			CheckThrowResult(result);

			cmd = "setCellCfg";
			cmd = AppendStringParam(cmd, cfg.cellularConfig.apnHost);
			cmd = AppendStringParam(cmd, cfg.cellularConfig.apnUser);
			cmd = AppendStringParam(cmd, cfg.cellularConfig.apnPass);
			result = SendCommand(serialPort, cmd);
			CheckThrowResult(result);

			updateWriteConfigPct(++updateCount,callback);
		}
		{
			writeScript(config->luaScript);
			updateWriteConfigPct(++updateCount,callback);
		}
		wxTimeSpan dur = wxDateTime::UNow() - start;
		VERBOSE(FMT("write config in %f",dur.GetMilliseconds().ToDouble()));
		callback->WriteConfigComplete(true,"");
	}
	catch(CommException &e){
		callback->WriteConfigComplete(false, e.GetErrorMessage());
	}
	CloseSerialPort();
}
Пример #18
0
int run_backend(const MythCommandLineParser &cmdline)
{
    if (!setup_context(cmdline))
        return GENERIC_EXIT_NO_MYTHCONTEXT;

    bool ismaster = gCoreContext->IsMasterHost();

    if (!UpgradeTVDatabaseSchema(ismaster, ismaster))
    {
        VERBOSE(VB_IMPORTANT, "Couldn't upgrade database to new schema");
        return GENERIC_EXIT_DB_OUTOFDATE;
    }

    if (!ismaster)
    {
        int ret = connect_to_master();
        if (ret != GENERIC_EXIT_OK)
            return ret;
    }

    QString myip = gCoreContext->GetSetting("BackendServerIP");
    int     port = gCoreContext->GetNumSetting("BackendServerPort", 6543);
    if (myip.isEmpty())
    {
        cerr << "No setting found for this machine's BackendServerIP.\n"
             << "Please run setup on this machine and modify the first page\n"
             << "of the general settings.\n";
        return GENERIC_EXIT_SETUP_ERROR;
    }

    MythSystemEventHandler *sysEventHandler = new MythSystemEventHandler();

    if (ismaster)
    {
        VERBOSE(VB_GENERAL, LOC + "Starting up as the master server.");
        gCoreContext->LogEntry("mythbackend", LP_INFO,
                           "MythBackend started as master server", "");
    }
    else
    {
        VERBOSE(VB_GENERAL, LOC + "Running as a slave backend.");
        gCoreContext->LogEntry("mythbackend", LP_INFO,
                           "MythBackend started as a slave backend", "");
    }

    print_warnings(cmdline);

    bool fatal_error = false;
    bool runsched = setupTVs(ismaster, fatal_error);
    if (fatal_error)
    {
        delete sysEventHandler;
        return GENERIC_EXIT_SETUP_ERROR;
    }

    if (ismaster)
    {
        if (runsched)
        {
            sched = new Scheduler(true, &tvList);
            int err = sched->GetError();
            if (err)
                return err;

            if (!cmdline.IsSchedulerEnabled())
                sched->DisableScheduling();
        }

        if (cmdline.IsHouseKeeperEnabled())
            housekeeping = new HouseKeeper(true, ismaster, sched);

        if (cmdline.IsAutoExpirerEnabled())
        {
            expirer = new AutoExpire(&tvList);
            if (sched)
                sched->SetExpirer(expirer);
        }
    }
    else if (cmdline.IsHouseKeeperEnabled())
    {
        housekeeping = new HouseKeeper(true, ismaster, NULL);
    }

    if (cmdline.IsJobQueueEnabled())
        jobqueue = new JobQueue(ismaster);

    // ----------------------------------------------------------------------
    //
    // ----------------------------------------------------------------------

    if (g_pUPnp == NULL)
    {
        g_pUPnp = new MediaServer();

        g_pUPnp->Init(ismaster, !cmdline.IsUPnPEnabled());
    }

    // ----------------------------------------------------------------------
    // Setup status server
    // ----------------------------------------------------------------------

    HttpStatus *httpStatus = NULL;
    HttpServer *pHS = g_pUPnp->GetHttpServer();

    if (pHS)
    {
        VERBOSE(VB_IMPORTANT, "Main::Registering HttpStatus Extension");

        httpStatus = new HttpStatus( &tvList, sched, expirer, ismaster );
        pHS->RegisterExtension( httpStatus );
    }

    VERBOSE(VB_IMPORTANT, QString("Enabled verbose msgs: %1")
            .arg(verboseString));

    MainServer *mainServer = new MainServer(
        ismaster, port, &tvList, sched, expirer);

    int exitCode = mainServer->GetExitCode();
    if (exitCode != GENERIC_EXIT_OK)
    {
        VERBOSE(VB_IMPORTANT, "Backend exiting, MainServer initialization "
                "error.");
        delete mainServer;
        return exitCode;
    }

    if (httpStatus && mainServer)
        httpStatus->SetMainServer(mainServer);

    StorageGroup::CheckAllStorageGroupDirs();

    if (gCoreContext->IsMasterBackend())
        SendMythSystemEvent("MASTER_STARTED");

    ///////////////////////////////
    ///////////////////////////////
    exitCode = qApp->exec();
    ///////////////////////////////
    ///////////////////////////////

    if (gCoreContext->IsMasterBackend())
    {
        SendMythSystemEvent("MASTER_SHUTDOWN");
        qApp->processEvents();
    }

    gCoreContext->LogEntry("mythbackend", LP_INFO, "MythBackend exiting", "");

    delete sysEventHandler;
    delete mainServer;

    cleanup();

    return exitCode;
}
Пример #19
0
int main(int argc, char **argv)
{
   int ret;

   trap_ifc_spec_t ifc_spec;
   //char *ifc_params[] = {"traptestshm,650000;traptestshm,650000"};
   //ifc_spec.types = "mm";
   char *ifc_params[3] = { argv[0], "-i", "tt;localhost,11111,65533;11111,5,65533" };
   int paramno = 3;

   uint64_t counter = 0;
   uint64_t iteration = 0;
   time_t duration;
   uint16_t payload_size;

   char *payload = NULL;

   //verbose = CL_VERBOSE_LIBRARY;
   trap_verbose = CL_VERBOSE_OFF;
   VERBOSE(CL_VERBOSE_OFF, "%s [number]\nnumber - size of data to send for testing", argv[0]);

   ret = trap_parse_params(&paramno, ifc_params, &ifc_spec);
   if (ret != TRAP_E_OK) {
      if (ret == TRAP_E_HELP) { // "-h" was found
         trap_print_help(&module_info);
         return 0;
      }
      fprintf(stderr, "ERROR in parsing of parameters for TRAP: %s\n", trap_last_error_msg);
      return 1;
   }
   // Initialize TRAP library (create and init all interfaces)
   ret = trap_init(&module_info, ifc_spec);
   if (ret != TRAP_E_OK) {
      fprintf(stderr, "ERROR in TRAP initialization %s\n", trap_last_error_msg);
      return 1;
   }

   duration = time(NULL);

   // Read data from input, process them and write to output
   while(!stop) {
      ret = trap_get_data(0, (const void **) &payload, &payload_size, TRAP_WAIT);
      if (ret != TRAP_E_OK) {
         VERBOSE(CL_ERROR, "error: %s", trap_last_error_msg);
      }
      ret = trap_send_data(0, (void *) payload, payload_size, TRAP_WAIT);
      if (ret == TRAP_E_OK) {
         counter++;
      } else {
         VERBOSE(CL_ERROR, "error: %s", trap_last_error_msg);
      }
      iteration++;
      if (counter == 10) {
         break;
      }
   }
   duration = time(NULL) - duration;

   printf("Number of iterations: %"PRIu64"\nLast sent: %"PRIu64"\nTime: %"PRIu64"s\n",
      (uint64_t) iteration,
      (uint64_t) counter-1,
      (uint64_t) duration);
   sleep(2);

   // Do all necessary cleanup before exiting
   // (close interfaces and free allocated memory)
   trap_finalize();
   //free(payload);

   return 0;
}
Пример #20
0
/// Compares two VideoMetadata instances
bool VideoFilterSettings::meta_less_than(const VideoMetadata &lhs,
                                         const VideoMetadata &rhs,
                                         bool sort_ignores_case) const
{
    bool ret = false;
    switch (orderby)
    {
        case kOrderByTitle:
        {
            VideoMetadata::SortKey lhs_key;
            VideoMetadata::SortKey rhs_key;
            if (lhs.HasSortKey() && rhs.HasSortKey())
            {
                lhs_key = lhs.GetSortKey();
                rhs_key = rhs.GetSortKey();
            }
            else
            {
                lhs_key = VideoMetadata::GenerateDefaultSortKey(lhs,
                                                           sort_ignores_case);
                rhs_key = VideoMetadata::GenerateDefaultSortKey(rhs,
                                                           sort_ignores_case);
            }
            ret = lhs_key < rhs_key;
            break;
        }
        case kOrderBySeasonEp:
        {
            if ((lhs.GetSeason() == rhs.GetSeason())
                && (lhs.GetEpisode() == rhs.GetEpisode())
                && (lhs.GetSeason() == 0)
                && (rhs.GetSeason() == 0)
                && (lhs.GetEpisode() == 0)
                && (rhs.GetEpisode() == 0))
            {
                VideoMetadata::SortKey lhs_key;
                VideoMetadata::SortKey rhs_key;
                if (lhs.HasSortKey() && rhs.HasSortKey())
                {
                    lhs_key = lhs.GetSortKey();
                    rhs_key = rhs.GetSortKey();
                }
                else
                {
                    lhs_key = VideoMetadata::GenerateDefaultSortKey(lhs,
                                                               sort_ignores_case);
                    rhs_key = VideoMetadata::GenerateDefaultSortKey(rhs,
                                                               sort_ignores_case);
                }
                ret = lhs_key < rhs_key;
            }
            else if (lhs.GetSeason() == rhs.GetSeason()
                     && lhs.GetTitle() == rhs.GetTitle())
                ret = lhs.GetEpisode() < rhs.GetEpisode();
            else
                ret = lhs.GetSeason() < rhs.GetSeason();
            break;
        }
        case kOrderByYearDescending:
        {
            ret = lhs.GetYear() > rhs.GetYear();
            break;
        }
        case kOrderByUserRatingDescending:
        {
            ret = lhs.GetUserRating() > rhs.GetUserRating();
            break;
        }
        case kOrderByLength:
        {
            ret = lhs.GetLength() < rhs.GetLength();
            break;
        }
        case kOrderByFilename:
        {
            QString lhsfn(sort_ignores_case ?
                          lhs.GetFilename().toLower() : lhs.GetFilename());
            QString rhsfn(sort_ignores_case ?
                          rhs.GetFilename().toLower() : rhs.GetFilename());
            ret = QString::localeAwareCompare(lhsfn, rhsfn) < 0;
            break;
        }
        case kOrderByID:
        {
            ret = lhs.GetID() < rhs.GetID();
            break;
        }
        case kOrderByDateAddedDescending:
        {
            ret = lhs.GetInsertdate() > rhs.GetInsertdate();
            break;
        }
        default:
        {
            VERBOSE(VB_IMPORTANT, QString("Error: unknown sort type %1")
                    .arg(orderby));
        }
    }

    return ret;
}
Пример #21
0
void ScanWizard::SetPage(const QString &pageTitle)
{
    VERBOSE(VB_CHANSCAN, QString("SetPage(%1)").arg(pageTitle));
    if (pageTitle != ChannelScannerGUI::kTitle)
    {
        scannerPane->quitScanning();
        return;
    }

    QMap<QString,QString> start_chan;
    DTVTunerType parse_type = DTVTunerType::kTunerTypeUnknown;

    uint    cardid    = configPane->GetCardID();
    QString inputname = configPane->GetInputName();
    uint    sourceid  = configPane->GetSourceID();
    int     scantype  = configPane->GetScanType();
    bool    do_scan   = true;

    VERBOSE(VB_CHANSCAN, LOC + "SetPage(): " +
            QString("type(%1) cardid(%2) inputname(%3)")
            .arg(scantype).arg(cardid).arg(inputname));

    if (scantype == ScanTypeSetting::DVBUtilsImport)
    {
        scannerPane->ImportDVBUtils(sourceid, lastHWCardType,
                                    configPane->GetFilename());
    }
    else if (scantype == ScanTypeSetting::NITAddScan_DVBT)
    {
        start_chan = configPane->GetStartChan();
        parse_type = DTVTunerType::kTunerTypeDVBT;
    }
    else if (scantype == ScanTypeSetting::NITAddScan_DVBS)
    {
        start_chan = configPane->GetStartChan();
        parse_type = DTVTunerType::kTunerTypeDVBS1;
    }
    else if (scantype == ScanTypeSetting::NITAddScan_DVBS2)
    {
        start_chan = configPane->GetStartChan();
        parse_type = DTVTunerType::kTunerTypeDVBS2;
    }
    else if (scantype == ScanTypeSetting::NITAddScan_DVBC)
    {
        start_chan = configPane->GetStartChan();
        parse_type = DTVTunerType::kTunerTypeDVBC;
    }
    else if (scantype == ScanTypeSetting::IPTVImport)
    {
        do_scan = false;
        scannerPane->ImportM3U(cardid, inputname, sourceid);
    }
    else if ((scantype == ScanTypeSetting::FullScan_ATSC)     ||
             (scantype == ScanTypeSetting::FullTransportScan) ||
             (scantype == ScanTypeSetting::TransportScan)     ||
             (scantype == ScanTypeSetting::FullScan_DVBC)     ||
             (scantype == ScanTypeSetting::FullScan_DVBT)     ||
             (scantype == ScanTypeSetting::FullScan_Analog))
    {
        ;
    }
    else if (scantype == ScanTypeSetting::ExistingScanImport)
    {
        do_scan = false;
        uint scanid = configPane->GetScanID();
        ScanDTVTransportList transports = LoadScan(scanid);
        ChannelImporter ci(true, true, true, true, false,
                           configPane->DoFreeToAirOnly(),
                           configPane->GetServiceRequirements());
        ci.Process(transports);
    }
    else
    {
        do_scan = false;
        VERBOSE(VB_CHANSCAN, LOC_ERR + "SetPage(): " +
                QString("type(%1) src(%2) cardid(%3) not handled")
                .arg(scantype).arg(sourceid).arg(cardid));

        MythPopupBox::showOkPopup(
            GetMythMainWindow(), tr("ScanWizard"),
            tr("Programmer Error, see console"));
    }

    // Just verify what we get from the UI...
    DTVMultiplex tuning;
    if ((parse_type != DTVTunerType::kTunerTypeUnknown) &&
        !tuning.ParseTuningParams(
            parse_type,
            start_chan["frequency"],      start_chan["inversion"],
            start_chan["symbolrate"],     start_chan["fec"],
            start_chan["polarity"],
            start_chan["coderate_hp"],    start_chan["coderate_lp"],
            start_chan["constellation"],  start_chan["trans_mode"],
            start_chan["guard_interval"], start_chan["hierarchy"],
            start_chan["modulation"],     start_chan["bandwidth"],
            start_chan["mod_sys"],        start_chan["rolloff"]))
    {
        MythPopupBox::showOkPopup(
            GetMythMainWindow(), tr("ScanWizard"),
            tr("Error parsing parameters"));

        do_scan = false;
    }

    if (do_scan)
    {
        QString table_start, table_end;
        configPane->GetFrequencyTableRange(table_start, table_end);

        scannerPane->Scan(
            configPane->GetScanType(),            configPane->GetCardID(),
            configPane->GetInputName(),           configPane->GetSourceID(),
            configPane->DoIgnoreSignalTimeout(),  configPane->DoFollowNIT(),
            configPane->DoTestDecryption(),       configPane->DoFreeToAirOnly(),
            configPane->GetServiceRequirements(),
            // stuff needed for particular scans
            configPane->GetMultiplex(),         start_chan,
            configPane->GetFrequencyStandard(), configPane->GetModulation(),
            configPane->GetFrequencyTable(),
            table_start, table_end);
    }
}
Пример #22
0
bool VideoFilterDialog::Create()
{
    if (!LoadWindowFromXML("video-ui.xml", "filter", this))
        return false;

    bool err = false;
    UIUtilE::Assign(this, m_textfilter, "textfilter_input", &err);
    UIUtilE::Assign(this, m_yearList, "year_select", &err);
    UIUtilE::Assign(this, m_userratingList, "userrating_select", &err);
    UIUtilE::Assign(this, m_categoryList, "category_select", &err);
    UIUtilE::Assign(this, m_countryList, "country_select", &err);
    UIUtilE::Assign(this, m_genreList, "genre_select", &err);
    UIUtilE::Assign(this, m_castList, "cast_select", &err);
    UIUtilE::Assign(this, m_runtimeList, "runtime_select", &err);
    UIUtilE::Assign(this, m_browseList, "browse_select", &err);
    UIUtilE::Assign(this, m_watchedList, "watched_select", &err);
    UIUtilE::Assign(this, m_inetrefList, "inetref_select", &err);
    UIUtilE::Assign(this, m_coverfileList, "coverfile_select", &err);
    UIUtilE::Assign(this, m_orderbyList, "orderby_select", &err);

    UIUtilE::Assign(this, m_doneButton, "done_button", &err);
    UIUtilE::Assign(this, m_saveButton, "save_button", &err);

    UIUtilE::Assign(this, m_numvideosText, "numvideos_text", &err);

    if (err)
    {
        VERBOSE(VB_IMPORTANT, "Cannot load screen 'filter'");
        return false;
    }

    BuildFocusList();

    fillWidgets();
    update_numvideo();

    connect(m_yearList, SIGNAL(itemSelected(MythUIButtonListItem*)),
            SLOT(SetYear(MythUIButtonListItem*)));
    connect(m_userratingList, SIGNAL(itemSelected(MythUIButtonListItem*)),
            SLOT(SetUserRating(MythUIButtonListItem*)));
    connect(m_categoryList, SIGNAL(itemSelected(MythUIButtonListItem*)),
            SLOT(SetCategory(MythUIButtonListItem*)));
    connect(m_countryList, SIGNAL(itemSelected(MythUIButtonListItem*)),
            SLOT(setCountry(MythUIButtonListItem*)));
    connect(m_genreList,SIGNAL(itemSelected(MythUIButtonListItem*)),
            SLOT(setGenre(MythUIButtonListItem*)));
    connect(m_castList,SIGNAL(itemSelected(MythUIButtonListItem*)),
            SLOT(SetCast(MythUIButtonListItem*)));
    connect(m_runtimeList, SIGNAL(itemSelected(MythUIButtonListItem*)),
            SLOT(setRunTime(MythUIButtonListItem*)));
    connect(m_browseList, SIGNAL(itemSelected(MythUIButtonListItem*)),
            SLOT(SetBrowse(MythUIButtonListItem*)));
    connect(m_watchedList, SIGNAL(itemSelected(MythUIButtonListItem*)),
            SLOT(SetWatched(MythUIButtonListItem*)));
    connect(m_inetrefList, SIGNAL(itemSelected(MythUIButtonListItem*)),
            SLOT(SetInetRef(MythUIButtonListItem*)));
    connect(m_coverfileList, SIGNAL(itemSelected(MythUIButtonListItem*)),
            SLOT(SetCoverFile(MythUIButtonListItem*)));
    connect(m_orderbyList, SIGNAL(itemSelected(MythUIButtonListItem*)),
            SLOT(setOrderby(MythUIButtonListItem*)));
    connect(m_textfilter, SIGNAL(valueChanged()),
    		SLOT(setTextFilter()));

    connect(m_saveButton, SIGNAL(Clicked()), SLOT(saveAsDefault()));
    connect(m_doneButton, SIGNAL(Clicked()), SLOT(saveAndExit()));

    return true;
}
Пример #23
0
/**
 * Copy in @host_path the equivalent of "@tracee->root +
 * canonicalize(@dir_fd + @guest_path)".  If @guest_path is not
 * absolute then it is relative to the directory referred by the
 * descriptor @dir_fd (AT_FDCWD is for the current working directory).
 * See the documentation of canonicalize() for the meaning of
 * @deref_final.  This function returns -errno if an error occured,
 * otherwise 0.
 */
int translate_path(Tracee *tracee, char host_path[PATH_MAX],
		   int dir_fd, const char *guest_path, bool deref_final)
{
	int status;

	/* Use "/" as the base if it is an absolute guest path. */
	if (guest_path[0] == '/') {
		strcpy(host_path, "/");
	}
	/* It is relative to the current working directory or to a
	 * directory referred by a descriptors, see openat(2) for
	 * details. */
	else if (dir_fd == AT_FDCWD) {
		status = getcwd2(tracee, host_path);
		if (status < 0)
			return status;
	}
	else {
		struct stat statl;

		/* /proc/@tracee->pid/fd/@dir_fd -> host_path.  */
		status = readlink_proc_pid_fd(tracee->pid, dir_fd, host_path);
		if (status < 0)
			return status;

		/* Ensure it points to a directory. */
		status = stat(host_path, &statl);
		if (status < 0)
			return -errno;
		if (!S_ISDIR(statl.st_mode))
			return -ENOTDIR;

		/* Remove the leading "root" part of the base
		 * (required!). */
		status = detranslate_path(tracee, host_path, NULL);
		if (status < 0)
			return status;
	}

	VERBOSE(tracee, 2, "pid %d: translate(\"%s\" + \"%s\")",
		tracee != NULL ? tracee->pid : 0, host_path, guest_path);

	status = notify_extensions(tracee, GUEST_PATH, (intptr_t)host_path, (intptr_t)guest_path);
	if (status < 0)
		return status;
	if (status > 0)
		goto skip;

	/* Canonicalize regarding the new root. */
	status = canonicalize(tracee, guest_path, deref_final, host_path, 0);
	if (status < 0)
		return status;

	/* Final binding substitution to convert "host_path" into a host
	 * path, since canonicalize() works from the guest
	 * point-of-view.  */
	status = substitute_binding(tracee, GUEST, host_path);
	if (status < 0)
		return status;

skip:
	VERBOSE(tracee, 2, "pid %d:          -> \"%s\"",
		tracee != NULL ? tracee->pid : 0, host_path);
	return 0;
}
Пример #24
0
void MythSocketThread::run(void)
{
    VERBOSE(VB_SOCKET, "MythSocketThread: readyread thread start");

    QMutexLocker locker(&m_readyread_lock);
    m_readyread_started_wait.wakeAll();
    while (m_readyread_run)
    {
        VERBOSE(VB_SOCKET|VB_EXTRA, "ProcessAddRemoveQueues");

        ProcessAddRemoveQueues();

        VERBOSE(VB_SOCKET|VB_EXTRA, "Construct FD_SET");

        // construct FD_SET for all connected and unlocked sockets...
        int maxfd = -1;
        fd_set rfds;
        FD_ZERO(&rfds);

        QList<MythSocket*>::const_iterator it = m_readyread_list.begin();
        for (; it != m_readyread_list.end(); ++it)
        {
            if (!(*it)->TryLock(false))
                continue;

            if ((*it)->state() == MythSocket::Connected &&
                !(*it)->m_notifyread)
            {
                FD_SET((*it)->socket(), &rfds);
                maxfd = std::max((*it)->socket(), maxfd);
            }
            (*it)->Unlock(false);
        }

        // There are no unlocked sockets, wait for event before we continue..
        if (maxfd < 0)
        {
            VERBOSE(VB_SOCKET|VB_EXTRA, "Empty FD_SET, sleeping");
            if (m_readyread_wait.wait(&m_readyread_lock))
                VERBOSE(VB_SOCKET|VB_EXTRA, "Empty FD_SET, woken up");
            else
                VERBOSE(VB_SOCKET|VB_EXTRA, "Empty FD_SET, timed out");
            continue;
        }

        int rval = 0;

        if (m_readyread_pipe[0] >= 0)
        {
            // Clear out any pending pipe reads, we have already taken care of
            // this event above under the m_readyread_lock.
            char dummy[128];
            if (m_readyread_pipe_flags[0] & O_NONBLOCK)
            {
                rval = ::read(m_readyread_pipe[0], dummy, 128);
                FD_SET(m_readyread_pipe[0], &rfds);
                maxfd = std::max(m_readyread_pipe[0], maxfd);
            }

            // also exit select on exceptions on same descriptors
            fd_set efds;
            memcpy(&efds, &rfds, sizeof(fd_set));

            // The select waits forever for data, so if we need to process
            // anything else we need to write to m_readyread_pipe[1]..
            // We unlock the ready read lock, because we don't need it
            // and this will allow WakeReadyReadThread() to run..
            m_readyread_lock.unlock();
            VERBOSE(VB_SOCKET|VB_EXTRA, "Waiting on select..");
            rval = select(maxfd + 1, &rfds, NULL, &efds, NULL);
            VERBOSE(VB_SOCKET|VB_EXTRA, "Got data on select");
            m_readyread_lock.lock();

            if (rval > 0 && FD_ISSET(m_readyread_pipe[0], &rfds))
            {
                int ret = ::read(m_readyread_pipe[0], dummy, 128);
                if (ret < 0)
                {
                    VERBOSE(VB_SOCKET|VB_EXTRA,
                            "Strange.. failed to read event pipe");
                }
            }
        }
        else
        {
            VERBOSE(VB_SOCKET|VB_EXTRA, "Waiting on select.. (no pipe)");

            // also exit select on exceptions on same descriptors
            fd_set efds;
            memcpy(&efds, &rfds, sizeof(fd_set));

            // Unfortunately, select on a pipe is not supported on all
            // platforms. So we fallback to a loop that instead times out
            // of select and checks for wakeAll event.
            while (!rval)
            {
                struct timeval timeout;
                timeout.tv_sec = 0;
                timeout.tv_usec = kShortWait * 1000;
                rval = select(maxfd + 1, &rfds, NULL, &efds, &timeout);
                if (!rval)
                    m_readyread_wait.wait(&m_readyread_lock, kShortWait);
            }

            VERBOSE(VB_SOCKET|VB_EXTRA, "Got data on select (no pipe)");
        }

        if (rval <= 0)
        {
            if (rval == 0)
            {
                // Note: This should never occur when using pipes. When there
                // is no error there should be data in at least one fd..
                VERBOSE(VB_SOCKET|VB_EXTRA, "MythSocketThread: select timeout");
            }
            else
                VERBOSE(VB_SOCKET,
                        "MythSocketThread: select returned error" + ENO);

            m_readyread_wait.wait(&m_readyread_lock, kShortWait);
            continue;
        }
        
        // ReadyToBeRead allows calls back into the socket so we need
        // to release the lock for a little while.
        // since only this loop updates m_readyread_list this is safe.
        m_readyread_lock.unlock();

        // Actually read some data! This is a form of co-operative
        // multitasking so the ready read handlers should be quick..

        uint downref_tm = 0;
        if (!m_readyread_downref_list.empty())
        {
            VERBOSE(VB_SOCKET|VB_EXTRA, "Deleting stale sockets");

            QTime tm = QTime::currentTime();
            for (it = m_readyread_downref_list.begin();
                 it != m_readyread_downref_list.end(); ++it)
            {
                (*it)->DownRef();
            }
            m_readyread_downref_list.clear();
            downref_tm = tm.elapsed();
        }

        VERBOSE(VB_SOCKET|VB_EXTRA, "Processing ready reads");

        QMap<uint,uint> timers;
        QTime tm = QTime::currentTime();
        it = m_readyread_list.begin();

        for (; it != m_readyread_list.end() && m_readyread_run; ++it)
        {
            if (!(*it)->TryLock(false))
                continue;
            
            int socket = (*it)->socket();

            if (socket >= 0 &&
                (*it)->state() == MythSocket::Connected &&
                FD_ISSET(socket, &rfds))
            {
                QTime rrtm = QTime::currentTime();
                ReadyToBeRead(*it);
                timers[socket] = rrtm.elapsed();
            }
            (*it)->Unlock(false);
        }

        if (VERBOSE_LEVEL_CHECK(VB_SOCKET|VB_EXTRA))
        {
            QString rep = QString("Total read time: %1ms, on sockets")
                .arg(tm.elapsed());
            QMap<uint,uint>::const_iterator it = timers.begin();
            for (; it != timers.end(); ++it)
                rep += QString(" {%1,%2ms}").arg(it.key()).arg(*it);
            if (downref_tm)
                rep += QString(" {downref, %1ms}").arg(downref_tm);

            VERBOSE(VB_SOCKET|VB_EXTRA, QString("MythSocketThread: ") + rep);
        }

        m_readyread_lock.lock();
        VERBOSE(VB_SOCKET|VB_EXTRA, "Reacquired ready read lock");
    }

    VERBOSE(VB_SOCKET, "MythSocketThread: readyread thread exit");
}
	void CSystemBundleActivator::SaveBundleRegistryState()
	{
		VERBOSE("[SysBndleActivator] %s", __FUNCTION__);
	}
Пример #26
0
/** \fn ThreadedFileWriter::Write(const void*, uint)
 *  \brief Writes data to the end of the write buffer
 *
 *   NOTE: This blocks while buffer is in use by the write to disk thread.
 *
 *  \param data  pointer to data to write to disk
 *  \param count size of data in bytes
 */
uint ThreadedFileWriter::Write(const void *data, uint count)
{
    if (count == 0)
        return 0;

    if (count > tfw_buf_size)
    {
        VERBOSE(VB_IMPORTANT, LOC +
                QString("WARNING: count(%1), tfw_buf_size(%2)")
                .arg(count).arg(tfw_buf_size));
    }

    uint iobound_cnt = 0;
    uint remaining = count;
    char *wdata = (char *)data;

    while (remaining)
    {
        bool first = true;

        buflock.lock();
        while (BufFreePriv() == 0)
        {
            if (first)
            {
                ++iobound_cnt;
                VERBOSE(VB_IMPORTANT, LOC_ERR + "Write() -- IOBOUND begin " +
                        QString("remaining(%1) free(%2) size(%3) cnt(%4)")
                        .arg(remaining).arg(BufFreePriv())
                        .arg(tfw_buf_size).arg(iobound_cnt));
                first = false;
            }

            bufferWroteData.wait(&buflock, 1000);
        }
        uint twpos = wpos;
        uint bytes = (BufFreePriv() < remaining) ? BufFreePriv() : remaining;
        buflock.unlock();

        if (!first)
            VERBOSE(VB_IMPORTANT, LOC_ERR + "Write() -- IOBOUND end");

        if (no_writes)
            return 0;

        if ((twpos + bytes) > tfw_buf_size)
        {
            int first_chunk_size  = tfw_buf_size - twpos;
            int second_chunk_size = bytes - first_chunk_size;
            memcpy(buf + twpos, wdata, first_chunk_size);
            memcpy(buf, wdata + first_chunk_size,
                   second_chunk_size);
        }
        else
        {
            memcpy(buf + twpos, wdata, bytes);
        }

        buflock.lock();
        if (twpos == wpos)
        {
            wpos = (wpos + bytes) % tfw_buf_size;
        }
        else
        {
            VERBOSE(VB_IMPORTANT, LOC_ERR + "Programmer Error detected! "
                    "wpos was changed from under the Write() function.");
        }
        buflock.unlock();

        bufferHasData.wakeAll();

        remaining -= bytes;
        wdata += bytes;

        if (remaining)
        {
            buflock.lock();
            if (0 == BufFreePriv())
                bufferWroteData.wait(&buflock, 10000);
            buflock.unlock();
        }
    }

    return count;
}
Пример #27
0
QString GalleryUtil::GetCaption(const QString &filePath)
{
    QString caption("");

    try
    {
#ifdef EXIF_SUPPORT
        char *exifvalue = new char[1024];
        ExifData *data = exif_data_new_from_file(
            filePath.toLocal8Bit().constData());
        if (data)
        {
            for (int i = 0; i < EXIF_IFD_COUNT; i++)
            {
                ExifEntry *entry = exif_content_get_entry (data->ifd[i],
                                                    EXIF_TAG_USER_COMMENT);
                if (entry)
                {
#if NEW_LIB_EXIF
                    exif_entry_get_value(entry, exifvalue, 1023);
                    caption = exifvalue;
#else
                    caption = exif_entry_get_value(entry);
#endif
                    // Found one, done
                    if(!caption.trimmed().isEmpty())
                       break;
                }

                entry = exif_content_get_entry (data->ifd[i],
                                                EXIF_TAG_IMAGE_DESCRIPTION);
                if (entry)
                {
#if NEW_LIB_EXIF
                    exif_entry_get_value(entry, exifvalue, 1023);
                    caption = exifvalue;
#else
                    caption = exif_entry_get_value(entry);
#endif
                    // Found one, done
                    if(!caption.trimmed().isEmpty())
                       break;
                }
            }
            exif_data_free(data);
        }
        else
        {
           VERBOSE(VB_FILE, LOC_ERR +
                   QString("Could not load exif data from '%1'")
                   .arg(filePath));
        }

        delete [] exifvalue;
#endif // EXIF_SUPPORT
    }
    catch (...)
    {
        VERBOSE(VB_IMPORTANT, LOC_ERR +
                QString("Failed to extract EXIF headers from '%1'")
                .arg(filePath));
    }

    return caption;
}
Пример #28
0
/** \fn ThreadedFileWriter::DiskLoop(void)
 *  \brief The thread run method that actually calls safe_write().
 */
void ThreadedFileWriter::DiskLoop(void)
{
    uint size = 0;
    written = 0;

    while (!in_dtor || BufUsed() > 0)
    {
        buflock.lock();
        size = BufUsedPriv();

        if (size == 0)
        {
            buflock.unlock();
            bufferEmpty.wakeAll();
            buflock.lock();
        }

        if (!size || (!in_dtor && !flush &&
            ((size < tfw_min_write_size) &&
             (written >= tfw_min_write_size))))
        {
            bufferHasData.wait(&buflock, 100);
            buflock.unlock();
            continue;
        }
        uint trpos = rpos;
        buflock.unlock();

        /* cap the max. write size. Prevents the situation where 90% of the
           buffer is valid, and we try to write all of it at once which
           takes a long time. During this time, the other thread fills up
           the 10% that was free... */
        size = (size > TFW_MAX_WRITE_SIZE) ? TFW_MAX_WRITE_SIZE : size;

        bool write_ok;
        if (ignore_writes)
            ;
        else if ((trpos + size) > tfw_buf_size)
        {
            int first_chunk_size  = tfw_buf_size - trpos;
            int second_chunk_size = size - first_chunk_size;
            size = safe_write(fd, buf + trpos, first_chunk_size, write_ok);
            if ((int)size == first_chunk_size && write_ok)
                size += safe_write(fd, buf, second_chunk_size, write_ok);
        }
        else
        {
            size = safe_write(fd, buf + trpos, size, write_ok);
        }

        if (!ignore_writes && !write_ok && ((EFBIG == errno) || (ENOSPC == errno)))
        {
            QString msg;
            switch (errno)
            {
                case EFBIG:
                    msg =
                        "Maximum file size exceeded by '%1'"
                        "\n\t\t\t"
                        "You must either change the process ulimits, configure"
                        "\n\t\t\t"
                        "your operating system with \"Large File\" support, or use"
                        "\n\t\t\t"
                        "a filesystem which supports 64-bit or 128-bit files."
                        "\n\t\t\t"
                        "HINT: FAT32 is a 32-bit filesystem.";
                    break;
                case ENOSPC:
                    msg =
                        "No space left on the device for file '%1'"
                        "\n\t\t\t"
                        "file will be truncated, no further writing will be done.";
                    break;
            }

            VERBOSE(VB_IMPORTANT, msg.arg(filename));
            ignore_writes = true;
        }

        if (written <= tfw_min_write_size)
        {
            written += size;
        }

        buflock.lock();
        if (trpos == rpos)
        {
            rpos = (rpos + size) % tfw_buf_size;
        }
        else
        {
            VERBOSE(VB_IMPORTANT, LOC_ERR + "Programmer Error detected! "
                    "rpos was changed from under the DiskLoop() function.");
        }
        m_file_wpos += size;
        buflock.unlock();

        bufferWroteData.wakeAll();
    }
}
Пример #29
0
void CPUCALL
interrupt(int num, int intrtype, int errorp, int error_code)
{
    descriptor_t gsd;
    UINT idt_idx;
    UINT32 new_ip;
    UINT16 new_cs;
    int exc_errcode;

    VERBOSE(("interrupt: num = 0x%02x, intrtype = %s, errorp = %s, error_code = %08x", num, (intrtype == INTR_TYPE_EXTINTR) ? "external" : (intrtype == INTR_TYPE_EXCEPTION ? "exception" : "softint"), errorp ? "on" : "off", error_code));

    if(num == 0x21 && md_int21())	{
        return;
    }

    CPU_SET_PREV_ESP();

    if (!CPU_STAT_PM) {
        /* real mode */
        CPU_WORKCLOCK(20);

        idt_idx = num * 4;
        if (idt_idx + 3 > CPU_IDTR_LIMIT) {
            VERBOSE(("interrupt: real-mode IDTR limit check failure (idx = 0x%04x, limit = 0x%08x", idt_idx, CPU_IDTR_LIMIT));
            EXCEPTION(GP_EXCEPTION, idt_idx + 2);
        }

        if ((intrtype == INTR_TYPE_EXTINTR) && CPU_STAT_HLT) {
            VERBOSE(("interrupt: reset HTL in real mode"));
            CPU_EIP++;
            CPU_STAT_HLT = 0;
        }

        REGPUSH0(REAL_FLAGREG);
        REGPUSH0(CPU_CS);
        REGPUSH0(CPU_IP);

        CPU_EFLAG &= ~(T_FLAG | I_FLAG | AC_FLAG | RF_FLAG);
        CPU_TRAP = 0;

        new_ip = cpu_memoryread_w(CPU_IDTR_BASE + idt_idx);
        new_cs = cpu_memoryread_w(CPU_IDTR_BASE + idt_idx + 2);
        LOAD_SEGREG(CPU_CS_INDEX, new_cs);
        CPU_EIP = new_ip;
    } else {
        /* protected mode */
        CPU_WORKCLOCK(200);

        VERBOSE(("interrupt: -------------------------------------------------------------- start"));
        VERBOSE(("interrupt: old EIP = %04x:%08x, ESP = %04x:%08x", CPU_CS, CPU_EIP, CPU_SS, CPU_ESP));

#if defined(DEBUG)
        if (num == 0x80) {
            /* Linux, FreeBSD, NetBSD, OpenBSD system call */
            VERBOSE(("interrupt: syscall# = %d\n%s", CPU_EAX, cpu_reg2str()));
        }
#endif

        idt_idx = num * 8;
        exc_errcode = idt_idx + 2;
        if (intrtype == INTR_TYPE_EXTINTR)
            exc_errcode++;

        if (idt_idx + 7 > CPU_IDTR_LIMIT) {
            VERBOSE(("interrupt: IDTR limit check failure (idx = 0x%04x, limit = 0x%08x", idt_idx, CPU_IDTR_LIMIT));
            EXCEPTION(GP_EXCEPTION, exc_errcode);
        }

        /* load a gate descriptor from interrupt descriptor table */
        memset(&gsd, 0, sizeof(gsd));
        load_descriptor(&gsd, CPU_IDTR_BASE + idt_idx);
        if (!SEG_IS_VALID(&gsd)) {
            VERBOSE(("interrupt: gate descripter is invalid."));
            EXCEPTION(GP_EXCEPTION, exc_errcode);
        }
        if (!SEG_IS_SYSTEM(&gsd)) {
            VERBOSE(("interrupt: gate descriptor is not system segment."));
            EXCEPTION(GP_EXCEPTION, exc_errcode);
        }

        switch (gsd.type) {
        case CPU_SYSDESC_TYPE_TASK:
        case CPU_SYSDESC_TYPE_INTR_16:
        case CPU_SYSDESC_TYPE_INTR_32:
        case CPU_SYSDESC_TYPE_TRAP_16:
        case CPU_SYSDESC_TYPE_TRAP_32:
            break;

        default:
            VERBOSE(("interrupt: invalid gate type (%d)", gsd.type));
            EXCEPTION(GP_EXCEPTION, exc_errcode);
            break;
        }

        /* 5.10.1.1. 例外/割り込みハンドラ・プロシージャの保護 */
        if ((intrtype == INTR_TYPE_SOFTINTR) && (gsd.dpl < CPU_STAT_CPL)) {
            VERBOSE(("interrupt: intrtype(softint) && DPL(%d) < CPL(%d)", gsd.dpl, CPU_STAT_CPL));
            EXCEPTION(GP_EXCEPTION, exc_errcode);
        }

        if (!SEG_IS_PRESENT(&gsd)) {
            VERBOSE(("interrupt: gate descriptor is not present."));
            EXCEPTION(NP_EXCEPTION, exc_errcode);
        }

        if ((intrtype == INTR_TYPE_EXTINTR) && CPU_STAT_HLT) {
            VERBOSE(("interrupt: reset HTL in protected mode"));
            CPU_EIP++;
            CPU_STAT_HLT = 0;
        }

        switch (gsd.type) {
        case CPU_SYSDESC_TYPE_TASK:
            interrupt_task_gate(&gsd, intrtype, errorp, error_code);
            break;

        case CPU_SYSDESC_TYPE_INTR_16:
        case CPU_SYSDESC_TYPE_INTR_32:
        case CPU_SYSDESC_TYPE_TRAP_16:
        case CPU_SYSDESC_TYPE_TRAP_32:
            interrupt_intr_or_trap(&gsd, intrtype, errorp, error_code);
            break;

        default:
            EXCEPTION(GP_EXCEPTION, exc_errcode);
            break;
        }

        VERBOSE(("interrupt: ---------------------------------------------------------------- end"));
    }

    CPU_CLEAR_PREV_ESP();
}
Пример #30
0
/*
 * In one pass, read all the directory entries of the specified
 * directory and call the callback function for non-directory
 * entries.
 *
 * On return:
 *    0: Lets the directory to be scanned for directory entries.
 *    < 0: Completely stops traversing.
 *    FST_SKIP: stops further scanning of the directory.  Traversing
 *        will continue with the next directory in the hierarchy.
 *    SKIP_ENTRY: Failed to get the directory entries, so the caller
 *	  should skip this entry.
 */
static int
traverse_level_nondir(struct fs_traverse *ftp,
    traverse_state_t *tsp, struct fst_node *pnp, dent_arg_t *darg)
{
	int pl; /* path length */
	int rv;
	struct fst_node en; /* entry node */
	longlong_t cookie_verf;
	fs_dent_info_t *dent;
	struct dirent *buf;
	size_t len = 0;
	int fd;

	rv = 0;
	pl = strlen(pnp->tn_path);

	buf = ndmp_malloc(MAX_DENT_BUF_SIZE);
	if (buf == NULL)
		return (errno);

	fd = open(tsp->ts_fh.fh_fpath, O_RDONLY);
	if (fd == -1) {
		free(buf);
		return (errno);
	}

	while (rv == 0) {
		long i, n_entries;

		darg->da_end = 0;
		n_entries = 0;
		rv = fs_getdents(fd, buf, &len, pnp->tn_path, &tsp->ts_dpos,
		    &cookie_verf, &n_entries, darg);
		if (rv < 0) {
			traverse_stats.fss_readdir_err++;

			NDMP_LOG(LOG_DEBUG, "Error %d on readdir(%s) pos %d",
			    rv, pnp->tn_path, tsp->ts_dpos);
			if (STOP_ONERR(ftp))
				break;
			/*
			 * We cannot read the directory entry, we should
			 * skip to the next directory.
			 */
			rv = SKIP_ENTRY;
			continue;
		} else {
			/* Break at the end of directory */
			if (rv > 0)
				rv = 0;
			else
				break;
		}

		/* LINTED imporper alignment */
		dent = (fs_dent_info_t *)darg->da_buf;
		/* LINTED imporper alignment */
		for (i = 0; i < n_entries; i++, dent = (fs_dent_info_t *)
		    ((char *)dent + dent->fd_len)) {

			if (VERBOSE(ftp))
				NDMP_LOG(LOG_DEBUG, "i %u dname: \"%s\"",
				    dent->fd_fh.fh_fid, dent->fd_name);

			if ((pl + strlen(dent->fd_name)) > PATH_MAX) {
				traverse_stats.fss_longpath_err++;

				NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
				    pnp->tn_path, dent->fd_name);
				if (STOP_ONLONG(ftp))
					rv = -ENAMETOOLONG;
				free(dent->fd_fh.fh_fpath);
				continue;
			}

			/*
			 * The entry is not a directory so the callback
			 * function must be called.
			 */
			if (!S_ISDIR(dent->fd_attr.st_mode)) {
				traverse_stats.fss_nondir_calls++;

				en.tn_path = dent->fd_name;
				en.tn_fh = &dent->fd_fh;
				en.tn_st = &dent->fd_attr;
				rv = CALLBACK(pnp, &en);
				dent->fd_fh.fh_fpath = NULL;
				if (rv < 0)
					break;
				if (rv == FST_SKIP) {
					traverse_stats.fss_nondir_skipped++;
					break;
				}
			}
		}
	}

	free(buf);
	(void) close(fd);
	return (rv);
}