Add support for device special files in packages

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
This commit is contained in:
David Oberhollenzer 2019-02-04 17:43:24 +01:00
parent 6f32c6b883
commit 16bf7172fe
11 changed files with 174 additions and 14 deletions

View File

@ -21,6 +21,10 @@ typedef struct image_entry_t {
struct {
char *target;
} symlink;
struct {
dev_t devno;
} device;
} data;
} image_entry_t;

View File

@ -53,6 +53,10 @@ typedef struct {
uint32_t id;
} toc_file_extra_t;
typedef struct {
uint64_t devno;
} toc_device_extra_t;
typedef struct {
uint32_t id;
/* uint8_t data[]; */

View File

@ -8,6 +8,7 @@ enum {
UNPACK_NO_CHOWN = 0x01,
UNPACK_NO_CHMOD = 0x02,
UNPACK_NO_SYMLINKS = 0x04,
UNPACK_NO_DEVICES = 0x08,
};
int pkg_unpack(int rootfd, int flags, pkg_reader_t *rd);

View File

@ -1,3 +1,4 @@
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
@ -31,6 +32,18 @@ static int print_pretty(image_entry_t *ent, const char *root)
case S_IFDIR:
fputs("directory\n\n", stdout);
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:
fputs("unknown\n\n", stdout);
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);
(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;
/* 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;
}
printf("%s m %o %u %u\n", ent->name, mode,
(unsigned int)ent->uid,
(unsigned int)ent->gid);
return 0;
}
@ -60,6 +93,18 @@ static int print_initrd(image_entry_t *ent, const char *root)
mode_t mode = 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:
printf("slink /%s %s", ent->name, ent->data.symlink.target);
mode = 0777;

View File

@ -10,10 +10,11 @@ static const struct option long_opts[] = {
{ "list-files", no_argument, NULL, 'l' },
{ "format", required_argument, NULL, 'F' },
{ "no-symlinks", no_argument, NULL, 'L' },
{ "no-devices", no_argument, NULL, 'D' },
{ 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,
struct pkg_dep_list *list)
@ -154,6 +155,9 @@ static int cmd_install(int argc, char **argv)
case 'L':
flags |= UNPACK_NO_SYMLINKS;
break;
case 'D':
flags |= UNPACK_NO_DEVICES;
break;
default:
tell_read_help(argv[0]);
goto out;

View File

@ -206,10 +206,54 @@ fail:
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[] = {
{ "file", filelist_mkfile },
{ "dir", filelist_mkdir },
{ "slink", filelist_mkslink },
{ "nod", filelist_mknod },
};
#define NUM_LINE_HOOKS (sizeof(line_hooks) / sizeof(line_hooks[0]))

View File

@ -3,6 +3,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

View File

@ -48,6 +48,16 @@ static int write_entry(pkg_writer_t *wr, image_entry_t *it)
}
case S_IFDIR:
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:
assert(0);
}

View File

@ -15,10 +15,11 @@ static const struct option long_opts[] = {
{ "no-chown", no_argument, NULL, 'o' },
{ "no-chmod", no_argument, NULL, 'm' },
{ "no-symlinks", no_argument, NULL, 'L' },
{ "no-devices", no_argument, NULL, 'D' },
{ 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)
{
@ -38,6 +39,9 @@ static int cmd_unpack(int argc, char **argv)
case 'L':
flags |= UNPACK_NO_SYMLINKS;
break;
case 'D':
flags |= UNPACK_NO_DEVICES;
break;
case 'o':
flags |= UNPACK_NO_CHOWN;
break;

View File

@ -1,5 +1,6 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.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;
}
@ -133,13 +148,29 @@ fail_trunc:
static int change_permissions(int dirfd, image_entry_t *list, int flags)
{
while (list != NULL) {
if (S_ISLNK(list->mode)) {
list = list->next;
continue;
bool do_chmod, do_chown;
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;
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,
list->mode & 07777, 0)) {
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,
AT_SYMLINK_NOFOLLOW)) {
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;
}
}
list = list->next;
}
return 0;

View File

@ -52,6 +52,20 @@ static int read_extra(pkg_reader_t *pkg, image_entry_t *ent)
}
case S_IFDIR:
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:
goto fail_unknown;
}