xref: /haiku/src/bin/package/command_list.cpp (revision 922e7ba1f3228e6f28db69b0ded8f86eb32dea17)
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 
21 #include <package/PackageInfo.h>
22 
23 #include "package.h"
24 #include "StandardErrorOutput.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", 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(), attribute->Data().UncompressedSize());
93 
94 		uint32 type = attribute->Type();
95 		if (isprint(type & 0xff) && isprint((type >> 8) & 0xff)
96 			 && isprint((type >> 16) & 0xff) && isprint(type >> 24)) {
97 			printf("  '%c%c%c%c'", int(type >> 24), int((type >> 16) & 0xff),
98 				int((type >> 8) & 0xff), int(type & 0xff));
99 		} else
100 			printf("  %#" B_PRIx32, type);
101 
102 		printf(">\n");
103 		return B_OK;
104 	}
105 
106 	virtual status_t HandleEntryDone(BPackageEntry* entry)
107 	{
108 		fLevel--;
109 		return B_OK;
110 	}
111 
112 	virtual status_t HandlePackageAttribute(
113 		const BPackageInfoAttributeValue& value)
114 	{
115 		switch (value.attributeID) {
116 			case B_PACKAGE_INFO_NAME:
117 				printf("package-attributes:\n");
118 				printf("\tname: %s\n", value.string);
119 				break;
120 
121 			case B_PACKAGE_INFO_SUMMARY:
122 				printf("\tsummary: %s\n", value.string);
123 				break;
124 
125 			case B_PACKAGE_INFO_DESCRIPTION:
126 				printf("\tdescription: %s\n", value.string);
127 				break;
128 
129 			case B_PACKAGE_INFO_VENDOR:
130 				printf("\tvendor: %s\n", value.string);
131 				break;
132 
133 			case B_PACKAGE_INFO_PACKAGER:
134 				printf("\tpackager: %s\n", value.string);
135 				break;
136 
137 			case B_PACKAGE_INFO_FLAGS:
138 				if (value.unsignedInt == 0)
139 					break;
140 				printf("\tflags:\n");
141 				if ((value.unsignedInt & B_PACKAGE_FLAG_APPROVE_LICENSE) != 0)
142 					printf("\t\tapprove_license\n");
143 				if ((value.unsignedInt & B_PACKAGE_FLAG_SYSTEM_PACKAGE) != 0)
144 					printf("\t\tsystem_package\n");
145 				break;
146 
147 			case B_PACKAGE_INFO_ARCHITECTURE:
148 				printf("\tarchitecture: %s\n",
149 					BPackageInfo::kArchitectureNames[value.unsignedInt]);
150 				break;
151 
152 			case B_PACKAGE_INFO_VERSION:
153 				_PrintPackageVersion(value.version);
154 				break;
155 
156 			case B_PACKAGE_INFO_COPYRIGHTS:
157 				printf("\tcopyright: %s\n", value.string);
158 				break;
159 
160 			case B_PACKAGE_INFO_LICENSES:
161 				printf("\tlicense: %s\n", value.string);
162 				break;
163 
164 			case B_PACKAGE_INFO_PROVIDES:
165 				printf("\tprovides: %s", value.resolvable.name);
166 				if (value.resolvable.haveVersion) {
167 					printf(" = ");
168 					_PrintPackageVersion(value.resolvable.version);
169 				}
170 				printf("\n");
171 				break;
172 
173 			case B_PACKAGE_INFO_REQUIRES:
174 				printf("\trequires: %s", value.resolvableExpression.name);
175 				if (value.resolvableExpression.haveOpAndVersion) {
176 					printf(" %s ", BPackageResolvableExpression::kOperatorNames[
177 							value.resolvableExpression.op]);
178 					_PrintPackageVersion(value.resolvableExpression.version);
179 				}
180 				printf("\n");
181 				break;
182 
183 			case B_PACKAGE_INFO_SUPPLEMENTS:
184 				printf("\tsupplements: %s", value.resolvableExpression.name);
185 				if (value.resolvableExpression.haveOpAndVersion) {
186 					printf(" %s ", BPackageResolvableExpression::kOperatorNames[
187 							value.resolvableExpression.op]);
188 					_PrintPackageVersion(value.resolvableExpression.version);
189 				}
190 				printf("\n");
191 				break;
192 
193 			case B_PACKAGE_INFO_CONFLICTS:
194 				printf("\tconflicts: %s", value.resolvableExpression.name);
195 				if (value.resolvableExpression.haveOpAndVersion) {
196 					printf(" %s ", BPackageResolvableExpression::kOperatorNames[
197 							value.resolvableExpression.op]);
198 					_PrintPackageVersion(value.resolvableExpression.version);
199 				}
200 				printf("\n");
201 				break;
202 
203 			case B_PACKAGE_INFO_FRESHENS:
204 				printf("\tfreshens: %s", value.resolvableExpression.name);
205 				if (value.resolvableExpression.haveOpAndVersion) {
206 					printf(" %s ", BPackageResolvableExpression::kOperatorNames[
207 							value.resolvableExpression.op]);
208 					_PrintPackageVersion(value.resolvableExpression.version);
209 				}
210 				printf("\n");
211 				break;
212 
213 			case B_PACKAGE_INFO_REPLACES:
214 				printf("\treplaces: %s\n", value.string);
215 				break;
216 
217 			default:
218 				printf(
219 					"*** Invalid package attribute section: unexpected "
220 					"package attribute id %d encountered\n", value.attributeID);
221 				return B_BAD_DATA;
222 		}
223 
224 		return B_OK;
225 	}
226 
227 	virtual void HandleErrorOccurred()
228 	{
229 	}
230 
231 private:
232 	static const char* _PermissionString(char* buffer, uint32 mode, bool sticky)
233 	{
234 		buffer[0] = (mode & 0x4) != 0 ? 'r' : '-';
235 		buffer[1] = (mode & 0x2) != 0 ? 'w' : '-';
236 
237 		if ((mode & 0x1) != 0)
238 			buffer[2] = sticky ? 's' : 'x';
239 		else
240 			buffer[2] = '-';
241 
242 		buffer[3] = '\0';
243 		return buffer;
244 	}
245 
246 	static void _PrintPackageVersion(const BPackageVersionData& version)
247 	{
248 		printf("%s", version.major);
249 		if (version.minor != NULL && version.minor[0] != '\0')
250 			printf(".%s", version.minor);
251 		if (version.micro != NULL && version.micro[0] != '\0')
252 			printf(".%s", version.micro);
253 		if (version.release > 0)
254 			printf("-%d", version.release);
255 	}
256 
257 private:
258 	int		fLevel;
259 	bool	fListAttribute;
260 };
261 
262 
263 int
264 command_list(int argc, const char* const* argv)
265 {
266 	bool listAttributes = false;
267 
268 	while (true) {
269 		static struct option sLongOptions[] = {
270 			{ "help", no_argument, 0, 'h' },
271 			{ 0, 0, 0, 0 }
272 		};
273 
274 		opterr = 0; // don't print errors
275 		int c = getopt_long(argc, (char**)argv, "+ha", sLongOptions, NULL);
276 		if (c == -1)
277 			break;
278 
279 		switch (c) {
280 			case 'a':
281 				listAttributes = true;
282 				break;
283 
284 			case 'h':
285 				print_usage_and_exit(false);
286 				break;
287 
288 			default:
289 				print_usage_and_exit(true);
290 				break;
291 		}
292 	}
293 
294 	// One argument should remain -- the package file name.
295 	if (optind + 1 != argc)
296 		print_usage_and_exit(true);
297 
298 	const char* packageFileName = argv[optind++];
299 
300 	// open package
301 	StandardErrorOutput errorOutput;
302 	BPackageReader packageReader(&errorOutput);
303 	status_t error = packageReader.Init(packageFileName);
304 	if (error != B_OK)
305 		return 1;
306 
307 	// list
308 	PackageContentListHandler handler(listAttributes);
309 	error = packageReader.ParseContent(&handler);
310 	if (error != B_OK)
311 		return 1;
312 
313 	return 0;
314 }
315