xref: /haiku/src/bin/addattr/main.cpp (revision bea66afaeb8d038d8918106a430a56b6e9fb3109)
1 /*
2  * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de.
3  * Copyright 2002, Sebastian Nozzi.
4  *
5  * Distributed under the terms of the MIT license.
6  */
7 
8 
9 #include "addAttr.h"
10 
11 #include <File.h>
12 #include <Mime.h>
13 #include <TypeConstants.h>
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 
19 
20 // supported types (if you add any, make sure that writeAttr() handles
21 // them properly)
22 
23 const struct {
24 	type_code	type;
25 	const char	*name;
26 } kSupportedTypes[] = {
27 	{B_STRING_TYPE, "string"},
28 	{B_MIME_STRING_TYPE, "mime"},
29 
30 	{B_INT32_TYPE, "int32"},
31 	{B_INT32_TYPE, "int"},
32 	{B_UINT32_TYPE, "uint32"},
33 	{B_UINT32_TYPE, "uint"},
34 
35 	{B_INT64_TYPE, "int64"},
36 	{B_INT64_TYPE, "llong"},
37 	{B_UINT64_TYPE, "uint64"},
38 	{B_UINT64_TYPE, "ullong"},
39 
40 	{B_FLOAT_TYPE, "float"},
41 	{B_DOUBLE_TYPE, "double"},
42 
43 	{B_BOOL_TYPE, "bool"},
44 
45 	{B_RAW_TYPE, "raw"},
46 };
47 const uint32 kNumSupportedTypes = sizeof(kSupportedTypes)
48 	/ sizeof(kSupportedTypes[0]);
49 
50 char *gProgramName;
51 
52 
53 /*!	For the given string that the user specifies as attribute type
54 	in the command line, this function tries to figure out the
55 	corresponding Be API value.
56 
57 	On success, "result" will contain that value
58 	On failure, B_BAD_VALUE is returned and "result" is not modified
59 */
60 static status_t
61 typeForString(const char *string, type_code *_result)
62 {
63 	for (uint32 i = 0; i < kNumSupportedTypes; i++) {
64 		if (!strcmp(string, kSupportedTypes[i].name)) {
65 			*_result = kSupportedTypes[i].type;
66 			return B_OK;
67 		}
68 	}
69 
70 	// type didn't show up - in this case, we parse the string
71 	// as number and use it directly as type code
72 
73 	if (sscanf(string, "%" B_SCNu32, _result) == 1)
74 		return B_OK;
75 
76 	uchar type[4];
77 	if (sscanf(string, "'%c%c%c%c'", &type[0], &type[1], &type[2], &type[3]) == 4) {
78 		*_result = (type[0] << 24) | (type[1] << 16) | (type[2] << 8) | type[3];
79 		return B_OK;
80 	}
81 
82 	return B_BAD_VALUE;
83 }
84 
85 
86 void
87 usage(int returnValue)
88 {
89 	fprintf(stderr, "usage: %s [-t type] [ -P ] attr value file1 [file2...]\n"
90 		"   or: %s [-f value-from-file] [-t type] [ -P ] attr file1 [file2...]\n\n"
91 		"\t-P : Don't resolve links\n"
92 		"\tType is one of:\n"
93 		"\t\tstring, mime, int, llong, float, double, bool, raw\n"
94 		"\t\tor a numeric value (ie. 0x1234, 42, 'ABCD', ...)\n"
95 		"\tThe default is \"string\"\n", gProgramName, gProgramName);
96 
97 	exit(returnValue);
98 }
99 
100 
101 void
102 assertArgument(int i, int argc)
103 {
104 	if (i >= argc)
105 		usage(1);
106 }
107 
108 
109 void
110 invalidAttrType(const char *attrTypeName)
111 {
112 	fprintf(stderr, "%s: attribute type \"%s\" is not valid\n", gProgramName,
113 		attrTypeName);
114 	fprintf(stderr, "\tTry one of: string, mime, int, llong, float, double,\n");
115 	fprintf(stderr, "\t\tbool, raw, or a numeric value (ie. 0x1234, 42, 'ABCD'"
116 		", ...)\n");
117 
118 	exit(1);
119 }
120 
121 
122 void
123 invalidBoolValue(const char *value)
124 {
125 	fprintf(stderr, "%s: attribute value \"%s\" is not valid\n", gProgramName,
126 		value);
127 	fprintf(stderr, "\tBool accepts: 0, f, false, disabled, off,\n");
128 	fprintf(stderr, "\t\t1, t, true, enabled, on\n");
129 
130 	exit(1);
131 }
132 
133 
134 int
135 main(int argc, char *argv[])
136 {
137 	gProgramName = strrchr(argv[0], '/');
138 	if (gProgramName == NULL)
139 		gProgramName = argv[0];
140 	else
141 		gProgramName++;
142 
143 	assertArgument(1, argc);
144 	if (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))
145 		usage(0);
146 
147 	type_code attrType = B_STRING_TYPE;
148 
149 	char *attrValue = NULL;
150 	size_t valueFileLength = 0;
151 	int32 i = 1;
152 	bool resolveLinks = true;
153 
154 	if (!strcmp(argv[i], "-f")) {
155 		// retrieve attribute value from file
156 		BFile file;
157 		off_t size;
158 		assertArgument(i, argc);
159 		status_t status = file.SetTo(argv[i + 1], B_READ_ONLY);
160 		if (status < B_OK) {
161 			fprintf(stderr, "%s: can't read attribute value from file %s: %s\n",
162 				gProgramName, argv[i], strerror(status));
163 
164 			return 1;
165 		}
166 
167  		status = file.GetSize(&size);
168  		if (status == B_OK) {
169 			if (size == 0) {
170 				fprintf(stderr, "%s: attribute value is empty: 0 bytes\n",
171 					gProgramName);
172 
173 				return 1;
174 			}
175  			if (size > 4 * 1024 * 1024) {
176 				fprintf(stderr, "%s: attribute value is too large: %" B_PRIdOFF
177 					" bytes\n", gProgramName, size);
178 
179 				return 1;
180  			}
181  			attrValue = (char *)malloc(size);
182  			if (attrValue != NULL)
183  				status = file.Read(attrValue, size);
184  			else
185  				status = B_NO_MEMORY;
186  		}
187 
188 		if (status < B_OK) {
189 			fprintf(stderr, "%s: can't read attribute value: %s\n",
190 				gProgramName, strerror(status));
191 
192 			return 1;
193 		}
194 
195 		valueFileLength = (size_t)size;
196 		i += 2;
197 	}
198 
199 	assertArgument(i, argc);
200 	if (!strcmp(argv[i], "-t")) {
201 		// Get the attribute type
202 		assertArgument(i, argc);
203 		if (typeForString(argv[i + 1], &attrType) != B_OK)
204 			invalidAttrType(argv[i + 1]);
205 
206 		i += 2;
207 	}
208 
209 	assertArgument(i, argc);
210 	if (!strcmp(argv[i], "-P")) {
211 		resolveLinks = false;
212 		i++;
213 	}
214 
215 	assertArgument(i, argc);
216 	const char *attrName = argv[i++];
217 
218 	assertArgument(i, argc);
219 	if (!valueFileLength)
220 		attrValue = argv[i++];
221 
222 	// no files specified?
223 	assertArgument(i, argc);
224 
225 	// Now that we gathered all the information proceed
226 	// to add the attribute to the file(s)
227 
228 	int result = 0;
229 
230 	for (; i < argc; i++) {
231 		status_t status = addAttr(argv[i], attrType, attrName, attrValue,
232 			valueFileLength, resolveLinks);
233 
234 		// special case for bool types
235 		if (status == B_BAD_VALUE && attrType == B_BOOL_TYPE)
236 			invalidBoolValue(attrValue);
237 
238 		if (status != B_OK) {
239 			fprintf(stderr, "%s: can't add attribute to file %s: %s\n",
240 				gProgramName, argv[i], strerror(status));
241 
242 			// proceed files, but return an error at the end
243 			result = 1;
244 		}
245 	}
246 
247 	if (valueFileLength)
248 		free(attrValue);
249 
250 	return result;
251 }
252 
253