Compare commits

...

47 Commits
v0.2 ... master

Author SHA1 Message Date
David Oberhollenzer 2ba65d6cfa Bump version
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-07-17 18:13:29 +02:00
David Oberhollenzer 80f298de55 Always quote files when producing a listing
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-07-17 18:13:29 +02:00
David Oberhollenzer 4a7b1d3b3c cleanup: move package dependency management to libpkg.a
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-07-17 12:45:23 +02:00
David Oberhollenzer a632656a60 cleanup: remove compressor block processing functions
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-07-17 12:34:14 +02:00
David Oberhollenzer ec1020ffc6 Add support for filenames with spaces in them
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-07-17 11:17:57 +02:00
David Oberhollenzer 6d053ff213 Update README
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-06-15 18:29:38 +02:00
David Oberhollenzer f426e4ef91 Remove pkg2sqfs
Rewritten and moved to a seperate project.

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-06-09 02:18:27 +02:00
David Oberhollenzer e08c819606 Bump version number
This is a patch level release that mainly contains a fix for pkg2sqfs.
It also contains some cleanups and a binary compatibility breaking
change to the package file format.

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-05-03 17:09:58 +02:00
David Oberhollenzer ba034260d4 Minor cleanup
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-05-03 00:14:48 +02:00
David Oberhollenzer ab753a402f Shrink table of contents header
We aren't gonna need 2^32 uids/gids, this is a package manager, not a
file system. Also, mode only uses 16 of 32 bits. We can shrink the
entire header to 8 bytes.

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-28 21:37:26 +02:00
David Oberhollenzer f95f02f6be Add options for default repo dir & default install dir
This should make working with the pkg program in the toolchain build
system much cleaner.

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-28 21:37:26 +02:00
David Oberhollenzer 5df2d5f730 Remove squashfs pseudo file listing generator
We no longer need this, since we can now produce our own squashfs images
directly from package files.

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-28 16:04:54 +02:00
David Oberhollenzer ed6841ed17 fix: flush SquashFS meta block if *exactely* filled
Otherwise we can get really funky corner cases where an inode offset is
indicated as just 1 byte after the end of a block. The unsquashfs program
doesn't complain but the kernel implementation really doesn't like that.

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-23 13:54:17 +02:00
David Oberhollenzer 7a70868fcd cleanup: move generic squashfs code to library
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-23 12:36:12 +02:00
David Oberhollenzer 5f0ee09c83 Bump version number
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-18 22:00:22 +02:00
David Oberhollenzer 75e169d06a fixup: squashfs limits number of dirents to 256
The kernel implementation BAILS if a directory header is followed by
more than a hard-coded maximum of entries (currently 256).

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-18 22:00:22 +02:00
David Oberhollenzer 9402492c16 Add mention of pkg2sqfs to README
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-18 14:37:42 +02:00
David Oberhollenzer 377596f37e pkg2sqfs: remove debug print
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-18 14:37:42 +02:00
David Oberhollenzer 33997bdb9e pkg2sqfs: fix size computation of directories
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-18 14:37:42 +02:00
David Oberhollenzer 00db5541e9 file list sort: remove duplicate directory entries
Can happen when merging multiple packages. But make sure they actually
are duplicates.

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-18 14:08:43 +02:00
David Oberhollenzer 96d4d353d4 Remove unnecessary flush from unpacking loop
The uncompressor will know when end of file is reached. Flushing
prematurely won't help. Especially the way the loop was constructed,
using an external buffer that is a lot larger than the internal
buffer of the compressor will cause multiple erroneous flushes.

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-18 14:08:43 +02:00
David Oberhollenzer b30e912e97 pkg2sqfs: add command line option to set timestamp
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-18 14:08:43 +02:00
David Oberhollenzer 576491eae6 pkg2sqfs: add command line option to select compressor
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-18 14:08:41 +02:00
David Oberhollenzer ac8e457c96 pkg2sqfs: set lzma dictionary size to block size
It's the default the kernel implementation expects if no options
are set.

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-18 14:08:03 +02:00
David Oberhollenzer 214a5e917e Add a way to pass options to compressors
Currently only used by lzma compressor to set the dictionary size.

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-18 14:08:03 +02:00
David Oberhollenzer e123eaf433 pkg2sqfs: implement meta data compression
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-18 14:08:02 +02:00
David Oberhollenzer f80e4e8d29 pkg2sqfs: implement data & fragment compression
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-18 14:08:02 +02:00
David Oberhollenzer 26b3683f7a Add block processing function to compressors
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-18 14:08:02 +02:00
David Oberhollenzer 765c836c3d Remove dependency on libbsd
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-18 14:08:02 +02:00
David Oberhollenzer d94bd8ff17 pkg2sqfs: sort directory entries asciibetically
The squashfs kernel implementation relies on the following properties:
 - directory entries are ordered asciibetically by name
 - directory entries have consecutive inode numbers
 - inode numbers are assigned in that order

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-17 16:54:29 +02:00
David Oberhollenzer cd79a4fccf make file list sorting more robust
If entries are sorted by length and some have the same length, sort
them asciibetically.

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-17 16:30:01 +02:00
David Oberhollenzer eadeee25d9 pkg2sqfs: move some functions to more approrpiate places
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-17 16:30:01 +02:00
David Oberhollenzer 025ab1007b pkg2sqfs: Add command line options for default inode settings
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-17 16:29:59 +02:00
David Oberhollenzer db25ddc108 pkg2sqfs: always padd image file to device block size
The kernel implementation apparently requires that.

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-17 16:29:22 +02:00
David Oberhollenzer 858779e42c Add pkg2sqfs utility stub
The goal is to transform a package file to a squashfs image. The mksquashfs
utility is a PITA with all kinds of idiotic not-thought-through corner
cases (e.g. the way "pseudo file definitions" have been tacked on, the
inabillity to set UID/GID for / *AND* have files not owned by root, the
way xattrs are handled, .....).

It would be preferable to fix mksquashfs itself, but the source code itself
is a horrid, unmaintained garbage pile. Its easier to write a small utility
instead that can turn a pkg file into a squashfs image in a way that
propperly treats file permissions and ownership, and is deterministic
(i.e. reproducable).

The utility currently generates an uncompressed squashfs image that
unsquashfs can unpack, but the kernel refuses the mount. The exact
problem still needs to be determined.

Furthermore, compression has to be implemented and some cleanup shoul
be done.

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-17 01:33:57 +02:00
David Oberhollenzer c78dc2255f pkg reader: try to read *entire* requested chunk
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-09 16:02:31 +02:00
David Oberhollenzer aa6bbf2ef4 Move pkg-tool internal headers out of global include directory
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-05 12:36:47 +02:00
David Oberhollenzer 6cfd9a37bf Move all the package I/O code to libpkg library
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-05 12:33:50 +02:00
David Oberhollenzer 1205ca0f3b Move compressors to utility library
- Remove compressor registration interface. Doesn't work in a static
   library, since all the files containing no exported members are
   optimized away at link time.
 - Repack as seperate utility library.

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-04-05 12:22:47 +02:00
David Oberhollenzer 63bad9786a Release version 0.3
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-03-31 13:39:21 +02:00
David Oberhollenzer 4d48e374d8 Add option to buildstrategy to produce a dot graph
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-03-30 23:40:19 +01:00
David Oberhollenzer 52f7bdc5c8 minor cleanup
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-03-30 18:31:40 +01:00
David Oberhollenzer b7e81c081b cleanup: split package provider code out of buildstrategy.c
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-03-30 18:20:33 +01:00
David Oberhollenzer 46f340b20f cleanup: split source package code out of buildstrategy.c
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-03-30 17:57:34 +01:00
David Oberhollenzer 8a52ea6717 Allow multiple source packages to provide the same binary package
In build strategy, record a linked list of providers instead of just
one per binary package. Add an option to scan a preference list in
addition.

