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