14f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin/*
24f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin * Copyright (C) 2017 The Android Open Source Project
34f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin *
44f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin * Licensed under the Apache License, Version 2.0 (the "License");
54f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin * you may not use this file except in compliance with the License.
64f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin * You may obtain a copy of the License at
74f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin *
84f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin *      http://www.apache.org/licenses/LICENSE-2.0
94f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin *
104f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin * Unless required by applicable law or agreed to in writing, software
114f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin * distributed under the License is distributed on an "AS IS" BASIS,
124f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin * See the License for the specific language governing permissions and
144f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin * limitations under the License.
154f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin */
164f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin
17780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin#include <ctype.h>
18780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin#include <getopt.h>
19780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin#include <stdio.h>
20780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin#include <stdlib.h>
21780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin#include <string.h>
22780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin#include <unistd.h>
23780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
24780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin#include "dt_table.h"
25780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin#include "mkdtimg_core.h"
26780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
27780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
28780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstruct cfg_create_params {
29780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  const char *img_filename;
30780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  const char *cfg_filename;
31780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  const char *dtb_dir;
32780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin};
33780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
34780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstatic const char short_options[] = "d:";
35780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstatic struct option options[] = {
36780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  { "dtb-dir",   required_argument, NULL, 'd' },
37780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  { 0,           0,                 NULL, 0 }
38780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin};
39780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
40780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
41780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstatic char *trim_line(char *line) {
42780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  /* Find the end of the string or the first of '#' */
43780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  char *end = line;
44780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  while (*end != '\0' && *end != '#') {
45780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    end++;
46780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
47780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  do {
48780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    end--;
49780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  } while (end >= line && isspace(*end));
50780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
51780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  *(end + 1) = '\0';
52780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
53780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  while (isspace(*line)) {
54780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    line++;
55780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
56780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return line;
57780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
58780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
59780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstatic int parse_config_entry_count(FILE *cfg_fp) {
60780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  int count = 0;
61780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
62780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  /* Any line without prefix spaces is entry filename */
63780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  char line[1024];
64780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  while (fgets(line, sizeof(line), cfg_fp) != NULL) {
65780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    char c = line[0];
66780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    if (c == '\0' || isspace(c) || c == '#') continue;
67780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    count++;
68780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
69780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
70780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return count;
71780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
72780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
73780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstatic int output_img_with_config(FILE *img_fp, FILE *cfg_fp) {
74780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  int entry_count = parse_config_entry_count(cfg_fp);
75780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  struct dt_image_writer *writer = dt_image_writer_start(img_fp, entry_count);
76780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
77780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  fseek(cfg_fp, 0, SEEK_SET); /* Reset the file pos to head */
78780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
79780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  int is_entry = 0;
80780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  char line[1024];
81780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  while (fgets(line, sizeof(line), cfg_fp) != NULL) {
82780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    char *trimmed = trim_line(line);
83780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    if (trimmed[0] == '\0') {
84780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      /* empty line, pass */
85780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      continue;
86780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    }
87780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
88780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    if (trimmed == line) {
89780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      /* This line is a file name,
90780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin        because it start from the first char of the line */
91780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      if (dt_image_writer_add_entry(writer, trimmed) != 0) {
92780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin        return -1;
93780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      }
94780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      is_entry = 1;
95780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      continue;
96780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    }
97780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
98780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    char *option, *value;
99780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    if (parse_option(&option, &value, trimmed) != 0) {
100780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      fprintf(stderr, "Wrong syntax: %s\n", trimmed);
101780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      return -1;
102780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    }
103780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
104780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    int ret = is_entry ?
105780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      set_entry_options(writer, option, value) :
106780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      set_global_options(writer, option, value);
107780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    if (ret != 0) {
108780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      fprintf(stderr, "Unknown option: %s\n", option);
109780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      return -1;
110780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    }
111780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
112780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
113780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (dt_image_writer_end(writer) != 0) {
114780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    return -1;
115780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
116780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
117780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return 0;
118780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
119780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
120780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstatic int process_command_cfg_create(const struct cfg_create_params *params) {
121780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  int ret = -1;
122780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  FILE *cfg_fp = NULL;
123780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  FILE *img_fp = NULL;
124780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
125780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  cfg_fp = fopen(params->cfg_filename, "r");
126780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (cfg_fp == NULL) {
127780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    fprintf(stderr, "Can not open config file: %s\n", params->cfg_filename);
128780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    goto end;
129780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
130780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
131780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  printf("create image file: %s...\n", params->img_filename);
132780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
133780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  img_fp = fopen(params->img_filename, "wb");
134780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (img_fp == NULL) {
135780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    fprintf(stderr, "Can not create file: %s\n", params->img_filename);
136780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    goto end;
137780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
138780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
139780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (params->dtb_dir != NULL) {
140780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    if (chdir(params->dtb_dir) != 0) {
141780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      fprintf(stderr, "Can not switch to directory: %s\n", params->dtb_dir);
142780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      goto end;
143780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    }
144780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
145780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
146780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  ret = output_img_with_config(img_fp, cfg_fp);
147780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
148780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linend:
149780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (img_fp) fclose(img_fp);
150780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (cfg_fp) fclose(cfg_fp);
151780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
152780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return ret;
153780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
154780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
155780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linvoid handle_usage_cfg_create(FILE *out_fp, const char *prog_name) {
156780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  fprintf(out_fp, "  %s cfg_create <image_file> <config_file> (<option>...)\n\n", prog_name);
157780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  fprintf(out_fp,
158780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    "    options:\n"
159780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    "      -d, --dtb-dir            The path to load dtb files.\n"
160780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    "                               Default is load from the current path.\n");
161780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
162780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
163780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linint handle_command_cfg_create(int argc, char *argv[], int arg_start) {
164780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (argc - arg_start < 2) {
165780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    handle_usage_cfg_create(stderr, argv[0]);
166780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    return 1;
167780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
168780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
169780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  struct cfg_create_params params;
170780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  memset(&params, 0, sizeof(params));
171780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  params.img_filename = argv[arg_start];
172780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  params.cfg_filename = argv[arg_start + 1];
173780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
174780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  optind = arg_start + 2;
175780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  while (1) {
176780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    int c = getopt_long(argc, argv, short_options, options, NULL);
177780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    if (c == -1) {
178780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      break;
179780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    }
180780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    switch (c) {
181780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      case 'd':
182780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin        params.dtb_dir = optarg;
183780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin        break;
184780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      default:
185780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin        /* Unknown option, return error */
186780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin        return 1;
187780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    }
188780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
189780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
190780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return process_command_cfg_create(&params);
191780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
192