Home | History | Annotate | Download | only in ota
      1 /*
      2  * Copyright (C) 2008 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 <errno.h>
     19 #include <getopt.h>
     20 #include <limits.h>
     21 #include <stdio.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 
     25 /*
     26  * Append a tag to a property value in a .prop file if it isn't already there.
     27  * Normally used to modify build properties to record incremental updates.
     28  */
     29 
     30 // Return nonzero if the tag should be added to this line.
     31 int should_tag(const char *line, const char *propname) {
     32     const char *prop = strstr(line, propname);
     33     if (prop == NULL) return 0;
     34 
     35     // Make sure this is actually the property name (not an accidental hit)
     36     const char *ptr;
     37     for (ptr = line; ptr < prop && isspace(*ptr); ++ptr) ;
     38     if (ptr != prop) return 0;  // Must be at the beginning of the line
     39 
     40     for (ptr += strlen(propname); *ptr != '\0' && isspace(*ptr); ++ptr) ;
     41     return (*ptr == '=');  // Must be followed by a '='
     42 }
     43 
     44 // Remove existing tags from the line, return the following number (if any)
     45 int remove_tag(char *line, const char *tag) {
     46     char *pos = strstr(line, tag);
     47     if (pos == NULL) return 0;
     48 
     49     char *end;
     50     int num = strtoul(pos + strlen(tag), &end, 10);
     51     strcpy(pos, end);
     52     return num;
     53 }
     54 
     55 // Write line to output with the tag added, adding a number (if >0)
     56 void write_tagged(FILE *out, const char *line, const char *tag, int number) {
     57     const char *end = line + strlen(line);
     58     while (end > line && isspace(end[-1])) --end;
     59     if (number > 0) {
     60         fprintf(out, "%.*s%s%d%s", end - line, line, tag, number, end);
     61     } else {
     62         fprintf(out, "%.*s%s%s", end - line, line, tag, end);
     63     }
     64 }
     65 
     66 int main(int argc, char **argv) {
     67     const char *filename = "/system/build.prop";
     68     const char *propname = "ro.build.fingerprint";
     69     const char *tag = NULL;
     70     int do_remove = 0, do_number = 0;
     71 
     72     int opt;
     73     while ((opt = getopt(argc, argv, "f:p:rn")) != -1) {
     74         switch (opt) {
     75         case 'f': filename = optarg; break;
     76         case 'p': propname = optarg; break;
     77         case 'r': do_remove = 1; break;
     78         case 'n': do_number = 1; break;
     79         case '?': return 2;
     80         }
     81     }
     82 
     83     if (argc != optind + 1) {
     84         fprintf(stderr,
     85             "usage: add-property-tag [flags] tag-to-add\n"
     86             "flags: -f /dir/file.prop (default /system/build.prop)\n"
     87             "       -p prop.name (default ro.build.fingerprint)\n"
     88             "       -r (if set, remove the tag rather than adding it)\n"
     89             "       -n (if set, add and increment a number after the tag)\n");
     90         return 2;
     91     }
     92 
     93     tag = argv[optind];
     94     FILE *input = fopen(filename, "r");
     95     if (input == NULL) {
     96         fprintf(stderr, "can't read %s: %s\n", filename, strerror(errno));
     97         return 1;
     98     }
     99 
    100     char tmpname[PATH_MAX];
    101     snprintf(tmpname, sizeof(tmpname), "%s.tmp", filename);
    102     FILE *output = fopen(tmpname, "w");
    103     if (output == NULL) {
    104         fprintf(stderr, "can't write %s: %s\n", tmpname, strerror(errno));
    105         return 1;
    106     }
    107 
    108     int found = 0;
    109     char line[4096];
    110     while (fgets(line, sizeof(line), input)) {
    111         if (!should_tag(line, propname)) {
    112             fputs(line, output);  // Pass through unmodified
    113         } else {
    114             found = 1;
    115             int number = remove_tag(line, tag);
    116             if (do_remove) {
    117                 fputs(line, output);  // Remove the tag but don't re-add it
    118             } else {
    119                 write_tagged(output, line, tag, number + do_number);
    120             }
    121         }
    122     }
    123 
    124     fclose(input);
    125     fclose(output);
    126 
    127     if (!found) {
    128         fprintf(stderr, "property %s not found in %s\n", propname, filename);
    129         remove(tmpname);
    130         return 1;
    131     }
    132 
    133     if (rename(tmpname, filename)) {
    134         fprintf(stderr, "can't rename %s to %s: %s\n",
    135             tmpname, filename, strerror(errno));
    136         remove(tmpname);
    137         return 1;
    138     }
    139 
    140     return 0;
    141 }
    142