github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/make/tools/fs_config/fs_config_generate.c (about)

     1  /*
     2   * Copyright (C) 2015 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 <stdbool.h>
    19  #include <stdio.h>
    20  #include <stdlib.h>
    21  #include <string.h>
    22  #include <unistd.h>
    23  
    24  #include <private/android_filesystem_config.h>
    25  
    26  /*
    27   * This program expects android_device_dirs and android_device_files
    28   * to be defined in the supplied android_filesystem_config.h file in
    29   * the device/<vendor>/<product> $(TARGET_DEVICE_DIR). Then generates
    30   * the binary format used in the /system/etc/fs_config_dirs and
    31   * the /system/etc/fs_config_files to be used by the runtimes.
    32   */
    33  #ifdef ANDROID_FILESYSTEM_CONFIG
    34  #include ANDROID_FILESYSTEM_CONFIG
    35  #else
    36  #include "android_filesystem_config.h"
    37  #endif
    38  
    39  #ifdef NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS
    40  static const struct fs_path_config android_device_dirs[] = { };
    41  #endif
    42  
    43  #ifdef NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_FILES
    44  static const struct fs_path_config android_device_files[] = {
    45  #ifdef NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS
    46      {0000, AID_ROOT, AID_ROOT, 0, "system/etc/fs_config_dirs"},
    47      {0000, AID_ROOT, AID_ROOT, 0, "vendor/etc/fs_config_dirs"},
    48      {0000, AID_ROOT, AID_ROOT, 0, "oem/etc/fs_config_dirs"},
    49      {0000, AID_ROOT, AID_ROOT, 0, "odm/etc/fs_config_dirs"},
    50  #endif
    51      {0000, AID_ROOT, AID_ROOT, 0, "system/etc/fs_config_files"},
    52      {0000, AID_ROOT, AID_ROOT, 0, "vendor/etc/fs_config_files"},
    53      {0000, AID_ROOT, AID_ROOT, 0, "oem/etc/fs_config_files"},
    54      {0000, AID_ROOT, AID_ROOT, 0, "odm/etc/fs_config_files"},
    55  };
    56  #endif
    57  
    58  static void usage() {
    59    fprintf(stderr,
    60      "Generate binary content for fs_config_dirs (-D) and fs_config_files (-F)\n"
    61      "from device-specific android_filesystem_config.h override.  Filter based\n"
    62      "on a comma separated partition list (-P) whitelist or prefixed by a\n"
    63      "minus blacklist.  Partitions are identified as path references to\n"
    64      "<partition>/ or system/<partition>/\n\n"
    65      "Usage: fs_config_generate -D|-F [-P list] [-o output-file]\n");
    66  }
    67  
    68  /* If tool switches to C++, use android-base/macros.h array_size() */
    69  #ifndef ARRAY_SIZE /* popular macro */
    70  #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
    71  #endif
    72  
    73  int main(int argc, char** argv) {
    74    const struct fs_path_config* pc;
    75    const struct fs_path_config* end;
    76    bool dir = false, file = false;
    77    const char* partitions = NULL;
    78    FILE* fp = stdout;
    79    int opt;
    80    static const char optstring[] = "DFP:ho:";
    81  
    82    while ((opt = getopt(argc, argv, optstring)) != -1) {
    83      switch (opt) {
    84      case 'D':
    85        if (file) {
    86          fprintf(stderr, "Must specify only -D or -F\n");
    87          usage();
    88          exit(EXIT_FAILURE);
    89        }
    90        dir = true;
    91        break;
    92      case 'F':
    93        if (dir) {
    94          fprintf(stderr, "Must specify only -F or -D\n");
    95          usage();
    96          exit(EXIT_FAILURE);
    97        }
    98        file = true;
    99        break;
   100      case 'P':
   101        if (partitions) {
   102          fprintf(stderr, "Specify only one partition list\n");
   103          usage();
   104          exit(EXIT_FAILURE);
   105        }
   106        while (*optarg && isspace(*optarg)) ++optarg;
   107        if (!optarg[0]) {
   108          fprintf(stderr, "Partition list empty\n");
   109          usage();
   110          exit(EXIT_FAILURE);
   111        }
   112        if (!optarg[1]) {
   113          fprintf(stderr, "Partition list too short \"%s\"\n", optarg);
   114          usage();
   115          exit(EXIT_FAILURE);
   116        }
   117        if ((optarg[0] == '-') && strchr(optstring, optarg[1]) && !optarg[2]) {
   118          fprintf(stderr, "Partition list is a flag \"%s\"\n", optarg);
   119          usage();
   120          exit(EXIT_FAILURE);
   121        }
   122        partitions = optarg;
   123        break;
   124      case 'o':
   125        if (fp != stdout) {
   126          fprintf(stderr, "Specify only one output file\n");
   127          usage();
   128          exit(EXIT_FAILURE);
   129        }
   130        fp = fopen(optarg, "wb");
   131        if (fp == NULL) {
   132          fprintf(stderr, "Can not open \"%s\"\n", optarg);
   133          exit(EXIT_FAILURE);
   134        }
   135        break;
   136      case 'h':
   137        usage();
   138        exit(EXIT_SUCCESS);
   139      default:
   140        usage();
   141        exit(EXIT_FAILURE);
   142      }
   143    }
   144  
   145    if (optind < argc) {
   146      fprintf(stderr, "Unknown non-argument \"%s\"\n", argv[optind]);
   147      usage();
   148      exit(EXIT_FAILURE);
   149    }
   150  
   151    if (!file && !dir) {
   152      fprintf(stderr, "Must specify either -F or -D\n");
   153      usage();
   154      exit(EXIT_FAILURE);
   155    }
   156  
   157    if (dir) {
   158      pc = android_device_dirs;
   159      end = &android_device_dirs[ARRAY_SIZE(android_device_dirs)];
   160    } else {
   161      pc = android_device_files;
   162      end = &android_device_files[ARRAY_SIZE(android_device_files)];
   163    }
   164    for (; (pc < end) && pc->prefix; pc++) {
   165      bool submit;
   166      char buffer[512];
   167      ssize_t len = fs_config_generate(buffer, sizeof(buffer), pc);
   168      if (len < 0) {
   169        fprintf(stderr, "Entry too large\n");
   170        exit(EXIT_FAILURE);
   171      }
   172      submit = true;
   173      if (partitions) {
   174        char* partitions_copy = strdup(partitions);
   175        char* arg = partitions_copy;
   176        char* sv = NULL; /* Do not leave uninitialized, NULL is known safe. */
   177        /* Deal with case all iterated partitions are blacklists with no match */
   178        bool all_blacklist_but_no_match = true;
   179        submit = false;
   180  
   181        if (!partitions_copy) {
   182          fprintf(stderr, "Failed to allocate a copy of %s\n", partitions);
   183          exit(EXIT_FAILURE);
   184        }
   185        /* iterate through (officially) comma separated list of partitions */
   186        while (!!(arg = strtok_r(arg, ",:; \t\n\r\f", &sv))) {
   187          static const char system[] = "system/";
   188          size_t plen;
   189          bool blacklist = false;
   190          if (*arg == '-') {
   191            blacklist = true;
   192            ++arg;
   193          } else {
   194            all_blacklist_but_no_match = false;
   195          }
   196          plen = strlen(arg);
   197          /* deal with evil callers */
   198          while (arg[plen - 1] == '/') {
   199            --plen;
   200          }
   201          /* check if we have <partition>/ or /system/<partition>/ */
   202          if ((!strncmp(pc->prefix, arg, plen) && (pc->prefix[plen] == '/')) ||
   203              (!strncmp(pc->prefix, system, strlen(system)) &&
   204               !strncmp(pc->prefix + strlen(system), arg, plen) &&
   205               (pc->prefix[strlen(system) + plen] == '/'))) {
   206            all_blacklist_but_no_match = false;
   207            /* we have a match !!! */
   208            if (!blacklist) submit = true;
   209            break;
   210          }
   211          arg = NULL;
   212        }
   213        free(partitions_copy);
   214        if (all_blacklist_but_no_match) submit = true;
   215      }
   216      if (submit && (fwrite(buffer, 1, len, fp) != (size_t)len)) {
   217        fprintf(stderr, "Write failure\n");
   218        exit(EXIT_FAILURE);
   219      }
   220    }
   221    fclose(fp);
   222  
   223    return 0;
   224  }