Пример #1
0
static struct config_file *add_ntp_program(struct timemaster_config *config,
					   struct script *script)
{
	struct config_file *ntp_config = xmalloc(sizeof(*ntp_config));
	char **command = NULL;

	ntp_config->content = xstrdup("");

	switch (config->ntp_program) {
	case CHRONYD:
		extend_config_string(&ntp_config->content,
				     config->chronyd.settings);
		ntp_config->path = string_newf("%s/chrony.conf",
					       config->rundir);
		command = get_chronyd_command(&config->chronyd, ntp_config);
		break;
	case NTPD:
		extend_config_string(&ntp_config->content,
				     config->ntpd.settings);
		ntp_config->path = string_newf("%s/ntp.conf", config->rundir);
		command = get_ntpd_command(&config->ntpd, ntp_config);
		break;
	}

	parray_append((void ***)&script->configs, ntp_config);
	parray_append((void ***)&script->commands, command);

	return ntp_config;
}
Пример #2
0
/*
 * List files, symbolic links and directories in the directory "root" and add
 * pgFile objects to "files".  We add "root" to "files" if add_root is true.
 *
 * If the sub-directory name is in "exclude" list, the sub-directory itself is
 * listed but the contents of the sub-directory is ignored.
 *
 * When omit_symlink is true, symbolic link is ignored and only file or
 * directory llnked to will be listed.
 */
void
dir_list_file(parray *files, const char *root, const char *exclude[], bool omit_symlink, bool add_root)
{
	char path[MAXPGPATH];
	char buf[MAXPGPATH * 2];
	char black_item[MAXPGPATH * 2];
	parray *black_list = NULL;

	join_path_components(path, backup_path, PG_BLACK_LIST);
	if (root && pgdata && strcmp(root, pgdata) == 0 &&
	    fileExists(path))
	{
		FILE *black_list_file = NULL;
		black_list = parray_new();
		black_list_file = fopen(path, "r");
		if (black_list_file == NULL)
			ereport(ERROR,
				(errcode(ERROR_SYSTEM),
				 errmsg("could not open black_list: %s", strerror(errno))));
		while (fgets(buf, lengthof(buf), black_list_file) != NULL)
		{
			join_path_components(black_item, pgdata, buf);
			if (black_item[strlen(black_item) - 1] == '\n')
				black_item[strlen(black_item) - 1] = '\0';
			if (black_item[0] == '#' || black_item[0] == '\0')
				continue;
			parray_append(black_list, black_item);
		}
		fclose(black_list_file);
		parray_qsort(black_list, BlackListCompare);
		dir_list_file_internal(files, root, exclude, omit_symlink, add_root, black_list);
	}
	else
		dir_list_file_internal(files, root, exclude, omit_symlink, add_root, NULL);
}
Пример #3
0
static void extend_string_array(char ***a, char **strings)
{
	char **s;

	for (s = strings; *s; s++)
		parray_append((void ***)a, xstrdup(*s));
}
Пример #4
0
static struct source *source_ptp_parse(char *parameter, char **settings)
{
	char *name, *value;
	struct source *source;
	int r = 0;

	source = xmalloc(sizeof(*source));
	source->type = PTP_DOMAIN;
	source->ptp.delay = DEFAULT_PTP_DELAY;
	source->ptp.ntp_poll = DEFAULT_PTP_NTP_POLL;
	source->ptp.phc2sys_poll = DEFAULT_PTP_PHC2SYS_POLL;
	source->ptp.interfaces = (char **)parray_new();
	source->ptp.ptp4l_settings = (char **)parray_new();
	source->ptp.ntp_options = xstrdup("");

	if (parse_int(parameter, &source->ptp.domain)) {
		pr_err("invalid ptp_domain number %s", parameter);
		goto failed;
	}

