示例#1
0
int red_extension_read_eeprom_from_fs(uint8_t *buffer, int extension) {
	FILE *f;
	char file_name[128];
	int length;

	if (robust_snprintf(file_name, sizeof(file_name), "/tmp/new_eeprom_extension_%d.conf", extension) < 0) {
		return -1;
	}

	if ((f = fopen(file_name, "rb")) == NULL) {
		return -1;
	} else {
		length = fread(buffer, 1, EEPROM_SIZE, f);

		if (fclose(f) < 0) {
			log_warn("Could not close file %s", file_name);
		}

		if (remove(file_name) < 0) {
			log_warn("Could not delete file %s", file_name);
		}

		return length;
	}
}
示例#2
0
// sets errno on error
int conf_file_write(ConfFile *conf_file, const char *filename) {
	bool success = false;
	char filename_tmp[1024];
	FILE *fp = NULL;
	int i;
	ConfFileLine *line;

	if (robust_snprintf(filename_tmp, sizeof(filename_tmp), "%s.tmp", filename) < 0) {
		goto cleanup;
	}

	// open <filename>.tmp for writing
	fp = fopen(filename_tmp, "wb"); // FIXME: don't create as 0666 in all cases

	if (fp == NULL) {
		goto cleanup;
	}

	// write lines to <filename>.tmp
	for (i = 0; i < conf_file->lines.count; ++i) {
		line = array_get(&conf_file->lines, i);

		// if raw is != NULL then this line does not contain a name/value pair
		if (line->raw != NULL) {
			if (robust_fwrite(fp, line->raw, strlen(line->raw)) < 0) {
				goto cleanup;
			}
		} else {
			if (conf_file_write_escaped(fp, line->name, true) < 0) {
				goto cleanup;
			}

			if (robust_fwrite(fp, " =", 2) < 0) {
				goto cleanup;
			}

			if (*line->value != '\0') {
				if (robust_fwrite(fp, " ", 1) < 0) {
					goto cleanup;
				}

				if (conf_file_write_escaped(fp, line->value, false) < 0) {
					goto cleanup;
				}
			}
		}

		if (robust_fwrite(fp, END_OF_LINE, strlen(END_OF_LINE)) < 0) {
			goto cleanup;
		}
	}

	robust_fclose(fp);
	fp = NULL;

	// rename <filename>.tmp to <filename>. use MoveFileEx on Windows instead
	// of rename, because rename cannot replace existing files on Windows
#ifdef _WIN32
	if (!MoveFileExA(filename_tmp, filename, MOVEFILE_REPLACE_EXISTING)) {
		errno = ERRNO_WINAPI_OFFSET + GetLastError();

		goto cleanup;
	}
#else
	if (rename(filename_tmp, filename) < 0) {
		goto cleanup;
	}
#endif

	success = true;

cleanup:
	robust_fclose(fp);

	return success ? 0 : -1;
}
APIE program_scheduler_create(ProgramScheduler *program_scheduler,
                              ProgramSchedulerProcessSpawnedFunction process_spawned,
                              ProgramSchedulerStateChangedFunction state_changed,
                              void *opaque) {
	int phase = 0;
	Program *program = containerof(program_scheduler, Program, scheduler);
	APIE error_code;
	char bin_directory[1024];
	char *log_directory;
	String *dev_null_file_name;
	int i;
	String *environment;

	// format bin directory name
	if (robust_snprintf(bin_directory, sizeof(bin_directory), "%s/bin",
	                    program->root_directory->buffer) < 0) {
		error_code = api_get_error_code_from_errno();

		log_error("Could not format program bin directory name: %s (%d)",
		          get_errno_name(errno), errno);

		goto cleanup;
	}

	// create bin directory as default user (UID 1000, GID 1000)
	error_code = directory_create(bin_directory, DIRECTORY_FLAG_RECURSIVE,
	                              0755, 1000, 1000);

	if (error_code != API_E_SUCCESS) {
		goto cleanup;
	}

	// format log directory name
	if (asprintf(&log_directory, "%s/log", program->root_directory->buffer) < 0) {
		error_code = api_get_error_code_from_errno();

		log_error("Could not format program log directory name: %s (%d)",
		          get_errno_name(errno), errno);

		goto cleanup;
	}

	phase = 1;

	// create log directory as default user (UID 1000, GID 1000)
	error_code = directory_create(log_directory, DIRECTORY_FLAG_RECURSIVE,
	                              0755, 1000, 1000);

	if (error_code != API_E_SUCCESS) {
		goto cleanup;
	}

	// get '/dev/null' stock string object
	error_code = inventory_get_stock_string("/dev/null", &dev_null_file_name);

	if (error_code != API_E_SUCCESS) {
		goto cleanup;
	}

	phase = 2;

	program_scheduler->process_spawned = process_spawned;
	program_scheduler->state_changed = state_changed;
	program_scheduler->opaque = opaque;
	program_scheduler->absolute_working_directory = NULL;
	program_scheduler->absolute_stdin_file_name = NULL;
	program_scheduler->absolute_stdout_file_name = NULL;
	program_scheduler->absolute_stderr_file_name = NULL;
	program_scheduler->log_directory = log_directory;
	program_scheduler->dev_null_file_name = dev_null_file_name;
	program_scheduler->observer.function = program_scheduler_handle_observer;
	program_scheduler->observer.opaque = program_scheduler;
	program_scheduler->observer_state = PROCESS_OBSERVER_STATE_FINISHED;
	program_scheduler->shutdown = false;
	program_scheduler->waiting_for_brickd = !network_is_brickd_connected();
	program_scheduler->timer_active = false;
	program_scheduler->cron_active = false;
	program_scheduler->last_spawned_process = NULL;
	program_scheduler->last_spawned_timestamp = 0;
	program_scheduler->state = PROGRAM_SCHEDULER_STATE_STOPPED;
	program_scheduler->timestamp = time(NULL);
	program_scheduler->message = NULL;

	// if X11 is enabled...
	if (_x11_enabled) {
		for (i = 0; i < program->config.environment->items.count; ++i) {
			environment = *(String **)array_get(&program->config.environment->items, i);

			// ...and the DISPLAY environment variable is set...
			if (strncmp(environment->buffer, "DISPLAY=", strlen("DISPLAY=")) == 0) {
				// ...then use the process monitor to wait for lxpanel to start
				program_scheduler->observer_state = PROCESS_OBSERVER_STATE_PENDING;

				break;
			}
		}
	}

	// FIXME: only create timer for interval mode, otherwise this wastes a
	//        file descriptor per non-interval scheduler
	if (timer_create_(&program_scheduler->timer, program_scheduler_handle_timer,
	                  program_scheduler) < 0) {
		error_code = api_get_error_code_from_errno();

		log_error("Could not create timer: %s (%d)",
		          get_errno_name(errno), errno);

		goto cleanup;
	}

	phase = 3;

cleanup:
	switch (phase) { // no breaks, all cases fall through intentionally
	case 2:
		string_unlock_and_release(dev_null_file_name);

	case 1:
		free(log_directory);

	default:
		break;
	}

	return phase == 3 ? API_E_SUCCESS : error_code;
}
static File *program_scheduler_prepare_continuous_log(ProgramScheduler *program_scheduler,
                                                      struct timeval timestamp,
                                                      const char *suffix) {
	struct tm localized_timestamp;
	char iso8601dt[64] = "unknown";
	char iso8601usec[16] = "";
	char iso8601tz[16] = "";
	char buffer[1024];
	APIE error_code;
	String *name;
	File *file;

	// format ISO 8601 date, time and timezone offset
	if (localtime_r(&timestamp.tv_sec, &localized_timestamp) != NULL) {
		// can use common ISO 8601 format YYYY-MM-DDThh:mm:ss.uuuuuu±hhmm
		// because this timestamp is not part of a filename
		strftime(iso8601dt, sizeof(iso8601dt), "%Y-%m-%dT%H:%M:%S", &localized_timestamp);
		snprintf(iso8601usec, sizeof(iso8601usec), ".%06d", (int)timestamp.tv_usec);
		strftime(iso8601tz, sizeof(iso8601tz), "%z", &localized_timestamp);
	}

	// format log filename
	if (robust_snprintf(buffer, sizeof(buffer), "%s/continuous_%s.log",
	                    program_scheduler->log_directory, suffix) < 0) {
		program_scheduler_handle_error(program_scheduler, true,
		                               "Could not format %s log file name: %s (%d)",
		                               suffix, get_errno_name(errno), errno);

		return NULL;
	}

	error_code = string_wrap(buffer, NULL,
	                         OBJECT_CREATE_FLAG_INTERNAL |
	                         OBJECT_CREATE_FLAG_LOCKED,
	                         NULL, &name);

	if (error_code != API_E_SUCCESS) {
		program_scheduler_handle_error(program_scheduler, true,
		                               "Could not wrap %s log file name into string object: %s (%d)",
		                               suffix, api_get_error_code_name(error_code), error_code);

		return NULL;
	}

	// open log file
	error_code = file_open(name->base.id,
	                       FILE_FLAG_WRITE_ONLY | FILE_FLAG_CREATE | FILE_FLAG_APPEND,
	                       0644, 1000, 1000,
	                       NULL, OBJECT_CREATE_FLAG_INTERNAL, NULL, &file);

	string_unlock_and_release(name);

	if (error_code != API_E_SUCCESS) {
		program_scheduler_handle_error(program_scheduler, true,
		                               "Could not open/create %s log file: %s (%d)",
		                               suffix, api_get_error_code_name(error_code), error_code);

		return NULL;
	}

	// format header
	if (robust_snprintf(buffer, sizeof(buffer), "\n\n%s%s%s\n-------------------------------------------------------------------------------\n",
	                    iso8601dt, iso8601usec, iso8601tz) < 0) {
		program_scheduler_handle_error(program_scheduler, true,
		                               "Could not format timestamp for %s log file: %s (%d)",
		                               suffix, get_errno_name(errno), errno);

		file_release(file);

		return NULL;
	}

	// write header
	if (write(file->fd, buffer, strlen(buffer)) < 0) {
		program_scheduler_handle_error(program_scheduler, true,
		                               "Could not write timestamp to %s log file: %s (%d)",
		                               suffix, get_errno_name(errno), errno);

		file_release(file);

		return NULL;
	}

	return file;
}
static File *program_scheduler_prepare_individual_log(ProgramScheduler *program_scheduler,
                                                      struct timeval timestamp,
                                                      const char *suffix) {
	uint64_t microseconds = (uint64_t)timestamp.tv_sec * 1000000 + (uint64_t)timestamp.tv_usec;
	struct tm localized_timestamp;
	char iso8601[128] = "unknown";
	char buffer[1024];
	struct stat st;
	APIE error_code;
	int counter = 0;
	String *name;
	File *file;

	// format ISO 8601 date, time and timezone offset
	if (localtime_r(&timestamp.tv_sec, &localized_timestamp) != NULL) {
		// use ISO 8601 format YYYYMMDDThhmmss±hhmm instead of the common
		// YYYY-MM-DDThh:mm:ss±hhmm because the colons in there can create
		// problems on Windows which does not allow colons in filenames
		strftime(iso8601, sizeof(iso8601), "%Y%m%dT%H%M%S%z", &localized_timestamp);
	}

	// create log file, include microsecond timestamp to reduce the chance for
	// file name collisions and as easy-to-parse timestamp for brickv
	if (robust_snprintf(buffer, sizeof(buffer), "%s/%s_%"PRIu64"_%s.log",
	                    program_scheduler->log_directory,
	                    iso8601, microseconds, suffix) < 0) {
		program_scheduler_handle_error(program_scheduler, true,
		                               "Could not format %s log file name: %s (%d)",
		                               suffix, get_errno_name(errno), errno);

		return NULL;
	}

	while (counter < 1000) {
		// only try to create the log file if it's not already existing
		if (lstat(buffer, &st) < 0) {
			error_code = string_wrap(buffer, NULL,
			                         OBJECT_CREATE_FLAG_INTERNAL |
			                         OBJECT_CREATE_FLAG_LOCKED,
			                         NULL, &name);

			if (error_code != API_E_SUCCESS) {
				program_scheduler_handle_error(program_scheduler, true,
				                               "Could not wrap %s log file name into string object: %s (%d)",
				                               suffix, api_get_error_code_name(error_code), error_code);

				return NULL;
			}

			error_code = file_open(name->base.id,
			                       FILE_FLAG_WRITE_ONLY | FILE_FLAG_CREATE | FILE_FLAG_EXCLUSIVE,
			                       0644, 1000, 1000,
			                       NULL, OBJECT_CREATE_FLAG_INTERNAL, NULL, &file);

			string_unlock_and_release(name);

			if (error_code == API_E_SUCCESS) {
				return file;
			}

			// if file_open failed with an error different from API_E_ALREADY_EXISTS
			// then give up, there is no point trying to recover this situation
			if (error_code != API_E_ALREADY_EXISTS) {
				program_scheduler_handle_error(program_scheduler, true,
				                               "Could not create %s log file: %s (%d)",
				                               suffix, api_get_error_code_name(error_code), error_code);

				return NULL;
			}
		}

		if (robust_snprintf(buffer, sizeof(buffer), "%s/%s_%"PRIu64"+%03d_%s.log",
		                    program_scheduler->log_directory,
		                    iso8601, microseconds, ++counter, suffix) < 0) {
			program_scheduler_handle_error(program_scheduler, true,
			                               "Could not format %s log file name: %s (%d)",
			                               suffix, get_errno_name(errno), errno);

			return NULL;
		}
	}

	program_scheduler_handle_error(program_scheduler, true,
	                               "Could not create %s log file within 1000 attempts",
	                               suffix);

	return NULL;
}
示例#6
0
static int prepare_paths(void) {
	char *home;
	struct passwd *pw;
	char brickd_dirname[1024];
	struct stat st;

	if (getuid() == 0) {
		return 0;
	}

	home = getenv("HOME");

	if (home == NULL || *home == '\0') {
		pw = getpwuid(getuid());

		if (pw == NULL) {
			fprintf(stderr, "Could not determine home directory: %s (%d)\n",
			        get_errno_name(errno), errno);

			return -1;
		}

		home = pw->pw_dir;
	}

	if (robust_snprintf(brickd_dirname, sizeof(brickd_dirname),
	                    "%s/.brickd", home) < 0) {
		fprintf(stderr, "Could not format ~/.brickd directory name: %s (%d)\n",
		        get_errno_name(errno), errno);

		return -1;
	}

	if (robust_snprintf(_config_filename, sizeof(_config_filename),
	                    "%s/.brickd/brickd.conf", home) < 0) {
		fprintf(stderr, "Could not format ~/.brickd/brickd.conf file name: %s (%d)\n",
		        get_errno_name(errno), errno);

		return -1;
	}

	if (robust_snprintf(_pid_filename, sizeof(_pid_filename),
	                    "%s/.brickd/brickd.pid", home) < 0) {
		fprintf(stderr, "Could not format ~/.brickd/brickd.pid file name: %s (%d)\n",
		        get_errno_name(errno), errno);

		return -1;
	}

	if (robust_snprintf(_log_filename, sizeof(_log_filename),
	                    "%s/.brickd/brickd.log", home) < 0) {
		fprintf(stderr, "Could not format ~/.brickd/brickd.log file name: %s (%d)\n",
		        get_errno_name(errno), errno);

		return -1;
	}

	if (mkdir(brickd_dirname, 0755) < 0) {
		if (errno != EEXIST) {
			fprintf(stderr, "Could not create directory '%s': %s (%d)\n",
			        brickd_dirname, get_errno_name(errno), errno);

			return -1;
		}

		if (stat(brickd_dirname, &st) < 0) {
			fprintf(stderr, "Could not get information for '%s': %s (%d)\n",
			        brickd_dirname, get_errno_name(errno), errno);

			return -1;
		}

		if (!S_ISDIR(st.st_mode)) {
			fprintf(stderr, "Expecting '%s' to be a directory\n", brickd_dirname);

			return -1;
		}
	}

	return 0;
}
示例#7
0
int inventory_load_programs(void) {
	bool success = false;
	DIR *dp;
	struct dirent *dirent;
	const char *identifier;
	char directory[1024];
	char filename[1024];
	APIE error_code;

	log_debug("Loading program configurations from '%s'", _programs_directory);

	dp = opendir(_programs_directory);

	if (dp == NULL) {
		if (errno == ENOENT) {
			// no programs directory, nothing to load
			return 0;
		}

		log_error("Could not open programs directory '%s': %s (%d)",
		          _programs_directory, get_errno_name(errno), errno);

		return -1;
	}

	for (;;) {
		errno = 0;
		dirent = readdir(dp);

		if (dirent == NULL) {
			if (errno == 0) {
				// end-of-directory reached
				break;
			} else {
				log_error("Could not get next entry of programs directory '%s': %s (%d)",
				          _programs_directory, get_errno_name(errno), errno);

				goto cleanup;
			}
		}

		if (strcmp(dirent->d_name, ".") == 0 ||
		    strcmp(dirent->d_name, "..") == 0 ||
		    dirent->d_type != DT_DIR) {
			continue;
		}

		identifier = dirent->d_name;

		if (robust_snprintf(directory, sizeof(directory), "%s/%s",
		                    _programs_directory, identifier) < 0) {
			log_error("Could not format program directory name: %s (%d)",
			          get_errno_name(errno), errno);

			goto cleanup;
		}

		if (robust_snprintf(filename, sizeof(filename), "%s/program.conf",
		                    directory) < 0) {
			log_error("Could not format program config file name: %s (%d)",
			          get_errno_name(errno), errno);

			goto cleanup;
		}

		log_debug("Loading program from '%s'", directory);

		error_code = program_load(identifier, directory, filename);

		if (error_code != API_E_SUCCESS) {
			// load errors are non-fatal
			log_debug("Could not load program from '%s', ignoring program: %s (%d)",
			          directory, api_get_error_code_name(error_code), error_code);
		}
	}

	success = true;

cleanup:
	closedir(dp);

	return success ? 0 : -1;
}
示例#8
0
int inventory_init(void) {
	int phase = 0;
	struct passwd *pw;
	int type;

	log_debug("Initializing inventory subsystem");

	// get home directory of the default user (UID 1000)
	pw = getpwuid(1000);

	if (pw == NULL) {
		log_error("Could not determine home directory for UID 1000: %s (%d)",
		          get_errno_name(errno), errno);

		goto cleanup;
	}

	if (robust_snprintf(_programs_directory, sizeof(_programs_directory),
	                    "%s/programs", pw->pw_dir) < 0) {
		log_error("Could not format programs directory name: %s (%d)",
		          get_errno_name(errno), errno);

		goto cleanup;
	}

	// create session array
	if (array_create(&_sessions, 32, sizeof(Session *), true) < 0) {
		log_error("Could not create session array: %s (%d)",
		          get_errno_name(errno), errno);

		goto cleanup;
	}

	phase = 1;

	// create object arrays
	for (type = OBJECT_TYPE_STRING; type <= OBJECT_TYPE_PROGRAM; ++type) {
		if (array_create(&_objects[type], 32, sizeof(Object *), true) < 0) {
			log_error("Could not create %s object array: %s (%d)",
			          object_get_type_name(type), get_errno_name(errno), errno);

			goto cleanup;
		}

		phase = 2;
	}

	// create stock string array
	if (array_create(&_stock_strings, 32, sizeof(String *), true) < 0) {
		log_error("Could not create stock string array: %s (%d)",
		          get_errno_name(errno), errno);

		goto cleanup;
	}

	phase = 3;

cleanup:
	switch (phase) { // no breaks, all cases fall through intentionally
	case 2:
		for (--type; type >= OBJECT_TYPE_STRING; --type) {
			array_destroy(&_objects[type], inventory_destroy_object);
		}

	case 1:
		array_destroy(&_sessions, inventory_destroy_session);

	default:
		break;
	}

	return phase == 3 ? 0 : -1;
}