mirror of
https://github.com/pygos/pkg-utils.git
synced 2024-11-24 21:40:43 +01:00
Add support for device special files in packages
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
This commit is contained in:
parent
6f32c6b883
commit
16bf7172fe
11 changed files with 174 additions and 14 deletions
|
@ -21,6 +21,10 @@ typedef struct image_entry_t {
|
||||||
struct {
|
struct {
|
||||||
char *target;
|
char *target;
|
||||||
} symlink;
|
} symlink;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
dev_t devno;
|
||||||
|
} device;
|
||||||
} data;
|
} data;
|
||||||
} image_entry_t;
|
} image_entry_t;
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,10 @@ typedef struct {
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
} toc_file_extra_t;
|
} toc_file_extra_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t devno;
|
||||||
|
} toc_device_extra_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
/* uint8_t data[]; */
|
/* uint8_t data[]; */
|
||||||
|
|
|
@ -8,6 +8,7 @@ enum {
|
||||||
UNPACK_NO_CHOWN = 0x01,
|
UNPACK_NO_CHOWN = 0x01,
|
||||||
UNPACK_NO_CHMOD = 0x02,
|
UNPACK_NO_CHMOD = 0x02,
|
||||||
UNPACK_NO_SYMLINKS = 0x04,
|
UNPACK_NO_SYMLINKS = 0x04,
|
||||||
|
UNPACK_NO_DEVICES = 0x08,
|
||||||
};
|
};
|
||||||
|
|
||||||
int pkg_unpack(int rootfd, int flags, pkg_reader_t *rd);
|
int pkg_unpack(int rootfd, int flags, pkg_reader_t *rd);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <sys/sysmacros.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -31,6 +32,18 @@ static int print_pretty(image_entry_t *ent, const char *root)
|
||||||
case S_IFDIR:
|
case S_IFDIR:
|
||||||
fputs("directory\n\n", stdout);
|
fputs("directory\n\n", stdout);
|
||||||
break;
|
break;
|
||||||
|
case S_IFCHR:
|
||||||
|
fputs("character device\n", stdout);
|
||||||
|
printf("\tmajor: %u\n\tminor: %u\n\n",
|
||||||
|
major(ent->data.device.devno),
|
||||||
|
minor(ent->data.device.devno));
|
||||||
|
break;
|
||||||
|
case S_IFBLK:
|
||||||
|
fputs("block device\n", stdout);
|
||||||
|
printf("\tmajor: %u\n\tminor: %u\n\n",
|
||||||
|
major(ent->data.device.devno),
|
||||||
|
minor(ent->data.device.devno));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fputs("unknown\n\n", stdout);
|
fputs("unknown\n\n", stdout);
|
||||||
goto fail_type;
|
goto fail_type;
|
||||||
|
@ -46,12 +59,32 @@ static int print_sqfs(image_entry_t *ent, const char *root)
|
||||||
mode_t mode = ent->mode & (~S_IFMT);
|
mode_t mode = ent->mode & (~S_IFMT);
|
||||||
(void)root;
|
(void)root;
|
||||||
|
|
||||||
if ((ent->mode & S_IFMT) == S_IFLNK)
|
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;
|
mode = 0777;
|
||||||
|
/* fall-through */
|
||||||
|
case S_IFDIR:
|
||||||
|
case S_IFREG:
|
||||||
printf("%s m %o %u %u\n", ent->name, mode,
|
printf("%s m %o %u %u\n", ent->name, mode,
|
||||||
(unsigned int)ent->uid,
|
(unsigned int)ent->uid, (unsigned int)ent->gid);
|
||||||
(unsigned int)ent->gid);
|
break;
|
||||||
|
default:
|
||||||
|
fputs("unknown file type in table of contents\n", stderr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +93,18 @@ static int print_initrd(image_entry_t *ent, const char *root)
|
||||||
mode_t mode = ent->mode & (~S_IFMT);
|
mode_t mode = ent->mode & (~S_IFMT);
|
||||||
|
|
||||||
switch (ent->mode & S_IFMT) {
|
switch (ent->mode & S_IFMT) {
|
||||||
|
case S_IFCHR:
|
||||||
|
printf("nod /%s 0%o %u %u c %u %u\n", ent->name, mode,
|
||||||
|
(unsigned int)ent->uid, (unsigned int)ent->gid,
|
||||||
|
major(ent->data.device.devno),
|
||||||
|
minor(ent->data.device.devno));
|
||||||
|
return 0;
|
||||||
|
case S_IFBLK:
|
||||||
|
printf("nod /%s 0%o %u %u b %u %u\n", ent->name, mode,
|
||||||
|
(unsigned int)ent->uid, (unsigned int)ent->gid,
|
||||||
|
major(ent->data.device.devno),
|
||||||
|
minor(ent->data.device.devno));
|
||||||
|
return 0;
|
||||||
case S_IFLNK:
|
case S_IFLNK:
|
||||||
printf("slink /%s %s", ent->name, ent->data.symlink.target);
|
printf("slink /%s %s", ent->name, ent->data.symlink.target);
|
||||||
mode = 0777;
|
mode = 0777;
|
||||||
|
|
|
@ -10,10 +10,11 @@ static const struct option long_opts[] = {
|
||||||
{ "list-files", no_argument, NULL, 'l' },
|
{ "list-files", no_argument, NULL, 'l' },
|
||||||
{ "format", required_argument, NULL, 'F' },
|
{ "format", required_argument, NULL, 'F' },
|
||||||
{ "no-symlinks", no_argument, NULL, 'L' },
|
{ "no-symlinks", no_argument, NULL, 'L' },
|
||||||
|
{ "no-devices", no_argument, NULL, 'D' },
|
||||||
{ NULL, 0, NULL, 0 },
|
{ NULL, 0, NULL, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *short_opts = "r:omdR:plF:L";
|
static const char *short_opts = "r:omdR:plF:LD";
|
||||||
|
|
||||||
static int unpack_packages(int repofd, int rootfd, int flags,
|
static int unpack_packages(int repofd, int rootfd, int flags,
|
||||||
struct pkg_dep_list *list)
|
struct pkg_dep_list *list)
|
||||||
|
@ -154,6 +155,9 @@ static int cmd_install(int argc, char **argv)
|
||||||
case 'L':
|
case 'L':
|
||||||
flags |= UNPACK_NO_SYMLINKS;
|
flags |= UNPACK_NO_SYMLINKS;
|
||||||
break;
|
break;
|
||||||
|
case 'D':
|
||||||
|
flags |= UNPACK_NO_DEVICES;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
tell_read_help(argv[0]);
|
tell_read_help(argv[0]);
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
@ -206,10 +206,54 @@ fail:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int filelist_mknod(input_file_t *f, void *obj)
|
||||||
|
{
|
||||||
|
image_entry_t **listptr = obj, *ent;
|
||||||
|
unsigned int maj, min;
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
ent = filelist_mkentry(f, S_IFCHR);
|
||||||
|
if (ent == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
switch (f->line[0]) {
|
||||||
|
case 'c':
|
||||||
|
case 'C':
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
case 'B':
|
||||||
|
ent->mode = (ent->mode & (~S_IFMT)) | S_IFBLK;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isspace(f->line[1]))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
ptr = f->line + 1;
|
||||||
|
while (isspace(*ptr))
|
||||||
|
++ptr;
|
||||||
|
|
||||||
|
if (sscanf(ptr, "%u %u", &maj, &min) != 2)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
ent->data.device.devno = makedev(maj, min);
|
||||||
|
|
||||||
|
ent->next = *listptr;
|
||||||
|
*listptr = ent;
|
||||||
|
return 0;
|
||||||
|
fail:
|
||||||
|
image_entry_free(ent);
|
||||||
|
input_file_complain(f, "error in device specification");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static const keyword_handler_t line_hooks[] = {
|
static const keyword_handler_t line_hooks[] = {
|
||||||
{ "file", filelist_mkfile },
|
{ "file", filelist_mkfile },
|
||||||
{ "dir", filelist_mkdir },
|
{ "dir", filelist_mkdir },
|
||||||
{ "slink", filelist_mkslink },
|
{ "slink", filelist_mkslink },
|
||||||
|
{ "nod", filelist_mknod },
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NUM_LINE_HOOKS (sizeof(line_hooks) / sizeof(line_hooks[0]))
|
#define NUM_LINE_HOOKS (sizeof(line_hooks) / sizeof(line_hooks[0]))
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/sysmacros.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
|
@ -48,6 +48,16 @@ static int write_entry(pkg_writer_t *wr, image_entry_t *it)
|
||||||
}
|
}
|
||||||
case S_IFDIR:
|
case S_IFDIR:
|
||||||
break;
|
break;
|
||||||
|
case S_IFBLK:
|
||||||
|
case S_IFCHR: {
|
||||||
|
toc_device_extra_t dev;
|
||||||
|
|
||||||
|
dev.devno = htole64(it->data.device.devno);
|
||||||
|
|
||||||
|
if (pkg_writer_write_payload(wr, &dev, sizeof(dev)))
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,11 @@ static const struct option long_opts[] = {
|
||||||
{ "no-chown", no_argument, NULL, 'o' },
|
{ "no-chown", no_argument, NULL, 'o' },
|
||||||
{ "no-chmod", no_argument, NULL, 'm' },
|
{ "no-chmod", no_argument, NULL, 'm' },
|
||||||
{ "no-symlinks", no_argument, NULL, 'L' },
|
{ "no-symlinks", no_argument, NULL, 'L' },
|
||||||
|
{ "no-devices", no_argument, NULL, 'D' },
|
||||||
{ NULL, 0, NULL, 0 },
|
{ NULL, 0, NULL, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *short_opts = "r:omL";
|
static const char *short_opts = "r:omLD";
|
||||||
|
|
||||||
static int cmd_unpack(int argc, char **argv)
|
static int cmd_unpack(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
@ -38,6 +39,9 @@ static int cmd_unpack(int argc, char **argv)
|
||||||
case 'L':
|
case 'L':
|
||||||
flags |= UNPACK_NO_SYMLINKS;
|
flags |= UNPACK_NO_SYMLINKS;
|
||||||
break;
|
break;
|
||||||
|
case 'D':
|
||||||
|
flags |= UNPACK_NO_DEVICES;
|
||||||
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
flags |= UNPACK_NO_CHOWN;
|
flags |= UNPACK_NO_CHOWN;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -40,6 +41,20 @@ static int create_hierarchy(int dirfd, image_entry_t *list, int flags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (ent = list; ent != NULL; ent = ent->next) {
|
||||||
|
if (S_ISBLK(ent->mode) || S_ISCHR(ent->mode)) {
|
||||||
|
if (flags & UNPACK_NO_DEVICES)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (mknodat(dirfd, ent->name, ent->mode,
|
||||||
|
ent->data.device.devno)) {
|
||||||
|
fprintf(stderr, "mknod %s: %s\n",
|
||||||
|
ent->name, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,13 +148,29 @@ fail_trunc:
|
||||||
|
|
||||||
static int change_permissions(int dirfd, image_entry_t *list, int flags)
|
static int change_permissions(int dirfd, image_entry_t *list, int flags)
|
||||||
{
|
{
|
||||||
while (list != NULL) {
|
bool do_chmod, do_chown;
|
||||||
if (S_ISLNK(list->mode)) {
|
|
||||||
list = list->next;
|
for (; list != NULL; list = list->next) {
|
||||||
|
do_chmod = (flags & UNPACK_NO_CHMOD) == 0;
|
||||||
|
do_chown = (flags & UNPACK_NO_CHOWN) == 0;
|
||||||
|
|
||||||
|
switch (list->mode & S_IFMT) {
|
||||||
|
case S_IFLNK:
|
||||||
|
if (flags & UNPACK_NO_SYMLINKS)
|
||||||
continue;
|
continue;
|
||||||
|
do_chmod = false;
|
||||||
|
break;
|
||||||
|
case S_IFBLK:
|
||||||
|
case S_IFCHR:
|
||||||
|
if (flags & UNPACK_NO_DEVICES)
|
||||||
|
continue;
|
||||||
|
do_chmod = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(flags & UNPACK_NO_CHMOD) && !S_ISLNK(list->mode)) {
|
if (do_chmod) {
|
||||||
if (fchmodat(dirfd, list->name,
|
if (fchmodat(dirfd, list->name,
|
||||||
list->mode & 07777, 0)) {
|
list->mode & 07777, 0)) {
|
||||||
fprintf(stderr, "%s: chmod: %s\n", list->name,
|
fprintf(stderr, "%s: chmod: %s\n", list->name,
|
||||||
|
@ -148,7 +179,7 @@ static int change_permissions(int dirfd, image_entry_t *list, int flags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(flags & UNPACK_NO_CHOWN)) {
|
if (do_chown) {
|
||||||
if (fchownat(dirfd, list->name, list->uid, list->gid,
|
if (fchownat(dirfd, list->name, list->uid, list->gid,
|
||||||
AT_SYMLINK_NOFOLLOW)) {
|
AT_SYMLINK_NOFOLLOW)) {
|
||||||
fprintf(stderr, "%s: chown: %s\n", list->name,
|
fprintf(stderr, "%s: chown: %s\n", list->name,
|
||||||
|
@ -156,8 +187,6 @@ static int change_permissions(int dirfd, image_entry_t *list, int flags)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list = list->next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -52,6 +52,20 @@ static int read_extra(pkg_reader_t *pkg, image_entry_t *ent)
|
||||||
}
|
}
|
||||||
case S_IFDIR:
|
case S_IFDIR:
|
||||||
break;
|
break;
|
||||||
|
case S_IFBLK:
|
||||||
|
case S_IFCHR: {
|
||||||
|
toc_device_extra_t extra;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = pkg_reader_read_payload(pkg, &extra, sizeof(extra));
|
||||||
|
if (ret < 0)
|
||||||
|
return -1;
|
||||||
|
if ((size_t)ret < sizeof(extra))
|
||||||
|
goto fail_trunc;
|
||||||
|
|
||||||
|
ent->data.device.devno = le64toh(extra.devno);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
goto fail_unknown;
|
goto fail_unknown;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue