1 /*
2 * Copyright 2009-2013, 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 <Entry.h>
16 #include <package/hpkg/PackageContentHandler.h>
17 #include <package/hpkg/PackageEntry.h>
18 #include <package/hpkg/PackageEntryAttribute.h>
19 #include <package/hpkg/PackageInfoAttributeValue.h>
20 #include <package/hpkg/PackageReader.h>
21 #include <package/hpkg/StandardErrorOutput.h>
22 #include <package/hpkg/v1/PackageContentHandler.h>
23 #include <package/hpkg/v1/PackageEntry.h>
24 #include <package/hpkg/v1/PackageEntryAttribute.h>
25 #include <package/hpkg/v1/PackageReader.h>
26
27 #include <package/PackageInfo.h>
28
29 #include "package.h"
30 #include "PackageInfoPrinter.h"
31
32
33 using namespace BPackageKit;
34 using BPackageKit::BHPKG::BErrorOutput;
35 using BPackageKit::BHPKG::BPackageInfoAttributeValue;
36 using BPackageKit::BHPKG::BStandardErrorOutput;
37
38
39 struct VersionPolicyV1 {
40 typedef BPackageKit::BHPKG::V1::BPackageContentHandler
41 PackageContentHandler;
42 typedef BPackageKit::BHPKG::V1::BPackageEntry PackageEntry;
43 typedef BPackageKit::BHPKG::V1::BPackageEntryAttribute
44 PackageEntryAttribute;
45 typedef BPackageKit::BHPKG::V1::BPackageReader PackageReader;
46
PackageDataSizeVersionPolicyV147 static inline uint64 PackageDataSize(
48 const BPackageKit::BHPKG::V1::BPackageData& data)
49 {
50 return data.UncompressedSize();
51 }
52
InitReaderVersionPolicyV153 static inline status_t InitReader(PackageReader& packageReader,
54 const char* fileName)
55 {
56 return packageReader.Init(fileName);
57 }
58 };
59
60 struct VersionPolicyV2 {
61 typedef BPackageKit::BHPKG::BPackageContentHandler PackageContentHandler;
62 typedef BPackageKit::BHPKG::BPackageEntry PackageEntry;
63 typedef BPackageKit::BHPKG::BPackageEntryAttribute PackageEntryAttribute;
64 typedef BPackageKit::BHPKG::BPackageReader PackageReader;
65
PackageDataSizeVersionPolicyV266 static inline uint64 PackageDataSize(
67 const BPackageKit::BHPKG::BPackageData& data)
68 {
69 return data.Size();
70 }
71
InitReaderVersionPolicyV272 static inline status_t InitReader(PackageReader& packageReader,
73 const char* fileName)
74 {
75 return packageReader.Init(fileName,
76 BPackageKit::BHPKG
77 ::B_HPKG_READER_DONT_PRINT_VERSION_MISMATCH_MESSAGE);
78 }
79 };
80
81
82 enum ListMode {
83 LIST_ALL,
84 LIST_PATHS_ONLY,
85 LIST_META_INFO_ONLY
86 };
87
88
89 template<typename VersionPolicy>
90 struct PackageContentListHandler : VersionPolicy::PackageContentHandler {
PackageContentListHandlerPackageContentListHandler91 PackageContentListHandler(bool listEntries, bool listAttributes)
92 :
93 fPrinter(),
94 fLevel(0),
95 fListEntries(listEntries),
96 fListAttribute(listEntries && listAttributes)
97 {
98 }
99
HandleEntryPackageContentListHandler100 virtual status_t HandleEntry(typename VersionPolicy::PackageEntry* entry)
101 {
102 if (!fListEntries)
103 return B_OK;
104
105 fLevel++;
106
107 int indentation = (fLevel - 1) * 2;
108 printf("%*s", indentation, "");
109
110 // name and size
111 printf("%-*s", indentation < 32 ? 32 - indentation : 0, entry->Name());
112 printf(" %8llu",
113 (unsigned long long)VersionPolicy::PackageDataSize(entry->Data()));
114
115 // time
116 struct tm* time = localtime(&entry->ModifiedTime().tv_sec);
117 printf(" %04d-%02d-%02d %02d:%02d:%02d",
118 1900 + time->tm_year, time->tm_mon + 1, time->tm_mday,
119 time->tm_hour, time->tm_min, time->tm_sec);
120
121 // file type
122 mode_t mode = entry->Mode();
123 if (S_ISREG(mode))
124 printf(" -");
125 else if (S_ISDIR(mode))
126 printf(" d");
127 else if (S_ISLNK(mode))
128 printf(" l");
129 else
130 printf(" ?");
131
132 // permissions
133 char buffer[4];
134 printf("%s", _PermissionString(buffer, mode >> 6,
135 (mode & S_ISUID) != 0));
136 printf("%s", _PermissionString(buffer, mode >> 3,
137 (mode & S_ISGID) != 0));
138 printf("%s", _PermissionString(buffer, mode, false));
139
140 // print the symlink path
141 if (S_ISLNK(mode))
142 printf(" -> %s", entry->SymlinkPath());
143
144 printf("\n");
145 return B_OK;
146 }
147
HandleEntryAttributePackageContentListHandler148 virtual status_t HandleEntryAttribute(
149 typename VersionPolicy::PackageEntry* entry,
150 typename VersionPolicy::PackageEntryAttribute* attribute)
151 {
152 if (!fListAttribute)
153 return B_OK;
154
155 int indentation = fLevel * 2;
156 printf("%*s<", indentation, "");
157 printf("%-*s %8llu", indentation < 31 ? 31 - indentation : 0,
158 attribute->Name(),
159 (unsigned long long)VersionPolicy::PackageDataSize(
160 attribute->Data()));
161
162 uint32 type = attribute->Type();
163 if (isprint(type & 0xff) && isprint((type >> 8) & 0xff)
164 && isprint((type >> 16) & 0xff) && isprint(type >> 24)) {
165 printf(" '%c%c%c%c'", int(type >> 24), int((type >> 16) & 0xff),
166 int((type >> 8) & 0xff), int(type & 0xff));
167 } else
168 printf(" %#" B_PRIx32, type);
169
170 printf(">\n");
171 return B_OK;
172 }
173
HandleEntryDonePackageContentListHandler174 virtual status_t HandleEntryDone(
175 typename VersionPolicy::PackageEntry* entry)
176 {
177 if (!fListEntries)
178 return B_OK;
179
180 fLevel--;
181 return B_OK;
182 }
183
HandlePackageAttributePackageContentListHandler184 virtual status_t HandlePackageAttribute(
185 const BPackageInfoAttributeValue& value)
186 {
187 if (value.attributeID == B_PACKAGE_INFO_NAME)
188 printf("package-attributes:\n");
189
190 if (!fPrinter.PrintAttribute(value)) {
191 printf("*** Invalid package attribute section: unexpected "
192 "package attribute id %d encountered\n", value.attributeID);
193 return B_BAD_DATA;
194 }
195
196 return B_OK;
197 }
198
HandleErrorOccurredPackageContentListHandler199 virtual void HandleErrorOccurred()
200 {
201 }
202
203 private:
_PermissionStringPackageContentListHandler204 static const char* _PermissionString(char* buffer, uint32 mode, bool sticky)
205 {
206 buffer[0] = (mode & 0x4) != 0 ? 'r' : '-';
207 buffer[1] = (mode & 0x2) != 0 ? 'w' : '-';
208
209 if ((mode & 0x1) != 0)
210 buffer[2] = sticky ? 's' : 'x';
211 else
212 buffer[2] = '-';
213
214 buffer[3] = '\0';
215 return buffer;
216 }
217
_PrintPackageVersionPackageContentListHandler218 static void _PrintPackageVersion(const BPackageVersionData& version)
219 {
220 printf("%s", BPackageVersion(version).ToString().String());
221 }
222
223 private:
224 PackageInfoPrinter fPrinter;
225 int fLevel;
226 bool fListEntries;
227 bool fListAttribute;
228 };
229
230
231 template<typename VersionPolicy>
232 struct PackageContentListPathsHandler : VersionPolicy::PackageContentHandler {
PackageContentListPathsHandlerPackageContentListPathsHandler233 PackageContentListPathsHandler()
234 :
235 fPathComponents()
236 {
237 }
238
HandleEntryPackageContentListPathsHandler239 virtual status_t HandleEntry(typename VersionPolicy::PackageEntry* entry)
240 {
241 fPathComponents.Add(entry->Name());
242 printf("%s\n", fPathComponents.Join("/").String());
243 return B_OK;
244 }
245
HandleEntryAttributePackageContentListPathsHandler246 virtual status_t HandleEntryAttribute(
247 typename VersionPolicy::PackageEntry* entry,
248 typename VersionPolicy::PackageEntryAttribute* attribute)
249 {
250 return B_OK;
251 }
252
HandleEntryDonePackageContentListPathsHandler253 virtual status_t HandleEntryDone(
254 typename VersionPolicy::PackageEntry* entry)
255 {
256 fPathComponents.Remove(fPathComponents.CountStrings() - 1);
257 return B_OK;
258 }
259
HandlePackageAttributePackageContentListPathsHandler260 virtual status_t HandlePackageAttribute(
261 const BPackageInfoAttributeValue& value)
262 {
263 return B_OK;
264 }
265
HandleErrorOccurredPackageContentListPathsHandler266 virtual void HandleErrorOccurred()
267 {
268 }
269
270 private:
271 BStringList fPathComponents;
272 };
273
274
275 template<typename VersionPolicy>
276 static void
do_list(const char * packageFileName,bool listAttributes,ListMode listMode,bool ignoreVersionError)277 do_list(const char* packageFileName, bool listAttributes, ListMode listMode,
278 bool ignoreVersionError)
279 {
280 // open package
281 BStandardErrorOutput errorOutput;
282 typename VersionPolicy::PackageReader packageReader(&errorOutput);
283 status_t error = VersionPolicy::InitReader(packageReader, packageFileName);
284 if (error != B_OK) {
285 if (ignoreVersionError && error == B_MISMATCHED_VALUES)
286 return;
287 exit(1);
288 }
289
290 // list
291 switch (listMode) {
292 case LIST_PATHS_ONLY:
293 {
294 PackageContentListPathsHandler<VersionPolicy> handler;
295 error = packageReader.ParseContent(&handler);
296 break;
297 }
298
299 case LIST_ALL:
300 case LIST_META_INFO_ONLY:
301 {
302 PackageContentListHandler<VersionPolicy> handler(
303 listMode != LIST_META_INFO_ONLY, listAttributes);
304 error = packageReader.ParseContent(&handler);
305 }
306 }
307
308 if (error != B_OK)
309 exit(1);
310
311 exit(0);
312 }
313
314
315 int
command_list(int argc,const char * const * argv)316 command_list(int argc, const char* const* argv)
317 {
318 ListMode listMode = LIST_ALL;
319 bool listAttributes = false;
320
321 while (true) {
322 static struct option sLongOptions[] = {
323 { "help", no_argument, 0, 'h' },
324 { 0, 0, 0, 0 }
325 };
326
327 opterr = 0; // don't print errors
328 int c = getopt_long(argc, (char**)argv, "+ahip", sLongOptions, NULL);
329 if (c == -1)
330 break;
331
332 switch (c) {
333 case 'a':
334 listAttributes = true;
335 break;
336
337 case 'i':
338 listMode = LIST_META_INFO_ONLY;
339 break;
340
341 case 'h':
342 print_usage_and_exit(false);
343 break;
344
345 case 'p':
346 listMode = LIST_PATHS_ONLY;
347 break;
348
349 default:
350 print_usage_and_exit(true);
351 break;
352 }
353 }
354
355 // One argument should remain -- the package file name.
356 if (optind + 1 != argc)
357 print_usage_and_exit(true);
358
359 const char* packageFileName = argv[optind++];
360
361 // If the file doesn't look like a package file, try to load it as a
362 // package info file.
363 if (!BString(packageFileName).EndsWith(".hpkg")) {
364 struct ErrorListener : BPackageInfo::ParseErrorListener {
365 virtual void OnError(const BString& msg, int line, int col)
366 {
367 fprintf(stderr, "%s:%d:%d: %s\n", fPath, line, col,
368 msg.String());
369 }
370
371 const char* fPath;
372 } errorListener;
373 errorListener.fPath = packageFileName;
374
375 BPackageInfo info;
376 if (info.ReadFromConfigFile(BEntry(packageFileName), &errorListener)
377 != B_OK) {
378 return 1;
379 }
380
381 printf("package-attributes:\n");
382 PackageInfoPrinter().PrintPackageInfo(info);
383 return 0;
384 }
385
386 BHPKG::BStandardErrorOutput errorOutput;
387
388 // current package file format version
389 do_list<VersionPolicyV2>(packageFileName, listAttributes, listMode, true);
390 do_list<VersionPolicyV1>(packageFileName, listAttributes, listMode, false);
391
392 return 0;
393 }
394