When looking up the provider and there is more than one, choose the
preferred one. Produce an error if none is given.

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-03-29 23:55:12 +01:00
David Oberhollenzer b2f1b5ef58 cleanup: buildstrategy
Split utility function to get a source package by name out from
handle provides.

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-03-29 21:57:48 +01:00
David Oberhollenzer 48d74777e7 Fix buildstrategy command argument handlin
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
2019-03-29 21:54:08 +01:00
41 changed files with 670 additions and 383 deletions

1
.gitignore vendored
View File

@ -18,3 +18,4 @@ config.h
*.a
*~
pkg
pkg2sqfs

View File

@ -11,7 +11,7 @@ Building this package produces a program called `pkg` that can:
* dump the contents and meta data of such an archive for inspection.
* install an archive and all its dependencies recursively, in topological
order, to a specified root directory.
* generate file listings from archives in formats suitable for `mksquashfs`
* generate file listings from archives in formats suitable for `gensquashfs`
and Linux `CONFIG_INITRAMFS_SOURCE`.
* work out a build order for source packages given information on what source
packages provide what binary packages and what binary packages they need in

View File

@ -1,5 +1,5 @@
AC_PREREQ([2.60])
AC_INIT([pkgtool], [0.2], [goliath@infraroot.at], pkgtool)
AC_INIT([pkgtool], [0.4.2], [goliath@infraroot.at], pkgtool)
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([foreign dist-xz subdir-objects])
AM_SILENT_RULES([yes])
@ -39,6 +39,21 @@ UL_WARN_ADD([-pedantic])
AC_SUBST([WARN_CFLAGS])
##### configuration options #####
AC_DEFINE([REPODIR], ["./"], [Default package repository directory])
AC_DEFINE([INSTALLROOT], ["./"], [Default package installation root])
AC_ARG_WITH([repo-dir],
[AS_HELP_STRING([--with-repo-dir],
[Set the default package repository directory])],
[AC_DEFINE_UNQUOTED([REPODIR], "$withval")])
AC_ARG_WITH([install-root],
[AS_HELP_STRING([--with-install-root],
[Set the default package installation directory])],
[AC_DEFINE_UNQUOTED([INSTALLROOT], "$withval")])
##### search for dependencies #####
have_zlib="no"

View File

@ -105,14 +105,10 @@ table of contents contains an entry with the following common structure:
0 1 2 3
+-------+-------+-------+-------+
0 | mode |
0 | mode | user id |
+-------+-------+-------+-------+
1 | user id |
1 | group id | path length |
+-------+-------+-------+-------+
2 | group id |
+-------+-------+-------+-------+
3 | path length |
+---------------+
The mode field contains standard UNIX permissions. The user ID and group ID
fields contain the numeric IDs of the user and group respectively that own
@ -142,8 +138,6 @@ On the bit level, the mode field is structured as follows:
| +------------------------- set UID bit
+----------------------------- file type
The upper 16 bit of the mode filed must be set to zero.
Currently, the following file types are supported:
* `S_IFCHR` with a value of 2. The entry defines a character device.

View File

