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