xref: /haiku/src/bin/package/command_list.cpp (revision 204dee708a999d5a71d0cb9497650ee7cef85d0a)
1 /*
2  * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <ctype.h>
8 #include <errno.h>
9 #include <getopt.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <time.h>
14 
15 #include <package/hpkg/PackageContentHandler.h>
16 #include <package/hpkg/PackageEntry.h>
17 #include <package/hpkg/PackageEntryAttribute.h>
18 #include <package/hpkg/PackageInfoAttributeValue.h>
19 #include <package/hpkg/PackageReader.h>
20 #include <package/hpkg/StandardErrorOutput.h>
21 
22 #include <package/PackageInfo.h>
23 
24 #include "package.h"
25 
26 
27 using namespace BPackageKit::BHPKG;
28 using namespace BPackageKit;
29 
30 
31 struct PackageContentListHandler : BPackageContentHandler {
32 	PackageContentListHandler(bool listAttributes)
33 		:
34 		fLevel(0),
35 		fListAttribute(listAttributes)
36 	{
37 	}
38 
39 	virtual status_t HandleEntry(BPackageEntry* entry)
40 	{
41 		fLevel++;
42 
43 		int indentation = (fLevel - 1) * 2;
44 		printf("%*s", indentation, "");
45 
46 		// name and size
47 		printf("%-*s", indentation < 32 ? 32 - indentation : 0, entry->Name());
48 		printf("  %8llu", (unsigned long long)entry->Data().UncompressedSize());
49 
50 		// time
51 		struct tm* time = localtime(&entry->ModifiedTime().tv_sec);
52 		printf("  %04d-%02d-%02d %02d:%02d:%02d",
53 			1900 + time->tm_year, time->tm_mon + 1, time->tm_mday,
54 			time->tm_hour, time->tm_min, time->tm_sec);
55 
56 		// file type
57 		mode_t mode = entry->Mode();
58 		if (S_ISREG(mode))
59 			printf("  -");
60 		else if (S_ISDIR(mode))
61 			printf("  d");
62 		else if (S_ISLNK(mode))
63 			printf("  l");
64 		else
65 			printf("  ?");
66 
67 		// permissions
68 		char buffer[4];
69 		printf("%s", _PermissionString(buffer, mode >> 6,
70 			(mode & S_ISUID) != 0));
71 		printf("%s", _PermissionString(buffer, mode >> 3,
72 			(mode & S_ISGID) != 0));
73 		printf("%s", _PermissionString(buffer, mode, false));
74 
75 		// print the symlink path
76 		if (S_ISLNK(mode))
77 			printf("  -> %s", entry->SymlinkPath());
78 
79 		printf("\n");
80 		return B_OK;
81 	}
82 
83 	virtual status_t HandleEntryAttribute(BPackageEntry* entry,
84 		BPackageEntryAttribute* attribute)
85 	{
86 		if (!fListAttribute)
87 			return B_OK;
88 
89 		int indentation = fLevel * 2;
90 		printf("%*s<", indentation, "");
91 		printf("%-*s  %8llu", indentation < 31 ? 31 - indentation : 0,
92 			attribute->Name(),
93 			(unsigned long long)attribute->Data().UncompressedSize());
94 
95 		uint32 type = attribute->Type();
96 		if (isprint(type & 0xff) && isprint((type >> 8) & 0xff)
97 			 && isprint((type >> 16) & 0xff) && isprint(type >> 24)) {
98 			printf("  '%c%c%c%c'", int(type >> 24), int((type >> 16) & 0xff),
99 				int((type >> 8) & 0xff), int(type & 0xff));
100 		} else
101 			printf("  %#" B_PRIx32, type);
102 
103 		printf(">\n");
104 		return B_OK;
105 	}
106 
107 	virtual status_t HandleEntryDone(BPackageEntry* entry)
108 	{
109 		fLevel--;
110 		return B_OK;
111 	}
112 
113 	virtual status_t HandlePackageAttribute(
114 		const BPackageInfoAttributeValue& value)
115 	{
116 		switch (value.attributeID) {
117 			case B_PACKAGE_INFO_NAME:
118 				printf("package-attributes:\n");
119 				printf("\tname: %s\n", value.string);
120 				break;
121 
122 			case B_PACKAGE_INFO_SUMMARY:
123 				printf("\tsummary: %s\n", value.string);
124 				break;
125 
126 			case B_PACKAGE_INFO_DESCRIPTION:
127 				printf("\tdescription: %s\n", value.string);
128 				break;
129 
130 			case B_PACKAGE_INFO_VENDOR:
131 				printf("\tvendor: %s\n", value.string);
132 				break;
133 
134 			case B_PACKAGE_INFO_PACKAGER:
135 				printf("\tpackager: %s\n", value.string);
136 				break;
137 
138 			case B_PACKAGE_INFO_FLAGS:
139 				if (value.unsignedInt == 0)
140 					break;
141 				printf("\tflags:\n");
142 				if ((value.unsignedInt & B_PACKAGE_FLAG_APPROVE_LICENSE) != 0)
143 					printf("\t\tapprove_license\n");
144 				if ((value.unsignedInt & B_PACKAGE_FLAG_SYSTEM_PACKAGE) != 0)
145 					printf("\t\tsystem_package\n");
146 				break;
147 
148 			case B_PACKAGE_INFO_ARCHITECTURE:
149 				printf("\tarchitecture: %s\n",
150 					BPackageInfo::kArchitectureNames[value.unsignedInt]);
151 				break;
152 
153 			case B_PACKAGE_INFO_VERSION:
154 				printf("\tversion: ");
155 				_PrintPackageVersion(value.version);
156 				printf("\n");
157 				break;
158 
159 			case B_PACKAGE_INFO_COPYRIGHTS:
160 				printf("\tcopyright: %s\n", value.string);
161 				break;
162 
163 			case B_PACKAGE_INFO_LICENSES:
164 				printf("\tlicense: %s\n", value.string);
165 				break;
166 
167 			case B_PACKAGE_INFO_URLS:
168 				printf("\tURL: %s\n", value.string);
169 				break;
170 
171 			case B_PACKAGE_INFO_SOURCE_URLS:
172 				printf("\tsource URL: %s\n", value.string);
173 				break;
174 
175 			case B_PACKAGE_INFO_PROVIDES:
176 				printf("\tprovides: %s", value.resolvable.name);
177 				if (value.resolvable.haveVersion) {
178 					printf(" = ");
179 					_PrintPackageVersion(value.resolvable.version);
180 				}
181 				if (value.resolvable.haveCompatibleVersion) {
182 					printf(" (compatible >= ");
183 					_PrintPackageVersion(value.resolvable.compatibleVersion);
184 					printf(")");
185 				}
186 				printf("\n");
187 				break;
188 
189 			case B_PACKAGE_INFO_REQUIRES:
190 				printf("\trequires: %s", value.resolvableExpression.name);
191 				if (value.resolvableExpression.haveOpAndVersion) {
192 					printf(" %s ", BPackageResolvableExpression::kOperatorNames[
193 							value.resolvableExpression.op]);
194 					_PrintPackageVersion(value.resolvableExpression.version);
195 				}
196 				printf("\n");
197 				break;
198 
199 			case B_PACKAGE_INFO_SUPPLEMENTS:
200 				printf("\tsupplements: %s", value.resolvableExpression.name);
201 				if (value.resolvableExpression.haveOpAndVersion) {
202 					printf(" %s ", BPackageResolvableExpression::kOperatorNames[
203 							value.resolvableExpression.op]);
204 					_PrintPackageVersion(value.resolvableExpression.version);
205 				}
206 				printf("\n");
207 				break;
208 
209 			case B_PACKAGE_INFO_CONFLICTS:
210 				printf("\tconflicts: %s", value.resolvableExpression.name);
211 				if (value.resolvableExpression.haveOpAndVersion) {
212 					printf(" %s ", BPackageResolvableExpression::kOperatorNames[
213 							value.resolvableExpression.op]);
214 					_PrintPackageVersion(value.resolvableExpression.version);
215 				}
216 				printf("\n");
217 				break;
218 
219 			case B_PACKAGE_INFO_FRESHENS:
220 				printf("\tfreshens: %s", value.resolvableExpression.name);
221 				if (value.resolvableExpression.haveOpAndVersion) {
222 					printf(" %s ", BPackageResolvableExpression::kOperatorNames[
223 							value.resolvableExpression.op]);
224 					_PrintPackageVersion(value.resolvableExpression.version);
225 				}
226 				printf("\n");
227 				break;
228 
229 			case B_PACKAGE_INFO_REPLACES:
230 				printf("\treplaces: %s\n", value.string);
231 				break;
232 
233 			case B_PACKAGE_INFO_INSTALL_PATH:
234 				printf("\tinstall path: %s\n", value.string);
235 				break;
236 
237 			default:
238 				printf(
239 					"*** Invalid package attribute section: unexpected "
240 					"package attribute id %d encountered\n", value.attributeID);
241 				return B_BAD_DATA;
242 		}
243 
244 		return B_OK;
245 	}
246 
247 	virtual void HandleErrorOccurred()
248 	{
249 	}
250 
251 private:
252 	static const char* _PermissionString(char* buffer, uint32 mode, bool sticky)
253 	{
254 		buffer[0] = (mode & 0x4) != 0 ? 'r' : '-';
255 		buffer[1] = (mode & 0x2) != 0 ? 'w' : '-';
256 
257 		if ((mode & 0x1) != 0)
258 			buffer[2] = sticky ? 's' : 'x';
259 		else
260 			buffer[2] = '-';
261 
262 		buffer[3] = '\0';
263 		return buffer;
264 	}
265 
266 	static void _PrintPackageVersion(const BPackageVersionData& version)
267 	{
268 		printf("%s", BPackageVersion(version).ToString().String());
269 	}
270 
271 private:
272 	int		fLevel;
273 	bool	fListAttribute;
274 };
275 
276 
277 struct PackageContentListPathsHandler : BPackageContentHandler {
278 	PackageContentListPathsHandler()
279 		:
280 		fPathComponents()
281 	{
282 	}
283 
284 	virtual status_t HandleEntry(BPackageEntry* entry)
285 	{
286 		fPathComponents.Add(entry->Name());
287 		printf("%s\n", fPathComponents.Join("/").String());
288 		return B_OK;
289 	}
290 
291 	virtual status_t HandleEntryAttribute(BPackageEntry* entry,
292 		BPackageEntryAttribute* attribute)
293 	{
294 		return B_OK;
295 	}
296 
297 	virtual status_t HandleEntryDone(BPackageEntry* entry)
298 	{
299 		fPathComponents.Remove(fPathComponents.CountStrings() - 1);
300 		return B_OK;
301 	}
302 
303 	virtual status_t HandlePackageAttribute(
304 		const BPackageInfoAttributeValue& value)
305 	{
306 		return B_OK;
307 	}
308 
309 	virtual void HandleErrorOccurred()
310 	{
311 	}
312 
313 private:
314 	BStringList	fPathComponents;
315 };
316 
317 
318 int
319 command_list(int argc, const char* const* argv)
320 {
321 	bool listAttributes = false;
322 	bool filePathsOnly = false;
323 
324 	while (true) {
325 		static struct option sLongOptions[] = {
326 			{ "help", no_argument, 0, 'h' },
327 			{ 0, 0, 0, 0 }
328 		};
329 
330 		opterr = 0; // don't print errors
331 		int c = getopt_long(argc, (char**)argv, "+hap", sLongOptions, NULL);
332 		if (c == -1)
333 			break;
334 
335 		switch (c) {
336 			case 'a':
337 				listAttributes = true;
338 				break;
339 
340 			case 'h':
341 				print_usage_and_exit(false);
342 				break;
343 
344 			case 'p':
345 				filePathsOnly = true;
346 				break;
347 
348 			default:
349 				print_usage_and_exit(true);
350 				break;
351 		}
352 	}
353 
354 	// One argument should remain -- the package file name.
355 	if (optind + 1 != argc)
356 		print_usage_and_exit(true);
357 
358 	const char* packageFileName = argv[optind++];
359 
360 	// open package
361 	BStandardErrorOutput errorOutput;
362 	BPackageReader packageReader(&errorOutput);
363 	status_t error = packageReader.Init(packageFileName);
364 	if (error != B_OK)
365 		return 1;
366 
367 	// list
368 	if (filePathsOnly) {
369 		PackageContentListPathsHandler handler;
370 		error = packageReader.ParseContent(&handler);
371 	} else {
372 		PackageContentListHandler handler(listAttributes);
373 		error = packageReader.ParseContent(&handler);
374 	}
375 	if (error != B_OK)
376 		return 1;
377 
378 	return 0;
379 }
380