	for (; *settings; settings++) {
		parse_setting(*settings, &name, &value);
		if (!strcasecmp(name, "delay")) {
			r = parse_double(value, &source->ptp.delay);
		} else if (!strcasecmp(name, "ntp_poll")) {
			r = parse_int(value, &source->ptp.ntp_poll);
		} else if (!strcasecmp(name, "phc2sys_poll")) {
			r = parse_int(value, &source->ptp.phc2sys_poll);
		} else if (!strcasecmp(name, "ptp4l_option")) {
			parray_append((void ***)&source->ptp.ptp4l_settings,
				      xstrdup(value));
		} else if (!strcasecmp(name, "ntp_options")) {
			replace_string(value, &source->ptp.ntp_options);
		} else if (!strcasecmp(name, "interfaces")) {
			parse_words(value, &source->ptp.interfaces);
		} else {
			pr_err("unknown ptp_domain setting %s", name);
			goto failed;
		}

		if (r) {
			pr_err("invalid value %s for %s", value, name);
			goto failed;
		}
	}

	if (!*source->ptp.interfaces) {
		pr_err("no interfaces specified for ptp_domain %d",
		       source->ptp.domain);
		goto failed;
	}

	return source;
failed:
	source_destroy(source);
	return NULL;
}
Пример #5
0
static void init_program_config(struct program_config *config,
				const char *name, ...)
{
	const char *s;
	va_list ap;

	config->path = xstrdup(name);
	config->settings = (char **)parray_new();
	config->options = (char **)parray_new();

	va_start(ap, name);

	/* add default options and settings */
	while ((s = va_arg(ap, const char *)))
		parray_append((void ***)&config->options, xstrdup(s));
	while ((s = va_arg(ap, const char *)))
		parray_append((void ***)&config->settings, xstrdup(s));

	va_end(ap);
}
Пример #6
0
static int parse_section(char **settings, char *name,
			 struct timemaster_config *config)
{
	struct source *source = NULL;
	char ***settings_dst = NULL;
	char *parameter = parse_word(name);

	if (!strcasecmp(name, "ntp_server")) {
		source = source_ntp_parse(parameter, settings);
		if (!source)
			return 1;
	} else if (!strcasecmp(name, "ptp_domain")) {
		source = source_ptp_parse(parameter, settings);
		if (!source)
			return 1;
	} else if (!strcasecmp(name, "chrony.conf")) {
		settings_dst = &config->chronyd.settings;
	} else if (!strcasecmp(name, "ntp.conf")) {
		settings_dst = &config->ntpd.settings;
	} else if (!strcasecmp(name, "ptp4l.conf")) {
		settings_dst = &config->ptp4l.settings;
	} else if (!strcasecmp(name, "chronyd")) {
		if (parse_program_settings(settings, &config->chronyd))
			return 1;
	} else if (!strcasecmp(name, "ntpd")) {
		if (parse_program_settings(settings, &config->ntpd))
			return 1;
	} else if (!strcasecmp(name, "phc2sys")) {
		if (parse_program_settings(settings, &config->phc2sys))
			return 1;
	} else if (!strcasecmp(name, "ptp4l")) {
		if (parse_program_settings(settings, &config->ptp4l))
			return 1;
	} else if (!strcasecmp(name, "timemaster")) {
		if (parse_timemaster_settings(settings, config))
			return 1;
	} else {
		pr_err("unknown section %s", name);
		return 1;
	}

	if (source)
		parray_append((void ***)&config->sources, source);

	if (settings_dst) {
		free_parray((void **)*settings_dst);
		*settings_dst = (char **)parray_new();
		extend_string_array(settings_dst, settings);
	}

	return 0;
}
Пример #7
0
static void parse_words(char *s, char ***a)
{
	char *w;

	if (**a) {
		free_parray((void **)(*a));
		*a = (char **)parray_new();
	}
	while (*s) {
		w = s;
		s = parse_word(s);
		parray_append((void ***)a, xstrdup(w));
	}
}
Пример #8
0
/*
 * Construct parray of pgFile from the file list.
 * If root is not NULL, path will be absolute path.
 */
