xref: /haiku/src/bin/package/command_list.cpp (revision 70d5966963513ff47a456ba70b7d2eec0f99648d)
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.attributeIndex) {
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_ARCHITECTURE:
137 				printf("\tarchitecure: %s\n",
138 					BPackageInfo::kArchitectureNames[value.unsignedInt]);
139 				break;
140 
141 			case B_PACKAGE_INFO_VERSION:
142 				printf("\tversion: %s.%s.%s-%d\n", value.version.major,
143 					value.version.minor, value.version.micro,
144 					value.version.release);
145 				break;
146 
147 			case B_PACKAGE_INFO_COPYRIGHTS:
148 				printf("\tcopyright: %s\n", value.string);
149 				break;
150 
151 			case B_PACKAGE_INFO_LICENSES:
152 				printf("\tlicense: %s\n", value.string);
153 				break;
154 
155 			case B_PACKAGE_INFO_PROVIDES:
156 				printf("\tprovides: %s", value.resolvable.name);
157 				if (value.resolvable.haveVersion) {
158 					printf(" = ");
159 					_PrintPackageVersion(value.resolvable.version);
160 				}
161 				printf("\n");
162 				break;
163 
164 			case B_PACKAGE_INFO_REQUIRES:
165 				printf("\trequires: %s", value.resolvableExpression.name);
166 				if (value.resolvableExpression.haveOpAndVersion) {
167 					printf(" %s ", BPackageResolvableExpression::kOperatorNames[
168 							value.resolvableExpression.op]);
169 					_PrintPackageVersion(value.resolvableExpression.version);
170 				}
171 				printf("\n");
172 				break;
173 
174 			case B_PACKAGE_INFO_SUPPLEMENTS:
175 				printf("\tsupplements: %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_CONFLICTS:
185 				printf("\tconflicts: %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_FRESHENS:
195 				printf("\tfreshens: %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_REPLACES:
205 				printf("\treplaces: %s\n", value.string);
206 				break;
207 
208 			default:
209 				printf(
210 					"*** Invalid package attribute section: unexpected "
211 					"package attribute index %d encountered\n",
212 					value.attributeIndex);
213 				return B_BAD_DATA;
214 		}
215 
216 		return B_OK;
217 	}
218 
219 	virtual void HandleErrorOccurred()
220 	{
221 	}
222 
223 private:
224 	static const char* _PermissionString(char* buffer, uint32 mode, bool sticky)
225 	{
226 		buffer[0] = (mode & 0x4) != 0 ? 'r' : '-';
227 		buffer[1] = (mode & 0x2) != 0 ? 'w' : '-';
228 
229 		if ((mode & 0x1) != 0)
230 			buffer[2] = sticky ? 's' : 'x';
231 		else
232 			buffer[2] = '-';
233 
234 		buffer[3] = '\0';
235 		return buffer;
236 	}
237 
238 	static void _PrintPackageVersion(const BPackageVersionData& version)
239 	{
240 		printf("%s", version.major);
241 		if (version.minor != NULL && version.minor[0] != '\0')
242 			printf(".%s", version.minor);
243 		if (version.micro != NULL && version.micro[0] != '\0')
244 			printf(".%s", version.micro);
245 		if (version.release > 0)
246 			printf("-%d", version.release);
247 	}
248 
249 private:
250 	int		fLevel;
251 	bool	fListAttribute;
252 };
253 
254 
255 int
256 command_list(int argc, const char* const* argv)
257 {
258 	bool listAttributes = false;
259 
260 	while (true) {
261 		static struct option sLongOptions[] = {
262 			{ "help", no_argument, 0, 'h' },
263 			{ 0, 0, 0, 0 }
264 		};
265 
266 		opterr = 0; // don't print errors
267 		int c = getopt_long(argc, (char**)argv, "+ha", sLongOptions, NULL);
268 		if (c == -1)
269 			break;
270 
271 		switch (c) {
272 			case 'a':
273 				listAttributes = true;
274 				break;
275 
276 			case 'h':
277 				print_usage_and_exit(false);
278 				break;
279 
280 			default:
281 				print_usage_and_exit(true);
282 				break;
283 		}
284 	}
285 
286 	// One argument should remain -- the package file name.
287 	if (optind + 1 != argc)
288 		print_usage_and_exit(true);
289 
290 	const char* packageFileName = argv[optind++];
291 
292 	// open package
293 	StandardErrorOutput errorOutput;
294 	BPackageReader packageReader(&errorOutput);
295 	status_t error = packageReader.Init(packageFileName);
296 printf("Init(): %s\n", strerror(error));
297 	if (error != B_OK)
298 		return 1;
299 
300 	// list
301 	PackageContentListHandler handler(listAttributes);
302 	error = packageReader.ParseContent(&handler);
303 printf("ParseContent(): %s\n", strerror(error));
304 	if (error != B_OK)
305 		return 1;
306 
307 	return 0;
308 }
309