Home | History | Annotate | Download | only in src
      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(&params, 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(&params);
    191 }
    192