@ -5,7 +5,7 @@
#include <stddef.h>
#include <sys/types.h>
#include "pkgformat.h"
#include "pkg/pkgformat.h"
typedef struct compressor_stream_t {
ssize_t (*write)(struct compressor_stream_t *stream, const uint8_t *in,
@ -24,21 +24,14 @@ typedef struct compressor_t {
const char *name;
PKG_COMPRESSION id;
compressor_stream_t *(*compression_stream)(struct compressor_t *cmp);
compressor_stream_t *(*compression_stream)(struct compressor_t *cmp,
void *options);
compressor_stream_t *(*uncompression_stream)(struct compressor_t *cmp);
} compressor_t;
void compressor_register(compressor_t *compressor);
compressor_t *compressor_by_name(const char *name);
compressor_t *compressor_by_id(PKG_COMPRESSION id);
#define REGISTER_COMPRESSOR(compressor) \
static void __attribute__((constructor)) register_##compressor(void) \
{ \
compressor_register((compressor_t *)&compressor); \
}
#endif /* COMPRESSOR_H */

View File

@ -31,7 +31,6 @@ typedef struct image_entry_t {
typedef enum {
TOC_FORMAT_PRETTY = 0,
TOC_FORMAT_SQFS = 1,
TOC_FORMAT_INITRD = 2,
TOC_FORMAT_PKG = 3,
} TOC_FORMAT;

View File

@ -36,10 +36,9 @@ typedef struct {
} record_t;
typedef struct {
uint32_t mode;
uint32_t uid;
uint32_t gid;
uint16_t mode;
uint16_t uid;
uint16_t gid;
uint16_t path_length;
/* uint8_t path[]; */
} toc_entry_t;

View File

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: ISC */
#ifndef DEPGRAPH_H
#define DEPGRAPH_H
#ifndef PKGLIST_H
#define PKGLIST_H
struct pkg_dep_node {
char *name;
@ -30,4 +30,4 @@ int collect_dependencies(int repofd, struct pkg_dep_list *list);
int sort_by_dependencies(struct pkg_dep_list *list);
#endif /* DEPGRAPH_H */
#endif /* PKGLIST_H */

View File

@ -4,8 +4,8 @@
#include <stdbool.h>
#include "comp/compressor.h"
#include "pkgformat.h"
#include "compressor.h"
typedef struct pkg_writer_t pkg_writer_t;

View File

@ -9,4 +9,30 @@ libfilelist_a_SOURCES = lib/filelist/dump_toc.c lib/filelist/image_entry.c
libfilelist_a_SOURCES += lib/filelist/image_entry_sort.c
libfilelist_a_SOURCES += include/filelist/image_entry.h
noinst_LIBRARIES += libutil.a libfilelist.a
libcomp_a_SOURCES = lib/comp/compressor.c lib/comp/none.c
libcomp_a_SOURCES += include/comp/compressor.h lib/comp/internal.h
libcomp_a_CFLAGS = $(AM_CFLAGS)
libcomp_a_CPPFLAGS = $(AM_CPPFLAGS)
if WITH_ZLIB
libcomp_a_SOURCES += lib/comp/zlib.c
libcomp_a_CFLAGS += $(ZLIB_CFLAGS)
libcomp_a_CPPFLAGS += -DWITH_ZLIB
endif
if WITH_LZMA
libcomp_a_SOURCES += lib/comp/lzma.c
libcomp_a_CFLAGS += $(XZ_CFLAGS)
libcomp_a_CPPFLAGS += -DWITH_LZMA
endif
libpkg_a_SOURCES = include/pkg/pkgformat.h include/pkg/pkgreader.h
libpkg_a_SOURCES += include/pkg/pkgio.h include/pkg/pkgwriter.h
libpkg_a_SOURCES += include/pkg/pkglist.h
libpkg_a_SOURCES += lib/pkg/pkgreader.c lib/pkg/pkgwriter.c
libpkg_a_SOURCES += lib/pkg/pkg_unpack.c lib/pkg/pkgio_rd_image_entry.c
libpkg_a_SOURCES += lib/pkg/collect.c lib/pkg/pkglist.c lib/pkg/tsort.c
noinst_LIBRARIES += libutil.a libfilelist.a libcomp.a libpkg.a

39
lib/comp/compressor.c Normal file
View File

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: ISC */
#include <string.h>
#include "internal.h"
static compressor_t *compressors[] = {
[PKG_COMPRESSION_NONE] = &comp_none,
#ifdef WITH_ZLIB
[PKG_COMPRESSION_ZLIB] = &comp_zlib,
#endif
#ifdef WITH_LZMA
[PKG_COMPRESSION_LZMA] = &comp_lzma,
#endif
};
compressor_t *compressor_by_name(const char *name)
{
size_t i;
for (i = 0; i < sizeof(compressors) / sizeof(compressors[0]); ++i) {
if (compressors[i] == NULL)
continue;
if (strcmp(compressors[i]->name, name) == 0)
return compressors[i];
}
return NULL;
}
compressor_t *compressor_by_id(PKG_COMPRESSION id)
{
if ((int)id < 0)
return NULL;
if ((size_t)id >= sizeof(compressors) / sizeof(compressors[0]))
return NULL;
return compressors[id];
}

11
lib/comp/internal.h Normal file
View File

@ -0,0 +1,11 @@
/* SPDX-License-Identifier: ISC */
#ifndef INTERNAL_H
#define INTERNAL_H
#include "comp/compressor.h"
extern compressor_t comp_lzma;
extern compressor_t comp_none;
extern compressor_t comp_zlib;
#endif /* INTERNAL_H */

View File

@ -5,7 +5,7 @@
#include <stdio.h>
#include <lzma.h>
#include "compressor.h"
#include "internal.h"
#define CHUNK_SIZE 16384
@ -17,6 +17,7 @@ typedef struct {
int used;
bool eof;
bool error;
size_t dict_size;
} lzma_stream_t;
static ssize_t lzma_write(compressor_stream_t *base,
@ -100,7 +101,7 @@ static void lzma_destroy(compressor_stream_t *base)
free(lzma);
}
static compressor_stream_t *create_stream(bool compress)
static compressor_stream_t *create_stream(bool compress, size_t dict_size)
{
lzma_stream_t *lzma = calloc(1, sizeof(*lzma));
compressor_stream_t *base;
@ -113,6 +114,7 @@ static compressor_stream_t *create_stream(bool compress)
}
lzma->action = LZMA_RUN;
lzma->dict_size = dict_size;
base = (compressor_stream_t *)lzma;
base->write = lzma_write;
@ -126,6 +128,9 @@ static compressor_stream_t *create_stream(bool compress)
if (lzma_lzma_preset(&opt_lzma2, LZMA_PRESET_DEFAULT))
goto fail;
if (dict_size)
opt_lzma2.dict_size = dict_size;
filters[0].id = LZMA_FILTER_LZMA2;
filters[0].options = &opt_lzma2;
@ -148,23 +153,21 @@ fail:
return NULL;
}
static compressor_stream_t *lzma_compress(compressor_t *cmp)
static compressor_stream_t *lzma_compress(compressor_t *cmp, void *options)
{
(void)cmp;
return create_stream(true);
return create_stream(true, options == NULL ? 0 : *((size_t *)options));
}
static compressor_stream_t *lzma_uncompress(compressor_t *cmp)
{
(void)cmp;
return create_stream(false);
return create_stream(false, 0);
}
static compressor_t lzma = {
compressor_t comp_lzma = {
.name = "lzma",
.id = PKG_COMPRESSION_LZMA,
.compression_stream = lzma_compress,
.uncompression_stream = lzma_uncompress,
};
REGISTER_COMPRESSOR(lzma)

View File

@ -4,7 +4,7 @@
#include <stdio.h>
#include <zlib.h>
#include "compressor.h"
#include "internal.h"
#define CHUNK_SIZE 16384
@ -62,11 +62,12 @@ static void dummy_destroy(compressor_stream_t *base)
free(base);
}
static compressor_stream_t *create_dummy_stream(compressor_t *cmp)
static compressor_stream_t *create_dummy_stream(compressor_t *cmp,
void *options)
{
dummy_stream_t *dummy = calloc(1, sizeof(*dummy));
compressor_stream_t *base;
(void)cmp;
(void)cmp; (void)options;
if (dummy == NULL) {
perror("creating dummy compressor stream");
@ -81,11 +82,14 @@ static compressor_stream_t *create_dummy_stream(compressor_t *cmp)
return base;
}
static compressor_t none = {
static compressor_stream_t *create_dummy_uncompressor(compressor_t *cmp)
{
return create_dummy_stream(cmp, NULL);
}
compressor_t comp_none = {
.name = "none",
.id = PKG_COMPRESSION_NONE,
.compression_stream = create_dummy_stream,
.uncompression_stream = create_dummy_stream,
.uncompression_stream = create_dummy_uncompressor,
};
REGISTER_COMPRESSOR(none)

View File

@ -5,7 +5,7 @@
#include <stdio.h>
#include <zlib.h>
#include "compressor.h"
#include "internal.h"
#define CHUNK_SIZE 16384
@ -147,9 +147,9 @@ static compressor_stream_t *create_stream(bool compress)
return base;
}
static compressor_stream_t *zlib_compress(compressor_t *cmp)
static compressor_stream_t *zlib_compress(compressor_t *cmp, void *options)
{
(void)cmp;
(void)cmp; (void)options;
return create_stream(true);
}
@ -159,11 +159,9 @@ static compressor_stream_t *zlib_uncompress(compressor_t *cmp)
return create_stream(false);
}
static compressor_t zlib = {
compressor_t comp_zlib = {
.name = "zlib",
.id = PKG_COMPRESSION_ZLIB,
.compression_stream = zlib_compress,
.uncompression_stream = zlib_uncompress,
};
REGISTER_COMPRESSOR(zlib)

View File

@ -55,40 +55,6 @@ fail_type:
return -1;
}
static int print_sqfs(image_entry_t *ent, const char *root)
{
mode_t mode = ent->mode & (~S_IFMT);
(void)root;
switch (ent->mode & S_IFMT) {
case S_IFCHR:
printf("%s c %o %u %u %u %u\n", ent->name, mode,
(unsigned int)ent->uid, (unsigned int)ent->gid,
major(ent->data.device.devno),
minor(ent->data.device.devno));
break;
case S_IFBLK:
printf("%s b %o %u %u %u %u\n", ent->name, mode,
(unsigned int)ent->uid, (unsigned int)ent->gid,
major(ent->data.device.devno),
minor(ent->data.device.devno));
break;
case S_IFLNK:
mode = 0777;
/* fall-through */
case S_IFDIR:
case S_IFREG:
printf("%s m %o %u %u\n", ent->name, mode,
(unsigned int)ent->uid, (unsigned int)ent->gid);
break;
default:
fputs("unknown file type in table of contents\n", stderr);
return -1;
}
return 0;
}
static int print_initrd(image_entry_t *ent, const char *root)
{
mode_t mode = ent->mode & (~S_IFMT);
@ -156,7 +122,7 @@ static int print_pkg(image_entry_t *ent, const char *root)
return -1;
}
printf(" %s 0%o %u %u ", ent->name, mode,
printf(" \"%s\" 0%o %u %u ", ent->name, mode,
(unsigned int)ent->uid, (unsigned int)ent->gid);
switch (ent->mode & S_IFMT) {
@ -186,7 +152,6 @@ static int print_pkg(image_entry_t *ent, const char *root)
static print_fun_t printers[] = {
[TOC_FORMAT_PRETTY] = print_pretty,
[TOC_FORMAT_SQFS] = print_sqfs,
[TOC_FORMAT_INITRD] = print_initrd,
[TOC_FORMAT_PKG] = print_pkg,
};

View File

@ -6,6 +6,8 @@
static int compare_ent(image_entry_t *a, image_entry_t *b)
{
int diff;
/* directories < .. < symlinks < devices < .. < files */
switch (a->mode & S_IFMT) {
case S_IFDIR:
@ -31,7 +33,8 @@ static int compare_ent(image_entry_t *a, image_entry_t *b)
return -1;
}
out_len:
return (int)strlen(a->name) - (int)strlen(b->name);
diff = (int)strlen(a->name) - (int)strlen(b->name);
return diff ? diff : strcmp(a->name, b->name);
out_fsize:
if (a->data.file.size > b->data.file.size)
return 1;
@ -65,6 +68,34 @@ static image_entry_t *insert_sorted(image_entry_t *list, image_entry_t *ent)
return list;
}
static void remove_duplicates(image_entry_t *list)
{
image_entry_t *it = list, *old;
int equal;
if (it == NULL)
return;
while (it->next != NULL) {
equal = 0;
if (S_ISDIR(it->mode) && S_ISDIR(it->next->mode)) {
equal = (strcmp(it->name, it->next->name) == 0);
equal = equal && (it->mode == it->next->mode);
equal = equal && (it->uid == it->next->uid);
equal = equal && (it->gid == it->next->gid);
}
if (equal) {
old = it->next;
it->next = old->next;
image_entry_free(old);
} else {
it = it->next;
}
}
}
image_entry_t *image_entry_sort(image_entry_t *list)
{
image_entry_t *sorted = NULL, *ent;
@ -76,5 +107,7 @@ image_entry_t *image_entry_sort(image_entry_t *list)
sorted = insert_sorted(sorted, ent);
}
remove_duplicates(sorted);
return sorted;
}

View File

@ -3,8 +3,8 @@
#include <string.h>
#include <stdio.h>
#include "pkgreader.h"
#include "depgraph.h"
#include "pkg/pkgreader.h"
#include "pkg/pkglist.h"
int collect_dependencies(int repofd, struct pkg_dep_list *list)
{

View File

@ -8,7 +8,7 @@
#include <errno.h>
#include <fcntl.h>
#include "pkgio.h"
#include "pkg/pkgio.h"
#include "util/util.h"
static int create_hierarchy(int dirfd, image_entry_t *list, int flags)

View File

@ -4,7 +4,7 @@
#include <stdlib.h>
#include <stdio.h>
#include "pkgio.h"
#include "pkg/pkgio.h"
#include "util/util.h"
static int read_extra(pkg_reader_t *pkg, image_entry_t *ent)

View File

@ -3,7 +3,7 @@
#include <stdlib.h>
#include <stdio.h>
#include "depgraph.h"
#include "pkg/pkglist.h"
struct pkg_dep_node *append_pkg(struct pkg_dep_list *list, const char *name)
{

View File

@ -8,9 +8,9 @@
#include <errno.h>
#include <ctype.h>
#include "comp/compressor.h"
#include "util/util.h"
#include "pkgreader.h"
#include "compressor.h"
#include "pkg/pkgreader.h"
struct pkg_reader_t {
int fd;
@ -235,26 +235,29 @@ record_t *pkg_reader_current_record_header(pkg_reader_t *rd)
ssize_t pkg_reader_read_payload(pkg_reader_t *rd, void *out, size_t size)
{
ssize_t ret;
ssize_t ret, total = 0;
if (rd->have_error)
return -1;
do {
if (rd->have_error)
return -1;
if (rd->have_eof || rd->offset_raw == rd->current.raw_size)
return 0;
if (rd->have_eof || rd->offset_raw == rd->current.raw_size)
break;
if (prefetch_compressed(rd))
return -1;
if (prefetch_compressed(rd))
return -1;
if (size >= (rd->current.raw_size - rd->offset_raw))
rd->stream->flush(rd->stream);
ret = rd->stream->read(rd->stream, out, size);
if (ret < 0)
return -1;
ret = rd->stream->read(rd->stream, out, size);
if (ret < 0)
return -1;
rd->offset_raw += ret;
out = (char *)out + ret;
size -= ret;
total += ret;
} while (size > 0);
rd->offset_raw += ret;
return ret;
return total;
}
int pkg_reader_rewind(pkg_reader_t *rd)

View File

@ -6,7 +6,7 @@
#include <stdio.h>
#include <errno.h>
#include "pkgwriter.h"
#include "pkg/pkgwriter.h"
#include "util/util.h"
struct pkg_writer_t {
@ -96,7 +96,7 @@ pkg_writer_t *pkg_writer_open(const char *path, bool force)
return NULL;
}
wr->stream = cmp->compression_stream(cmp);
wr->stream = cmp->compression_stream(cmp, NULL);
if (wr->stream == NULL) {
fputs("error creating compressor stream for package header\n",
stderr);
@ -153,7 +153,7 @@ int pkg_writer_start_record(pkg_writer_t *wr, uint32_t magic,
if (write_header(wr))
return -1;
wr->stream = cmp->compression_stream(cmp);
wr->stream = cmp->compression_stream(cmp, NULL);
if (wr->stream == NULL)
return -1;

View File

@ -2,7 +2,7 @@
#include <stdlib.h>
#include <stdio.h>
#include "depgraph.h"
#include "pkg/pkglist.h"
static void remove_dependency(struct pkg_dep_list *list,
struct pkg_dep_node *pkg)

View File

@ -1,13 +1,8 @@
pkg_SOURCES = include/pkgformat.h include/pkgreader.h include/pkgio.h
pkg_SOURCES += include/compressor.h include/command.h include/pkgwriter.h
pkg_SOURCES += include/depgraph.h
pkg_SOURCES += main/pkg.c main/compressor.c main/command.c main/pkgreader.c
pkg_SOURCES += main/pkgwriter.c main/pkgio_rd_image_entry.c main/pkg_unpack.c
pkg_SOURCES += main/depgraph/collect.c main/depgraph/pkglist.c
pkg_SOURCES += main/depgraph/tsort.c
pkg_SOURCES = main/command.h main/pkg.c main/command.c
pkg_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/main
pkg_CFLAGS = $(AM_CFLAGS)
pkg_LDADD = libutil.a libfilelist.a
pkg_LDADD = libpkg.a libutil.a libfilelist.a libcomp.a
##### commands #####
@ -27,6 +22,8 @@ pkg_SOURCES += main/cmd/install.c
# buildstrategy command
pkg_SOURCES += main/cmd/buildstrategy/buildstrategy.h
pkg_SOURCES += main/cmd/buildstrategy/buildstrategy.c
pkg_SOURCES += main/cmd/buildstrategy/srcpkg.c
pkg_SOURCES += main/cmd/buildstrategy/provider.c
# depgraph command
pkg_SOURCES += main/cmd/depgraph.c
@ -38,24 +35,12 @@ pkg_SOURCES += main/cmd/unpack.c
pkg_SOURCES += main/cmd/help.c
##### compressors #####
# dummy compressor
pkg_SOURCES += main/compressors/none.c
# zlib compressor
if WITH_ZLIB
pkg_SOURCES += main/compressors/zlib.c
pkg_CFLAGS += $(ZLIB_CFLAGS)
pkg_LDADD += $(ZLIB_LIBS)
endif
# lzma compressor
if WITH_LZMA
pkg_SOURCES += main/compressors/lzma.c
pkg_CFLAGS += $(XZ_CFLAGS)
pkg_LDADD += $(XZ_LIBS)
endif
if WITH_ZLIB
pkg_LDADD += $(ZLIB_LIBS)
endif
bin_PROGRAMS += pkg

View File

@ -37,27 +37,21 @@ static int foreach_line(const char *filename, line_handler_t cb)
/*****************************************************************************/
static hash_table_t tbl_provides;
static hash_table_t tbl_sourcepkgs;
static int handle_depends(const char *filename, size_t linenum,
const char *sourcepkg, const char *binpkg)
{
source_pkg_t *src, *dep;
size_t count;
void *new;
(void)filename; (void)linenum;
src = hash_table_lookup(&tbl_sourcepkgs, sourcepkg);
src = src_pkg_get(sourcepkg);
if (src == NULL)
return 0;
dep = hash_table_lookup(&tbl_provides, binpkg);
if (dep == NULL) {
fprintf(stderr,
"%s: %zu: nothing provides '%s' required by '%s'\n",
filename, linenum, binpkg, sourcepkg);
dep = provider_get(sourcepkg, binpkg);
if (dep == NULL)
return -1;
}
if ((src->num_depends % 10) == 0) {
count = src->num_depends + 10;
@ -78,105 +72,30 @@ static int handle_depends(const char *filename, size_t linenum,
static int handle_provides(const char *filename, size_t linenum,
const char *sourcepkg, const char *binpkg)
{
source_pkg_t *src = NULL;
(void)filename; (void)linenum;
src = hash_table_lookup(&tbl_provides, binpkg);
if (src != NULL) {
fprintf(stderr,
"%s: %zu: %s: package already provided by %s\n",
filename, linenum, binpkg, src->name);
return -1;
}
return provider_add(sourcepkg, binpkg);
}
src = hash_table_lookup(&tbl_sourcepkgs, sourcepkg);
static int handle_prefere(const char *filename, size_t linenum,
const char *binpkg, const char *sourcepkg)
{
(void)filename; (void)linenum;
if (src == NULL) {
src = calloc(1, sizeof(*src));
if (src == NULL)
goto fail_oom;
src->name = strdup(sourcepkg);
if (src->name == NULL)
goto fail_oom;
if (hash_table_set(&tbl_sourcepkgs, sourcepkg, src))
goto fail;
}
return hash_table_set(&tbl_provides, binpkg, src);
fail_oom:
fputs("out of memory\n", stderr);
fail:
if (src != NULL)
free(src->name);
free(src);
return -1;
return provider_add_prefered(binpkg, sourcepkg);
}
/*****************************************************************************/
static const struct option long_opts[] = {
{ "provides", no_argument, NULL, 'p' },
{ "depends", no_argument, NULL, 'd' },
{ "prefere", required_argument, NULL, 'P' },
{ "provides", required_argument, NULL, 'p' },
{ "depends", required_argument, NULL, 'd' },
{ "graph", no_argument, NULL, 'g' },
{ NULL, 0, NULL, 0 },
};
static const char *short_opts = "p:d:";
static int process_args(int argc, char **argv)
{
const char *provides = NULL, *depends = NULL;
int i;
for (;;) {
i = getopt_long(argc, argv, short_opts, long_opts, NULL);
if (i == -1)
break;
switch (i) {
case 'p':
provides = optarg;
break;
case 'd':
depends = optarg;
break;
default:
goto fail_arg;
}
}
if (optind >= argc) {
fputs("no packages specified\n", stderr);
goto fail_arg;
}
if (provides == NULL) {
fputs("no source package provides specified\n", stderr);
goto fail_arg;
}
if (hash_table_init(&tbl_provides, 1024))
return EXIT_FAILURE;
if (hash_table_init(&tbl_sourcepkgs, 1024))
goto fail_provides;
if (foreach_line(provides, handle_provides))
goto fail_srcpkg;
if (depends != NULL && foreach_line(depends, handle_depends) != 0)
goto fail_srcpkg;
return 0;
fail_srcpkg:
hash_table_cleanup(&tbl_sourcepkgs);
fail_provides:
hash_table_cleanup(&tbl_provides);
return -1;
fail_arg:
tell_read_help(argv[0]);
return -1;
}
static const char *short_opts = "p:d:P:g";
static void pkg_mark_deps(source_pkg_t *pkg)
{
@ -193,98 +112,89 @@ static void pkg_mark_deps(source_pkg_t *pkg)
}
}
static int remove_untagged(void *usr, const char *name, void *p)
{
int mask = *((int *)usr);
source_pkg_t *pkg = p;
(void)name;
if ((pkg->flags & mask) == 0) {
free(pkg->name);
free(pkg->depends);
free(pkg);
return 1;
}
return 0;
}
static int remove_unmarked_deps(void *usr, const char *name, void *p)
{
source_pkg_t *pkg = p;
size_t i = 0;
(void)usr; (void)name;
while (i < pkg->num_depends) {
if ((pkg->depends[i]->flags & FLAG_BUILD_PKG) == 0) {
pkg->depends[i] = pkg->depends[pkg->num_depends - 1];
pkg->num_depends -= 1;
} else {
++i;
}
}
return 0;
}
static int find_no_dep(void *usr, const char *name, void *p)
{
source_pkg_t *pkg = p;
int *found = usr;
if (pkg->num_depends == 0) {
printf("%s\n", name);
pkg->flags &= ~FLAG_BUILD_PKG;
*found = 1;
}
return 0;
}
static int cmd_buildstrategy(int argc, char **argv)
{
int i, ret = EXIT_FAILURE;
const char *provides = NULL, *depends = NULL, *prefere = NULL;
int i, ret = EXIT_FAILURE, mode = MODE_BUILD_ORDER;
source_pkg_t *pkg;
if (process_args(argc, argv))
if (src_pkg_init())
return EXIT_FAILURE;
for (i = optind; i < argc; ++i) {
pkg = hash_table_lookup(&tbl_provides, argv[i]);
if (provider_init())
goto out_src;
if (pkg == NULL) {
fprintf(stderr, "nothing provides '%s'\n", argv[i]);
goto out;
for (;;) {
i = getopt_long(argc, argv, short_opts, long_opts, NULL);
if (i == -1)
break;
switch (i) {
case 'P':
prefere = optarg;
break;
case 'p':
provides = optarg;
break;
case 'd':
depends = optarg;
break;
case 'g':
mode = MODE_BUILD_GRAPH;
break;
default:
goto fail_arg;
}
}
if (optind >= argc) {
fputs("no packages specified\n", stderr);
goto fail_arg;
}
if (provides == NULL) {
fputs("no source package provides specified\n", stderr);
goto fail_arg;
}
if (prefere != NULL && foreach_line(prefere, handle_prefere) != 0)
goto out;
if (foreach_line(provides, handle_provides))
goto out;
if (depends != NULL && foreach_line(depends, handle_depends) != 0)
goto out;
for (i = optind; i < argc; ++i) {
pkg = provider_get(NULL, argv[i]);
if (pkg == NULL)
goto out;
pkg_mark_deps(pkg);
}
i = FLAG_BUILD_PKG;
hash_table_foreach(&tbl_sourcepkgs, &i, remove_untagged);
while (tbl_sourcepkgs.count > 0) {
i = 0;
hash_table_foreach(&tbl_sourcepkgs, &i, find_no_dep);
if (!i) {
fputs("cycle detected in package dependencies!\n",
stderr);
switch (mode) {
case MODE_BUILD_GRAPH:
fputs("digraph buildgraph {\n\tcompound=true;\n", stdout);
src_pkg_print_graph_cluster();
fputs("}\n", stdout);
break;
default:
if (src_pkg_output_build_order())
goto out;
}
hash_table_foreach(&tbl_sourcepkgs, NULL, remove_unmarked_deps);
i = FLAG_BUILD_PKG;
hash_table_foreach(&tbl_sourcepkgs, &i, remove_untagged);
break;
}
ret = EXIT_SUCCESS;
out:
i = 0;
hash_table_foreach(&tbl_sourcepkgs, &i, remove_untagged);
hash_table_cleanup(&tbl_sourcepkgs);
hash_table_cleanup(&tbl_provides);
provider_cleanup();
out_src:
src_pkg_cleanup();
return ret;
fail_arg:
tell_read_help(argv[0]);
goto out;
}
static command_t buildstrategy = {
@ -306,7 +216,15 @@ static command_t buildstrategy = {
" binary package.\n"
" --depends, -d <file> A two column CSV file. Each line contains the name\n"
" of a source package and a binary package that it\n"
" requires to build.\n",
" requires to build.\n"
" --prefere, -P <file> A two column CSV file. Each line contains the name\n"
" of a binary package and a source package that\n"
" produces this binary. If the `--provides` file\n"
" specifies that more than one source pacakge\n"
" provides a binary package, this file contains the\n"
" prefered one we should use.\n"
" --graph, -g Instead of printing out an ordered list, produce\n"
" a dot graph of the source packages to be built.\n",
.run_cmd = cmd_buildstrategy,
};

View File

@ -17,7 +17,13 @@ enum {
FLAG_BUILD_PKG = 0x01,
};
enum {
MODE_BUILD_ORDER = 0,
MODE_BUILD_GRAPH,
};
typedef struct source_pkg_t {
struct source_pkg_t *next;
char *name;
struct source_pkg_t **depends;
@ -26,4 +32,24 @@ typedef struct source_pkg_t {
int flags;
} source_pkg_t;
int src_pkg_init(void);
void src_pkg_cleanup(void);
source_pkg_t *src_pkg_get(const char *name);
int src_pkg_output_build_order(void);
int provider_init(void);
void provider_cleanup(void);
int provider_add(const char *sourcepkg, const char *binpkg);
int provider_add_prefered(const char *binpkg, const char *sourcepkg);
source_pkg_t *provider_get(const char *parent, const char *binpkg);
void src_pkg_print_graph_cluster(void);
#endif /* BUILDSTRATEGY_H */

View File

@ -0,0 +1,110 @@
/* SPDX-License-Identifier: ISC */
#include "buildstrategy.h"
static hash_table_t tbl_provides;
static hash_table_t tbl_preferes;
int provider_init(void)
{
if (hash_table_init(&tbl_provides, 1024))
return -1;
if (hash_table_init(&tbl_preferes, 1024)) {
hash_table_cleanup(&tbl_provides);
return -1;
}
return 0;
}
void provider_cleanup(void)
{
hash_table_cleanup(&tbl_provides);
hash_table_cleanup(&tbl_preferes);
}
int provider_add(const char *sourcepkg, const char *binpkg)
{
source_pkg_t *head = hash_table_lookup(&tbl_provides, binpkg), *src;
for (src = head; src != NULL; src = src->next) {
if (strcmp(src->name, sourcepkg) == 0)
return 0;
}
src = src_pkg_get(sourcepkg);
if (src == NULL)
return -1;
src->next = head;
return hash_table_set(&tbl_provides, binpkg, src);
}
int provider_add_prefered(const char *binpkg, const char *sourcepkg)
{
source_pkg_t *src = src_pkg_get(sourcepkg);
if (src == NULL)
return -1;
return hash_table_set(&tbl_preferes, binpkg, src);
}
source_pkg_t *provider_get(const char *parent, const char *binpkg)
{
source_pkg_t *spkg, *pref;
spkg = hash_table_lookup(&tbl_provides, binpkg);
if (spkg == NULL)
goto fail_none;
pref = hash_table_lookup(&tbl_preferes, binpkg);
if (spkg->next != NULL) {
if (pref == NULL)
goto fail_no_pref;
while (spkg != NULL && strcmp(spkg->name, pref->name) != 0) {
spkg = spkg->next;
}
if (spkg == NULL) {
spkg = hash_table_lookup(&tbl_provides, binpkg);
goto fail_provider;
}
} else {
if (pref != NULL && strcmp(spkg->name, pref->name) != 0)
goto fail_provider;
}
return spkg;
fail_none:
fprintf(stderr, "No source package provides binary package '%s'.\n\n",
binpkg);
goto fail;
fail_provider:
fprintf(stderr,
"Preferred provider for binary package '%s' is set to\n"
"source package '%s', which does not provide '%s'.\n\n",
binpkg, pref->name, binpkg);
goto fail_list_providers;
fail_no_pref:
fprintf(stderr, "No preferred provider set for "
"binary package '%s'.\n\n", binpkg);
goto fail_list_providers;
fail_list_providers:
fprintf(stderr, "The following source packages provide the "
"binary package '%s':\n\n", binpkg);
while (spkg != NULL) {
fprintf(stderr, "\t%s\n", spkg->name);
spkg = spkg->next;
}
fputc('\n', stderr);
goto fail;
fail:
if (parent != NULL) {
fprintf(stderr, "Binary package '%s' is required to "
"build source package '%s'\n", binpkg, parent);
}
return NULL;
}

View File

@ -0,0 +1,145 @@
/* SPDX-License-Identifier: ISC */
#include "buildstrategy.h"
static hash_table_t tbl_sourcepkgs;
static int src_pkg_destroy(void *usr, const char *name, void *p)
{
source_pkg_t *pkg = p;
(void)name; (void)usr;
free(pkg->name);
free(pkg->depends);
free(pkg);
return 1;
}
int src_pkg_init(void)
{
return hash_table_init(&tbl_sourcepkgs, 1024);
}
void src_pkg_cleanup(void)
{
hash_table_foreach(&tbl_sourcepkgs, NULL, src_pkg_destroy);
hash_table_cleanup(&tbl_sourcepkgs);
}
source_pkg_t *src_pkg_get(const char *name)
{
source_pkg_t *src = hash_table_lookup(&tbl_sourcepkgs, name);
if (src == NULL) {
src = calloc(1, sizeof(*src));
if (src == NULL)
goto fail_oom;
src->name = strdup(name);
if (src->name == NULL)
goto fail_oom;
if (hash_table_set(&tbl_sourcepkgs, name, src))
goto fail;
}
return src;
fail_oom:
fputs("out of memory\n", stderr);
fail:
if (src != NULL)
free(src->name);
free(src);
return NULL;
}
static int remove_untagged(void *usr, const char *name, void *p)
{
int mask = *((int *)usr);
source_pkg_t *pkg = p;
(void)name;
if ((pkg->flags & mask) == 0) {
free(pkg->name);
free(pkg->depends);
free(pkg);
return 1;
}
return 0;
}
static int find_no_dep(void *usr, const char *name, void *p)
{
source_pkg_t *pkg = p;
int *found = usr;
if (pkg->num_depends == 0) {
printf("%s\n", name);
pkg->flags &= ~FLAG_BUILD_PKG;
*found = 1;
}
return 0;
}
static int remove_unmarked_deps(void *usr, const char *name, void *p)
{
source_pkg_t *pkg = p;
size_t i = 0;
(void)usr; (void)name;
while (i < pkg->num_depends) {
if ((pkg->depends[i]->flags & FLAG_BUILD_PKG) == 0) {
pkg->depends[i] = pkg->depends[pkg->num_depends - 1];
pkg->num_depends -= 1;
} else {
++i;
}
}
return 0;
}
int src_pkg_output_build_order(void)
{
int i = FLAG_BUILD_PKG;
hash_table_foreach(&tbl_sourcepkgs, &i, remove_untagged);
while (tbl_sourcepkgs.count > 0) {
i = 0;
hash_table_foreach(&tbl_sourcepkgs, &i, find_no_dep);
if (!i) {
fputs("cycle detected in package dependencies!\n",
stderr);
return -1;
}
hash_table_foreach(&tbl_sourcepkgs, NULL, remove_unmarked_deps);
i = FLAG_BUILD_PKG;
hash_table_foreach(&tbl_sourcepkgs, &i, remove_untagged);
}
return 0;
}
static int print_cluster(void *usr, const char *name, void *p)
{
source_pkg_t *pkg = p;
size_t i;
(void)usr;
if (!(pkg->flags & FLAG_BUILD_PKG))
return 0;
for (i = 0; i < pkg->num_depends; ++i) {
printf("\t\"%s\" -> \"%s\"\n",
name, pkg->depends[i]->name);
}
return 0;
}
void src_pkg_print_graph_cluster(void)
{
hash_table_foreach(&tbl_sourcepkgs, NULL, print_cluster);
}

View File

@ -7,8 +7,9 @@
#include <stdio.h>
#include <fcntl.h>
#include "depgraph.h"
#include "pkg/pkglist.h"
#include "command.h"
#include "config.h"
static const struct option long_opts[] = {
{ "no-dependencies", no_argument, NULL, 'd' },
@ -37,7 +38,7 @@ static void print_dot_graph(struct pkg_dep_list *list)
static int cmd_depgraph(int argc, char **argv)
{
int i, repofd = AT_FDCWD, ret = EXIT_FAILURE;
int i, repofd = -1, ret = EXIT_FAILURE;
struct pkg_dep_list list;
bool resolve_deps = true;
@ -53,7 +54,7 @@ static int cmd_depgraph(int argc, char **argv)
resolve_deps = false;
break;
case 'R':
if (repofd != AT_FDCWD) {
if (repofd != -1) {
fputs("repo specified more than once\n",
stderr);
tell_read_help(argv[0]);
@ -71,6 +72,14 @@ static int cmd_depgraph(int argc, char **argv)
}
}
if (repofd == -1) {
repofd = open(REPODIR, O_RDONLY | O_DIRECTORY);
if (repofd < 0) {
perror(REPODIR);
goto out;
}
}
for (i = optind; i < argc; ++i) {
if (append_pkg(&list, argv[i]) == NULL)
goto out;
@ -84,7 +93,7 @@ static int cmd_depgraph(int argc, char **argv)
print_dot_graph(&list);
ret = EXIT_SUCCESS;
out:
if (repofd != AT_FDCWD)
if (repofd != -1)
close(repofd);
pkg_list_cleanup(&list);
return ret;
@ -101,6 +110,7 @@ static command_t depgraph = {
"Possible options:\n"
" --repo-dir, -R <path> Specify the input repository path to fetch the\n"
" packages from.\n"
" If not set, defaults to " REPODIR ".\n"
" --no-dependencies, -d Do not resolve dependencies, only process the\n"
" packages listed on the command line.\n",
.run_cmd = cmd_depgraph,

View File

@ -27,9 +27,7 @@ static int cmd_dump(int argc, char **argv)
switch (i) {
case 'l':
flags |= DUMP_TOC;
if (strcmp(optarg, "sqfs") == 0) {
format = TOC_FORMAT_SQFS;
} else if (strcmp(optarg, "initrd") == 0) {
if (strcmp(optarg, "initrd") == 0) {
format = TOC_FORMAT_INITRD;
} else if (strcmp(optarg, "pkg") == 0) {
format = TOC_FORMAT_PKG;
@ -108,10 +106,6 @@ static command_t dump = {
" If \"detail\" is specified, a human readable,\n"
" pretty printed format with details is used.\n"
"\n"
" If \"sqfs\" is specified, a squashfs pseudo\n"
" file is genareated for setting permissions\n"
" bits and ownership appropriately.\n"
"\n"
" If \"initrd\" is specified, the format of\n"
" Linux gen_init_cpio is produced.\n"
"\n"

View File

@ -12,10 +12,11 @@
#include "filelist/image_entry.h"
#include "pkgformat.h"
#include "pkgreader.h"
#include "pkg/pkgformat.h"
#include "pkg/pkgreader.h"
#include "pkg/pkgio.h"
#include "command.h"
#include "pkgio.h"
typedef enum {
DUMP_TOC = 0x01,

View File

@ -7,10 +7,11 @@
#include <stdio.h>
#include <fcntl.h>
#include "pkg/pkglist.h"
#include "pkg/pkgio.h"
#include "util/util.h"
#include "depgraph.h"
#include "command.h"
#include "pkgio.h"
#include "config.h"
enum {
INSTALL_MODE_INSTALL = 0,
@ -95,8 +96,8 @@ static int list_files(int repofd, const char *rootdir, TOC_FORMAT format,
static int cmd_install(int argc, char **argv)
{
int i, rootfd = AT_FDCWD, repofd = AT_FDCWD, flags = 0;
int ret = EXIT_FAILURE, mode = INSTALL_MODE_INSTALL;
int i, rootfd = -1, repofd = -1, flags = 0;
TOC_FORMAT format = TOC_FORMAT_PRETTY;
const char *rootdir = NULL;
struct pkg_dep_list list;
@ -118,9 +119,7 @@ static int cmd_install(int argc, char **argv)
break;
case 'l':
mode = INSTALL_MODE_LIST_FILES;
if (strcmp(optarg, "sqfs") == 0) {
format = TOC_FORMAT_SQFS;
} else if (strcmp(optarg, "initrd") == 0) {
if (strcmp(optarg, "initrd") == 0) {
format = TOC_FORMAT_INITRD;
} else if (strcmp(optarg, "pkg") == 0) {
format = TOC_FORMAT_PKG;
@ -133,7 +132,7 @@ static int cmd_install(int argc, char **argv)
}
break;
case 'R':
if (repofd != AT_FDCWD) {
if (repofd != -1) {
fputs("repo specified more than once\n",
stderr);
tell_read_help(argv[0]);
@ -146,7 +145,7 @@ static int cmd_install(int argc, char **argv)
}
break;
case 'r':
if (rootfd != AT_FDCWD) {
if (rootfd != -1) {
fputs("root specified more than once\n",
stderr);
tell_read_help(argv[0]);
@ -182,6 +181,22 @@ static int cmd_install(int argc, char **argv)
}
}
if (repofd == -1) {
repofd = open(REPODIR, O_RDONLY | O_DIRECTORY);
if (repofd < 0) {
perror(REPODIR);
goto out;
}
}
if (rootfd == -1) {
rootfd = open(INSTALLROOT, O_RDONLY | O_DIRECTORY);
if (rootfd < 0) {
perror(INSTALLROOT);
goto out;
}
}
for (i = optind; i < argc; ++i) {
if (append_pkg(&list, argv[i]) == NULL)
goto out;
@ -211,9 +226,9 @@ static int cmd_install(int argc, char **argv)
ret = EXIT_SUCCESS;
out:
if (rootfd != AT_FDCWD)
if (rootfd != -1)
close(rootfd);
if (repofd != AT_FDCWD)
if (repofd != -1)
close(repofd);
pkg_list_cleanup(&list);
return ret;
@ -231,11 +246,12 @@ static command_t install = {
"Possible options:\n"
" --repo-dir, -R <path> Specify the input repository path to fetch the\n"
" packages from.\n"
" --root, -r <path> A root directory to unpack the package. Default\n"
" if not set is the current working directory.\n"
" If not set, defaults to " REPODIR ".\n"
" --root, -r <path> A root directory to unpack the package.\n"
" If not set, defaults to " INSTALLROOT ".\n"
" --no-chown, -o Do not change ownership of the extracted data.\n"
" Keep the uid/gid of the user who runs the \n"
" program."
" program.\n"
" --no-chmod, -m Do not change permission flags of the extarcted\n"
" data. Use 0644 for all files and 0755 for all\n"
" directories.\n"
@ -252,10 +268,6 @@ static command_t install = {
" If \"detail\" is specified, a human readable,\n"
" pretty printed format with details is used.\n"
"\n"
" If \"sqfs\" is specified, a squashfs pseudo\n"
" file is genareated for setting permissions bits\n"
" and ownership appropriately.\n"
"\n"
" If \"initrd\" is specified, the format of Linux\n"
" gen_init_cpio is produced.\n",
.run_cmd = cmd_install,

View File

@ -13,6 +13,22 @@ static void oom(const char *filename, size_t linenum)
input_file_complain(filename, linenum, "out of memory");
}
static void unescape_name(char *name)
{
char *dst = name, *src = name + 1;
while (*src != '"' && *src != '\0') {
if (src[0] == '\\' && (src[1] == '\\' || src[1] == '"')) {
*(dst++) = src[1];
src += 2;
} else {
*(dst++) = *(src++);
}
}
*dst = '\0';
}
static image_entry_t *filelist_mkentry(char *line, const char *filename,
size_t linenum, mode_t filetype)
{
@ -27,8 +43,23 @@ static image_entry_t *filelist_mkentry(char *line, const char *filename,
}
/* name */
for (i = 0; !isspace(line[i]) && line[i] != '\0'; ++i)
;
if (*line == '"') {
for (i = 1; line[i] != '"' && line[i] != '\0'; ++i) {
if (line[i] == '\\' &&
(line[i + 1] == '\\' || line[i + 1] == '"')) {
++i;
}
}
if (line[i++] != '"') {
input_file_complain(filename, linenum,
"missing \" after file name");
goto fail;
}
} else {
for (i = 0; !isspace(line[i]) && line[i] != '\0'; ++i)
;
}
if (!isspace(line[i])) {
input_file_complain(filename, linenum,
@ -43,6 +74,10 @@ static image_entry_t *filelist_mkentry(char *line, const char *filename,
}
memcpy(ent->name, line, i);
if (ent->name[0] == '"')
unescape_name(ent->name);
if (canonicalize_name(ent->name)) {
input_file_complain(filename, linenum, "invalid file name");
goto fail;

View File

@ -65,9 +65,7 @@ static int cmd_pack(int argc, char **argv)
}
if (repodir == NULL) {
fputs("missing argument: repository directory\n", stderr);
tell_read_help(argv[0]);
return EXIT_FAILURE;
repodir = REPODIR;
}
if (optind < argc)
@ -117,6 +115,7 @@ static command_t pack = {
" --file-list, -l <path> Specify a file containing a list of input files.\n"
" --repo-dir, -r <path> Specify the output repository path to store the\n"
" package in.\n"
" If not set, defaults to " REPODIR ".\n"
" --description, -d <path> Specify a file containing a description of the\n"
" package, including information such as package\n"
" dependencies, the actual package name, etc.\n"

View File

@ -21,10 +21,11 @@
#include "filelist/image_entry.h"
#include "compressor.h"
#include "pkgformat.h"
#include "pkgwriter.h"
#include "comp/compressor.h"
#include "pkg/pkgformat.h"
#include "pkg/pkgwriter.h"
#include "command.h"
#include "config.h"
typedef struct dependency_t {
struct dependency_t *next;

View File

@ -7,9 +7,9 @@
#include "util/util.h"
#include "pkgreader.h"
#include "pkg/pkgreader.h"
#include "pkg/pkgio.h"
#include "command.h"
#include "pkgio.h"
static const struct option long_opts[] = {
{ "root", required_argument, NULL, 'r' },

View File

@ -1,32 +0,0 @@
/* SPDX-License-Identifier: ISC */
#include <string.h>
#include "compressor.h"
static compressor_t *list = NULL;
void compressor_register(compressor_t *compressor)
{
compressor->next = list;
list = compressor;
}
compressor_t *compressor_by_name(const char *name)
{
compressor_t *it = list;
while (it != NULL && strcmp(it->name, name) != 0)
it = it->next;
return it;
}
compressor_t *compressor_by_id(PKG_COMPRESSION id)
{
compressor_t *it = list;
while (it != NULL && it->id != id)
it = it->next;
return it;
}