parray *
dir_read_file_list(const char *root, const char *file_txt)
{
	FILE   *fp;
	parray *files;
	char	buf[MAXPGPATH * 2];

	fp = fopen(file_txt, "rt");
	if (fp == NULL)
		ereport(ERROR,
			((errno == ENOENT ? errcode(ERROR_CORRUPTED) : errcode(ERROR_SYSTEM)),
			 errmsg("could not open \"%s\": %s", file_txt, strerror(errno))));

	files = parray_new();

	while (fgets(buf, lengthof(buf), fp))
	{
		char			path[MAXPGPATH];
		char			type;
		unsigned long	write_size;
		pg_crc32c		crc;
		unsigned int	mode;	/* bit length of mode_t depends on platforms */
		struct tm		tm;
		pgFile		   *file;

		memset(&tm, 0, sizeof(tm));
		if (sscanf(buf, "%s %c %lu %u %o %d-%d-%d %d:%d:%d",
			path, &type, &write_size, &crc, &mode,
			&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
			&tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 11)
		{
			ereport(ERROR,
				(errcode(ERROR_CORRUPTED),
				 errmsg("invalid format found in \"%s\"", file_txt)));
		}
		if (type != 'f' && type != 'F' && type != 'd' && type != 'l')
		{
			ereport(ERROR,
				(errcode(ERROR_CORRUPTED),
				 errmsg("invalid type '%c' found in \"%s\"", type, file_txt)));
		}
		tm.tm_isdst = -1;

		file = (pgFile *) pgut_malloc(offsetof(pgFile, path) +
					(root ? strlen(root) + 1 : 0) + strlen(path) + 1);

		tm.tm_year -= 1900;
		tm.tm_mon -= 1;
		file->mtime = mktime(&tm);
		file->mode = mode |
			((type == 'f' || type == 'F') ? S_IFREG :
			 type == 'd' ? S_IFDIR : type == 'l' ? S_IFLNK : 0);
		file->size = 0;
		file->read_size = 0;
		file->write_size = write_size;
		file->crc = crc;
		file->is_datafile = (type == 'F' ? true : false);
		file->linked = NULL;
		if (root)
			sprintf(file->path, "%s/%s", root, path);
		else
			strcpy(file->path, path);

		parray_append(files, file);
	}

	fclose(fp);

	/* file.txt is sorted, so this qsort is redundant */
	parray_qsort(files, pgFileComparePath);

	return files;
}
Пример #9
0
void
dir_list_file_internal(parray *files, const char *root, const char *exclude[],
			bool omit_symlink, bool add_root, parray *black_list)
{
	pgFile *file;

	file = pgFileNew(root, omit_symlink);
	if (file == NULL)
		return;

	/* skip if the file is in black_list defined by user */
	if (black_list && parray_bsearch(black_list, root, BlackListCompare))
	{
		/* found in black_list. skip this item */
		return;
	}

	if (add_root)
		parray_append(files, file);

	/* chase symbolic link chain and find regular file or directory */
	while (S_ISLNK(file->mode))
	{
		ssize_t	len;
		char	linked[MAXPGPATH];

		len = readlink(file->path, linked, sizeof(linked));
		if (len == -1)
		{
			ereport(ERROR,
				(errcode(ERROR_SYSTEM),
				 errmsg("could not read link \"%s\": %s", file->path, strerror(errno))));
		}
		linked[len] = '\0';
		file->linked = pgut_strdup(linked);

		/* make absolute path to read linked file */
		if (linked[0] != '/')
		{
			char	dname[MAXPGPATH];
			char	absolute[MAXPGPATH];

			strncpy(dname, file->path, lengthof(dname));
			join_path_components(absolute, dirname(dname), linked);
			file = pgFileNew(absolute, omit_symlink);
		}
		else
			file = pgFileNew(file->linked, omit_symlink);

		/* linked file is not found, stop following link chain */
		if (file == NULL)
			return;

		parray_append(files, file);
	}

	/*
	 * If the entry was a directory, add it to the list and add call this
	 * function recursivelly.
	 * If the directory name is in the exclude list, do not list the contents.
	 */
	while (S_ISDIR(file->mode))
	{
		int				i;
		bool			skip = false;
		DIR			    *dir;
		struct dirent   *dent;
		char		    *dirname;

		/* skip entry which matches exclude list */
	   	dirname = strrchr(file->path, '/');
		if (dirname == NULL)
			dirname = file->path;
		else
			dirname++;

		/*
		 * If the item in the exclude list starts with '/', compare to the
		 * absolute path of the directory. Otherwise compare to the directory
		 * name portion.
		 */
		for (i = 0; exclude && exclude[i]; i++)
		{
			if (exclude[i][0] == '/')
			{
				if (strcmp(file->path, exclude[i]) == 0)
				{
					skip = true;
					break;
				}
			}
			else
			{
				if (strcmp(dirname, exclude[i]) == 0)
				{
					skip = true;
					break;
				}
			}
		}
		if (skip)
			break;

		/* open directory and list contents */
		dir = opendir(file->path);
		if (dir == NULL)
		{
			if (errno == ENOENT)
			{
				/* maybe the direcotry was removed */
				return;
			}
			ereport(ERROR,
				(errcode(ERROR_SYSTEM),
				 errmsg("could not open directory \"%s\": %s",
					file->path, strerror(errno))));
		}

		errno = 0;
		while ((dent = readdir(dir)))
		{
			char child[MAXPGPATH];

			/* skip entries point current dir or parent dir */
			if (strcmp(dent->d_name, ".") == 0 ||
				strcmp(dent->d_name, "..") == 0)
				continue;

			join_path_components(child, file->path, dent->d_name);
			dir_list_file_internal(files, child, exclude, omit_symlink, true, black_list);
		}
		if (errno && errno != ENOENT)
		{
			int errno_tmp = errno;
			closedir(dir);
			ereport(ERROR,
				(errcode(ERROR_SYSTEM),
				 errmsg("could not read directory \"%s\": %s",
					file->path, strerror(errno_tmp))));
		}
		closedir(dir);

		break;	/* pseudo loop */
	}

	parray_qsort(files, pgFileComparePath);
}
Пример #10
0
static int add_ptp_source(struct ptp_domain *source,
			  struct timemaster_config *config, int *shm_segment,
			  int ***allocated_phcs, char **ntp_config,
			  struct script *script)
{
	struct config_file *config_file;
	char **command, *uds_path, **interfaces;
	int i, j, num_interfaces, *phc, *phcs, hw_ts;
	struct sk_ts_info ts_info;

	pr_debug("adding PTP domain %d", source->domain);

	hw_ts = SOF_TIMESTAMPING_TX_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE |
		SOF_TIMESTAMPING_RAW_HARDWARE;

	for (num_interfaces = 0;
	     source->interfaces[num_interfaces]; num_interfaces++)
		;

	if (!num_interfaces)
		return 0;

	/* get PHCs used by specified interfaces */
	phcs = xmalloc(num_interfaces * sizeof(int));
	for (i = 0; i < num_interfaces; i++) {
		phcs[i] = -1;

		/* check if the interface has a usable PHC */
		if (sk_get_ts_info(source->interfaces[i], &ts_info)) {
			pr_err("failed to get time stamping info for %s",
			       source->interfaces[i]);
			free(phcs);
			return 1;
		}

		if (!ts_info.valid ||
		    ((ts_info.so_timestamping & hw_ts) != hw_ts)) {
			pr_debug("interface %s: no PHC", source->interfaces[i]);
			continue;
		}

		pr_debug("interface %s: PHC %d", source->interfaces[i],
			 ts_info.phc_index);

		/* and the PHC isn't already used in another source */
		for (j = 0; (*allocated_phcs)[j]; j++) {
			if (*(*allocated_phcs)[j] == ts_info.phc_index) {
				pr_debug("PHC %d already allocated",
					 ts_info.phc_index);
				break;
			}
		}
		if (!(*allocated_phcs)[j])
			phcs[i] = ts_info.phc_index;
	}

	for (i = 0; i < num_interfaces; i++) {
		/* skip if already used by ptp4l in this domain */
		if (phcs[i] == -2)
			continue;

		interfaces = (char **)parray_new();
		parray_append((void ***)&interfaces, source->interfaces[i]);

		/* merge all interfaces sharing PHC to one ptp4l command */
		if (phcs[i] >= 0) {
			for (j = i + 1; j < num_interfaces; j++) {
				if (phcs[i] == phcs[j]) {
					parray_append((void ***)&interfaces,
						      source->interfaces[j]);
					/* mark the interface as used */
					phcs[j] = -2;
				}
			}

			/* don't use this PHC in other sources */
			phc = xmalloc(sizeof(int));
			*phc = phcs[i];
			parray_append((void ***)allocated_phcs, phc);
		}

		uds_path = string_newf("%s/ptp4l.%d.socket",
				       config->rundir, *shm_segment);

		config_file = xmalloc(sizeof(*config_file));
		config_file->path = string_newf("%s/ptp4l.%d.conf",
						config->rundir, *shm_segment);
		config_file->content = xstrdup("[global]\n");
		extend_config_string(&config_file->content,
				     config->ptp4l.settings);
		extend_config_string(&config_file->content,
				     source->ptp4l_settings);
		string_appendf(&config_file->content,
			       "slaveOnly 1\n"
			       "domainNumber %d\n"
			       "uds_address %s\n",
			       source->domain, uds_path);

		if (phcs[i] >= 0) {
			/* HW time stamping */
			command = get_ptp4l_command(&config->ptp4l, config_file,
						    interfaces, 1);
			parray_append((void ***)&script->commands, command);

			command = get_phc2sys_command(&config->phc2sys,
						      source->domain,
						      source->phc2sys_poll,
						      *shm_segment, uds_path);
			parray_append((void ***)&script->commands, command);
		} else {
			/* SW time stamping */
			command = get_ptp4l_command(&config->ptp4l, config_file,
						    interfaces, 0);
			parray_append((void ***)&script->commands, command);

			string_appendf(&config_file->content,
				       "clock_servo ntpshm\n"
				       "ntpshm_segment %d\n", *shm_segment);
		}

		parray_append((void ***)&script->configs, config_file);

		add_shm_source(*shm_segment, source->ntp_poll,
			       source->phc2sys_poll, source->delay,
			       source->ntp_options, "PTP", config, ntp_config);

		(*shm_segment)++;

		free(uds_path);
		free(interfaces);
	}

	free(phcs);

	return 0;
}
Пример #11
0
static struct timemaster_config *config_parse(char *path)
{
	struct timemaster_config *config = xcalloc(1, sizeof(*config));
	FILE *f;
	char buf[4096], *line, *section_name = NULL;
	char **section_lines = NULL;
	int ret = 0;

	config->sources = (struct source **)parray_new();
	config->ntp_program = DEFAULT_NTP_PROGRAM;
	config->rundir = xstrdup(DEFAULT_RUNDIR);
	config->first_shm_segment = DEFAULT_FIRST_SHM_SEGMENT;

	init_program_config(&config->chronyd, "chronyd",
			    NULL, DEFAULT_CHRONYD_SETTINGS, NULL);
	init_program_config(&config->ntpd, "ntpd",
			    NULL, DEFAULT_NTPD_SETTINGS, NULL);
	init_program_config(&config->phc2sys, "phc2sys",
			    DEFAULT_PHC2SYS_OPTIONS, NULL, NULL);
	init_program_config(&config->ptp4l, "ptp4l",
			    DEFAULT_PTP4L_OPTIONS, NULL, NULL);

	f = fopen(path, "r");
	if (!f) {
		pr_err("failed to open %s: %m", path);
		free(config);
		return NULL;
	}

	while (fgets(buf, sizeof(buf), f)) {
		/* remove trailing and leading whitespace */
		for (line = buf + strlen(buf) - 1;
		     line >= buf && isspace(*line); line--)
			*line = '\0';
		for (line = buf; *line && isspace(*line); line++)
			;
		/* skip comments and empty lines */
		if (!*line || *line == '#')
			continue;

		if (*line == '[') {
			/* parse previous section before starting another */
			if (section_name) {
				if (parse_section(section_lines, section_name,
						  config)) {
					ret = 1;
					break;
				}
				free_parray((void **)section_lines);
				free(section_name);
			}
			section_name = parse_section_name(line);
			section_lines = (char **)parray_new();
			continue;
		}

		if (!section_lines) {
			pr_err("settings outside section");
			ret = 1;
			break;
		}

		parray_append((void ***)&section_lines, xstrdup(line));
	}

	if (!ret && section_name &&
	    parse_section(section_lines, section_name, config)) {
		ret = 1;
	}

	fclose(f);

	if (section_name)
		free(section_name);
	if (section_lines)
		free_parray((void **)section_lines);

	if (ret) {
		config_destroy(config);
		return NULL;
	}

	return config;
}