This service is available only in Japanese-language.

rootを封印してsudoユーザを新規登録すると作成したパーティションの所有者がsudoユーザのものになる

よろしくお願いします。
■yocto project : v4.0 (Kirkstone)
■ターゲット : Raspberry Pi CM4

まず、rootユーザを以下の通り封印して新しくsudoユーザを登録するようlocal.confに記載しました。
--------
INHERIT += " extrausers"

# root(管理者アカウント : 封印)
EXTRA_USERS_PARAMS += " \
usermod -g root root; \
usermod -s /bin/false root; \
usermod -m -d /root root; \
usermod -p '**************************' root; \
"

# originalgrp(新規ユーザグループ)
EXTRA_USERS_PARAMS += " \
groupadd -f originalgrp; \
"

# alternative(管理者アカウント代替)
EXTRA_USERS_PARAMS += " \
useradd -g sudo alternative; \
usermod -aG originalgrp alternative; \
usermod -s /bin/bash alternative; \
usermod -m -d /home/alternative alternative; \
usermod -p '**************************' alternative; \
"
--------

また、いくつかのパーティションを作成するようオリジナルのwksファイルも使用するようにしました。
各パーティション用のpythonファイルはrootfs.pyを参考にして用意しました。
--------
# Use original partition wks file
WKS_FILE = "sdimage-raspberrypi-original.wks"
--------

結論としては各アカウントは意図通り登録され、各パーティションも作成されました。ここで問題なのは、その各パーティションの所有者が上記で作成したsudoユーザになっている点です。
→各パーティションの所有者はsudoユーザを作成するまで(rootを封印していない状態)はrootでした。

これはyoctoでパーティションを作成する段階(おそらくfakeroot時?)でそのようになっているのだと思われますが、これを回避してroot所有とすることは可能でしょうか?

sdimage-raspberrypi-original.wksの中身
--------
part /boot --source bootimg-partition --ondisk mmcblk0 --fstype=vfat --label boot --active --align 4096 --size 20M
part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --label root --align 4096 --size 256M
part /swap --ondisk mmcblk0 --fstype=swap --label swap --align 4096 --size 200M
part /opt --source org-opt --ondisk mmcblk0 --fstype=ext4 --label opt --align 4096 --size 128M
part /log --source org-log --ondisk mmcblk0 --fstype=ext4 --label log --align 4096 --size 200M
--------

自分で作成したpythonスクリプト(基本的にはどのパーティションもつくりは同じです)
--------
import logging
import os
import shutil

from wic import WicError
from wic.pluginbase import SourcePlugin
from wic.misc import exec_cmd, get_bitbake_var, exec_native_cmd

logger = logging.getLogger('wic')
logger.setLevel(logging.DEBUG)

class LOGPartPlugin(SourcePlugin):
"""
Populate partition content from a /log directory.
"""

name = 'ilips-log'

@staticmethod
def __get_pseudo(native_sysroot, rootfs, pseudo_dir):
pseudo = "export PSEUDO_PREFIX=%s/usr;" % native_sysroot
pseudo += "export PSEUDO_LOCALSTATEDIR=%s;" % pseudo_dir
pseudo += "export PSEUDO_PASSWD=%s;" % rootfs
pseudo += "export PSEUDO_NOSYMLINKEXP=1;"
pseudo += "%s " % get_bitbake_var("FAKEROOTCMD")
return pseudo

@classmethod
def do_prepare_partition(cls, part, source_params, cr, cr_workdir,
oe_builddir, bootimg_dir, kernel_dir,
rootfs_dir, native_sysroot):
"""
Called to do the actual content population for a partition i.e. it
'prepares' the partition to be incorporated into the image.
"""
# ※各パーティション用のディレクトリは IMAGE_ROOTFS のひとつ上のディレクトリに作成(../log)
#  されているのでこれを利用するものとする。
#  -> build/tmp/work/raspberrypi_cm4_64-poky-linux/core-image-base/1.0-r0/rootfs
log_dir = os.path.join(str(get_bitbake_var("IMAGE_ROOTFS")), "../log")
if os.path.exists(log_dir):
logger.info('log_dir(%s) is exist', log_dir)
else:
logger.critical('log_dir(%s) is not exist', log_dir)
raise WicError("Couldn't find LOG directory...")

logger.debug(' cls :%s', str(cls))
logger.debug(' part :%s', str(part))
logger.debug(' source_params :%s', str(source_params))
logger.debug(' cr :%s', str(cr))
logger.debug(' cr_workdir :%s', str(cr_workdir))
logger.debug(' oe_builddir :%s', str(oe_builddir))
logger.debug(' bootimg_dir :%s', str(bootimg_dir))
logger.debug(' kernel_dir :%s', str(kernel_dir))
logger.debug(' rootfs_dir :%s', str(rootfs_dir))
logger.debug(' native_sysroot:%s', str(native_sysroot))

# 投入先のパーティション設定
dst = os.path.join(cr_workdir, "tmpdir.%s" % part.lineno)
if not os.path.exists(dst):
os.makedirs(dst)
logger.info('log_dir dst :%s', dst)

pseudo_dir = os.path.join(dst, "../pseudo")
pseudo = cls.__get_pseudo(native_sysroot, dst, pseudo_dir)

