1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <ctype.h> 18 #include <getopt.h> 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include <unistd.h> 23 24 #include "dt_table.h" 25 #include "mkdtimg_core.h" 26 27 28 struct cfg_create_params { 29 const char *img_filename; 30 const char *cfg_filename; 31 const char *dtb_dir; 32 }; 33 34 static const char short_options[] = "d:"; 35 static struct option options[] = { 36 { "dtb-dir", required_argument, NULL, 'd' }, 37 { 0, 0, NULL, 0 } 38 }; 39 40 41 static char *trim_line(char *line) { 42 /* Find the end of the string or the first of '#' */ 43 char *end = line; 44 while (*end != '\0' && *end != '#') { 45 end++; 46 } 47 do { 48 end--; 49 } while (end >= line && isspace(*end)); 50 51 *(end + 1) = '\0'; 52 53 while (isspace(*line)) { 54 line++; 55 } 56 return line; 57 } 58 59 static int parse_config_entry_count(FILE *cfg_fp) { 60 int count = 0; 61 62 /* Any line without prefix spaces is entry filename */ 63 char line[1024]; 64 while (fgets(line, sizeof(line), cfg_fp) != NULL) { 65 char c = line[0]; 66 if (c == '\0' || isspace(c) || c == '#') continue; 67 count++; 68 } 69 70 return count; 71 } 72 73 static int output_img_with_config(FILE *img_fp, FILE *cfg_fp) { 74 int entry_count = parse_config_entry_count(cfg_fp); 75 struct dt_image_writer *writer = dt_image_writer_start(img_fp, entry_count); 76 77 fseek(cfg_fp, 0, SEEK_SET); /* Reset the file pos to head */ 78 79 int is_entry = 0; 80 char line[1024]; 81 while (fgets(line, sizeof(line), cfg_fp) != NULL) { 82 char *trimmed = trim_line(line); 83 if (trimmed[0] == '\0') { 84 /* empty line, pass */ 85 continue; 86 } 87 88 if (trimmed == line) { 89 /* This line is a file name, 90 because it start from the first char of the line */ 91 if (dt_image_writer_add_entry(writer, trimmed) != 0) { 92 return -1; 93 } 94 is_entry = 1; 95 continue; 96 } 97 98 char *option, *value; 99 if (parse_option(&option, &value, trimmed) != 0) { 100 fprintf(stderr, "Wrong syntax: %s\n", trimmed); 101 return -1; 102 } 103 104 int ret = is_entry ? 105 set_entry_options(writer, option, value) : 106 set_global_options(writer, option, value); 107 if (ret != 0) { 108 fprintf(stderr, "Unknown option: %s\n", option); 109 return -1; 110 } 111 } 112 113 if (dt_image_writer_end(writer) != 0) { 114 return -1; 115 } 116 117 return 0; 118 } 119 120 static int process_command_cfg_create(const struct cfg_create_params *params) { 121 int ret = -1; 122 FILE *cfg_fp = NULL; 123 FILE *img_fp = NULL; 124 125 cfg_fp = fopen(params->cfg_filename, "r"); 126 if (cfg_fp == NULL) { 127 fprintf(stderr, "Can not open config file: %s\n", params->cfg_filename); 128 goto end; 129 } 130 131 printf("create image file: %s...\n", params->img_filename); 132 133 img_fp = fopen(params->img_filename, "wb"); 134 if (img_fp == NULL) { 135 fprintf(stderr, "Can not create file: %s\n", params->img_filename); 136 goto end; 137 } 138 139 if (params->dtb_dir != NULL) { 140 if (chdir(params->dtb_dir) != 0) { 141 fprintf(stderr, "Can not switch to directory: %s\n", params->dtb_dir); 142 goto end; 143 } 144 } 145 146 ret = output_img_with_config(img_fp, cfg_fp); 147 148 end: 149 if (img_fp) fclose(img_fp); 150 if (cfg_fp) fclose(cfg_fp); 151 152 return ret; 153 } 154 155 void handle_usage_cfg_create(FILE *out_fp, const char *prog_name) { 156 fprintf(out_fp, " %s cfg_create <image_file> <config_file> (<option>...)\n\n", prog_name); 157 fprintf(out_fp, 158 " options:\n" 159 " -d, --dtb-dir The path to load dtb files.\n" 160 " Default is load from the current path.\n"); 161 } 162 163 int handle_command_cfg_create(int argc, char *argv[], int arg_start) { 164 if (argc - arg_start < 2) { 165 handle_usage_cfg_create(stderr, argv[0]); 166 return 1; 167 } 168 169 struct cfg_create_params params; 170 memset(¶ms, 0, sizeof(params)); 171 params.img_filename = argv[arg_start]; 172 params.cfg_filename = argv[arg_start + 1]; 173 174 optind = arg_start + 2; 175 while (1) { 176 int c = getopt_long(argc, argv, short_options, options, NULL); 177 if (c == -1) { 178 break; 179 } 180 switch (c) { 181 case 'd': 182 params.dtb_dir = optarg; 183 break; 184 default: 185 /* Unknown option, return error */ 186 return 1; 187 } 188 } 189 190 return process_command_cfg_create(¶ms); 191 } 192