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