/*
|
* Copyright (C) 2017 The Android Open Source Project
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
|
#include <ctype.h>
|
#include <getopt.h>
|
#include <stdio.h>
|
#include <stdlib.h>
|
#include <string.h>
|
#include <unistd.h>
|
|
#include "dt_table.h"
|
#include "mkdtimg_core.h"
|
|
|
struct cfg_create_params {
|
const char *img_filename;
|
const char *cfg_filename;
|
const char *dtb_dir;
|
};
|
|
static const char short_options[] = "d:";
|
static struct option options[] = {
|
{ "dtb-dir", required_argument, NULL, 'd' },
|
{ 0, 0, NULL, 0 }
|
};
|
|
|
static char *trim_line(char *line) {
|
/* Find the end of the string or the first of '#' */
|
char *end = line;
|
while (*end != '\0' && *end != '#') {
|
end++;
|
}
|
do {
|
end--;
|
} while (end >= line && isspace(*end));
|
|
*(end + 1) = '\0';
|
|
while (isspace(*line)) {
|
line++;
|
}
|
return line;
|
}
|
|
static int parse_config_entry_count(FILE *cfg_fp) {
|
int count = 0;
|
|
/* Any line without prefix spaces is entry filename */
|
char line[1024];
|
while (fgets(line, sizeof(line), cfg_fp) != NULL) {
|
char c = line[0];
|
if (c == '\0' || isspace(c) || c == '#') continue;
|
count++;
|
}
|
|
return count;
|
}
|
|
static int output_img_with_config(FILE *img_fp, FILE *cfg_fp) {
|
int entry_count = parse_config_entry_count(cfg_fp);
|
struct dt_image_writer *writer = dt_image_writer_start(img_fp, entry_count);
|
|
fseek(cfg_fp, 0, SEEK_SET); /* Reset the file pos to head */
|
|
int is_entry = 0;
|
char line[1024];
|
while (fgets(line, sizeof(line), cfg_fp) != NULL) {
|
char *trimmed = trim_line(line);
|
if (trimmed[0] == '\0') {
|
/* empty line, pass */
|
continue;
|
}
|
|
if (trimmed == line) {
|
/* This line is a file name,
|
because it start from the first char of the line */
|
if (dt_image_writer_add_entry(writer, trimmed) != 0) {
|
return -1;
|
}
|
is_entry = 1;
|
continue;
|
}
|
|
char *option, *value;
|
if (parse_option(&option, &value, trimmed) != 0) {
|
fprintf(stderr, "Wrong syntax: %s\n", trimmed);
|
return -1;
|
}
|
|
int ret = is_entry ?
|
set_entry_options(writer, option, value) :
|
set_global_options(writer, option, value);
|
if (ret != 0) {
|
fprintf(stderr, "Unknown option: %s\n", option);
|
return -1;
|
}
|
}
|
|
if (dt_image_writer_end(writer) != 0) {
|
return -1;
|
}
|
|
return 0;
|
}
|
|
static int process_command_cfg_create(const struct cfg_create_params *params) {
|
int ret = -1;
|
FILE *cfg_fp = NULL;
|
FILE *img_fp = NULL;
|
|
cfg_fp = fopen(params->cfg_filename, "r");
|
if (cfg_fp == NULL) {
|
fprintf(stderr, "Can not open config file: %s\n", params->cfg_filename);
|
goto end;
|
}
|
|
printf("create image file: %s...\n", params->img_filename);
|
|
img_fp = fopen(params->img_filename, "wb");
|
if (img_fp == NULL) {
|
fprintf(stderr, "Can not create file: %s\n", params->img_filename);
|
goto end;
|
}
|
|
if (params->dtb_dir != NULL) {
|
if (chdir(params->dtb_dir) != 0) {
|
fprintf(stderr, "Can not switch to directory: %s\n", params->dtb_dir);
|
goto end;
|
}
|
}
|
|
ret = output_img_with_config(img_fp, cfg_fp);
|
if (ret < 0)
|
fprintf(stderr, "Can not output image with config: %s\n",
|
params->cfg_filename);
|
|
end:
|
if (img_fp) {
|
fclose(img_fp);
|
if (ret < 0) unlink(params->img_filename);
|
}
|
if (cfg_fp) fclose(cfg_fp);
|
|
return ret;
|
}
|
|
void handle_usage_cfg_create(FILE *out_fp, const char *prog_name) {
|
fprintf(out_fp, " %s cfg_create <image_file> <config_file> (<option>...)\n\n", prog_name);
|
fprintf(out_fp,
|
" options:\n"
|
" -d, --dtb-dir The path to load dtb files.\n"
|
" Default is load from the current path.\n");
|
}
|
|
int handle_command_cfg_create(int argc, char *argv[], int arg_start) {
|
if (argc - arg_start < 2) {
|
handle_usage_cfg_create(stderr, argv[0]);
|
return 1;
|
}
|
|
struct cfg_create_params params;
|
memset(¶ms, 0, sizeof(params));
|
params.img_filename = argv[arg_start];
|
params.cfg_filename = argv[arg_start + 1];
|
|
optind = arg_start + 2;
|
while (1) {
|
int c = getopt_long(argc, argv, short_options, options, NULL);
|
if (c == -1) {
|
break;
|
}
|
switch (c) {
|
case 'd':
|
params.dtb_dir = optarg;
|
break;
|
default:
|
/* Unknown option, return error */
|
return 1;
|
}
|
}
|
|
return process_command_cfg_create(¶ms);
|
}
|