# あらかじめ用意された内容物を一気にコピー
copy_cmd = "cp -a %s %s" % ((log_dir + os.sep + "/*").replace('//', '/'), dst)
logger.info('log_dir cmd :%s', str(copy_cmd))
exec_native_cmd(copy_cmd, native_sysroot, pseudo)

part.prepare_rootfs(cr_workdir, oe_builddir,
dst, native_sysroot,
pseudo_dir = pseudo_dir)
--------
※各パーティションはあらかじめ「rootfs」が作成される場所と同じ位置に作成しています。
 <yocto work>/build/tmp/work/raspberrypi_cm4_64-poky-linux/core-image-base/1.0-r0

お世話になります。本件回答いたします。
まず、sdimage-raspberrypi-original.wksの中身の情報ありがとうございます。

---
part /boot --source bootimg-partition --ondisk mmcblk0 --fstype=vfat --label boot --active --align 4096 --size 20M
part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --label root --align 4096 --size 256M
part /swap --ondisk mmcblk0 --fstype=swap --label swap --align 4096 --size 200M
part /opt --source org-opt --ondisk mmcblk0 --fstype=ext4 --label opt --align 4096 --size 128M
part /log --source org-log --ondisk mmcblk0 --fstype=ext4 --label log --align 4096 --size 200M
---

/optと/logのパーティションに対して`--source org-opt`のように
自作のpythonファイルを指定している旨、理解いたしました。
wksで`--source`によって指定されるpythonスクリプトは「sourceプラグイン」と呼ばれます。

今回作成したsourceプラグインの目的は下記のどちらになりますでしょうか?

1. ホストマシンに用意したファイル群をイメージ作成時にコピーする
2. /opt、/logのマウントポイントを作成する(中身は空で良い)

1. のケースの場合、レシピで管理されないファイルをターゲットのイメージに書き込む事は
今回のようなトラブルのもととなるので一般的には避けるように設計します。
また、sourceプラグインの自作も本来、頻繁に行うものではありません。

2. のケースの場合は通常、sourceプラグインを作成する必要はなく、
core-image-base.bbappendなど、イメージレシピに対するbbappendを作成して次のような処理を記述します。

---
create_dirs() {
mkdir ${IMAGE_ROOTFS}/opt
mkdir ${IMAGE_ROOTFS}/log
}

ROOTFS_POSTPROCESS_COMMAND += "create_dirs;"
---

その場合、wksも下記のように修正刷る必要があります。

---
part /boot --source bootimg-partition --ondisk mmcblk0 --fstype=vfat --label boot --active --align 4096 --size 20M
part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --label root --align 4096 --size 256M
part /swap --ondisk mmcblk0 --fstype=swap --label swap --align 4096 --size 200M
part /opt --ondisk mmcblk0 --fstype=ext4 --label opt --align 4096 --size 128M
part /log --ondisk mmcblk0 --fstype=ext4 --label log --align 4096 --size 200M
---

ここまでの設計上の問題点を踏まえた上でですが、
今回の実装上の問題について記載いたします。

今回、追加したファイル及びディレクトリのパーミッションが、
alternativeユーザのものとなってしまうとの事でしたが、
実際にはそうではなく、UID=1000になっていることが問題となります。
自作したsourceプラグインの実装に問題があり、ホストマシンのパーミッション情報が
ターゲット向けのイメージに入り込んでしまっているという事です。
ホストマシンの一般ユーザーのユーザIDと
今回ターゲットに追加したalternativeユーザのIDがたまたま一致した状況です。

その原因ですが、自作したpythonスクリプトの下記の部分で
cpコマンドに「-a」オプションを与えている事となります。
これによってホストマシン上のパーミッション情報もすべてコピーされてしまうため、
今回の現象は発生しています。

---
copy_cmd = "cp -a %s %s" % ((log_dir + os.sep + "/*").replace('//', '/'), dst)
---

例えば下記のようにすることでパーミッション情報のコピーは発生しなくなるため
意図した挙動になるかと思います。

---
copy_cmd = "cp -r %s %s" % ((log_dir + os.sep + "/*").replace('//', '/'), dst)
---

また、この実装では下記のようにイメージをクリーンビルドしたタイミングで
コピー元となるホストマシン上のlogやoptが
削除される可能性がありますので、
設計上の観点からsourceプラグインを自作せずに済む方法で見直しを行うことをお勧めします。

---
$ bitbake core-image-base -c clean
$ bitbake core-image-base
---

以上、よろしくお願いいたします。

> 今回作成したsourceプラグインの目的は下記のどちらになりますでしょうか?
>
> 1. ホストマシンに用意したファイル群をイメージ作成時にコピーする
> 2. /opt、/logのマウントポイントを作成する(中身は空で良い)

上記は1です。レシピで管理されないものの扱いについては今後再考することとします。
マウントポイントの作成そのものは2のやり方で行っております(もう少し明かすと、マウントポイントの作成とマウント元のパーティション中身作成{削除して新規作成}を記載した関数をROOTFS_POSTPROCESS_COMMANDで追加しています)。

alternativeユーザと勘違いしていた点については、仕組み的にたまたま合致してそう見えただけということ、理解しました。
上記のアドバイスのとおりcpコマンドのオプションを変更してUID.GIDともに0であることを確認できました。

いずれにしても、まだまだ学びが足りませんね。ありがとうございました。