• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
should_tag(const char * line,const char * propname)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)
remove_tag(char * line,const char * tag)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)
write_tagged(FILE * out,const char * line,const char * tag,int number)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 
main(int argc,char ** argv)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