linux-firmwareがロードされず画面が黒くなる

Kernel-4.14以降は最新のfirmwareをインストールしなければ、ブート画面がブラックアウトするそうです。
で、emerge linux-firmwareするのですが、

The following license changes are necessary to proceed:
 (see "package.license" in the portage(5) man page for more details)
# required by =sys-kernel/linux-firmware-20200316 (argument)
=sys-kernel/linux-firmware-20200316 linux-fw-redistributable no-source-code

と、ライセンスを確認してないよ!って怒られます。
こんなの初めて。
では、licenseファイルを作りましょう。

# echo  sys-kernel/linux-firmware linux-fw-redistributable no-source-code >> /etc/portage/package.license

これでemerge linux-firmwareを実行しましょう。

# emerge linux-firmware
Calculating dependencies... done!

- sys-firmware/radeon-ucode-20160628::gentoo (masked by: radeon-ucode license(s))
For more information, see the MASKED PACKAGES section in the emerge
man page or refer to the Gentoo Handbook.


>>> Verifying ebuild manifests
>>> Running pre-merge checks for sys-kernel/linux-firmware-20200316
 * Your boot partition is not mounted at /boot.
 * Please mount it and retry.
 * ERROR: sys-kernel/linux-firmware-20200316::gentoo failed (pretend phase):
 *   /boot not mounted
 *
 * Call stack:
 *                        ebuild.sh, line 125:  Called pkg_pretend
 *   linux-firmware-20200316.ebuild, line  78:  Called mount-boot_pkg_pretend
 *                mount-boot.eclass, line  87:  Called mount-boot_check_status
 *                mount-boot.eclass, line  72:  Called die
 * The specific snippet of code:
 *              die "/boot not mounted"
 *
 * If you need support, post the output of `emerge --info '=sys-kernel/linux-firmware-20200316::gentoo'`,
 * the complete build log and the output of `emerge -pqv '=sys-kernel/linux-firmware-20200316::gentoo'`.
 * The complete build log is located at '/var/tmp/portage/sys-kernel/linux-firmware-20200316/temp/build.log'.
 * The ebuild environment file is located at '/var/tmp/portage/sys-kernel/linux-firmware-20200316/temp/die.env'.
 * Working directory: '/var/tmp/portage/sys-kernel/linux-firmware-20200316/homedir'
 * S: '/var/tmp/portage/sys-kernel/linux-firmware-20200316/work/linux-firmware-20200316'

ああ、そうですか、すみません。
mount /bootを実行してからemergeしなおしました。
めでたしめでたし。

Gerbera (旧mediatomb)のimport.js

mediatombを長年愛用してきましたが、後継のGerberaにようやく移行。
DLNAサーバーソフトなら、miniDLNAやらps3mediaserverやらがあるんでしょうが、mediatombを使い続けていたのは強力なインポート機能があるからでした。
で、防備録としてインポート機能のカスタマイズを記録。

javascriptを用いたインポート機能を利用するには、まず、config.xmlでvirtual-layout typeをデフォルトのbuilt-inからjsに変更しなければなりません。

<virtual-layout type="js">
    <import-script>/usr/share/gerbera/js/import.js</import-script>
</virtual-layout>

で、デフォルトでは/usr/share/gerbera/js/import.jsにあるファイルを編集します。なお、このファイル、Gerberaをアップデートインストールするたびに上書きインストールされるため、カスタマイズしたものをバックアップを取っておくか、別な場所にファイル指定しておくなどの対策が必要です。

さて、まずはアルバム内を表示したときに、曲名の先頭にトラック番号を付ける処理です。
こうすることで、DLNADMC側でABC順に再生する機器でも、曲名の先頭に01など数字から始まる曲名が着いていることで、曲順がアルバム内の順番通りに再生されます。
これは、import.js内にコメントアウトとコメント化する箇所が指定されています。

// uncomment this if you want to have track numbers in front of the title
// in album view


    var track = obj.meta[M_TRACKNUMBER];
    if (!track) {
        track = '';
    } else {
        if (track.length == 1) {
            track = '0' + track;
        }
        track = track + ' ';
    }

    // comment the following line out if you uncomment the stuff above  :)
//    var track = '';

これで、ArtistからAlbumを選択して再生した場合や、そのままAlbumを直接選択して再生した場合などは、曲名の先頭に01から始まるトラック番号が付与されました。

しかしです、mediatombやGerberaには、"All - full name"という、便利なカテゴリがあります。この配下には、"アーティスト名 アルバム名 曲名"という名前で曲名が表示されます。特定のアーティストの曲を前アルバム全て再生したい!と言うときなどに便利です。が、ここにトラック番号が入っていません。

そこで、"All - full name"配下の曲名にもトラック番号を表示するようにします。

    chain = ['Audio', 'All - full name'];
    var temp = '';
    if (artist_full) {
        temp = artist_full;
    }

    if (album_full) {
        temp = temp + ' - ' + album_full + ' - ';
    } else {
        temp = temp + ' - ';
    }

    obj.title = temp + track + title; //ここを変更
    addCdsObject(obj, createContainerChain(chain));

    chain = ['Audio', 'Artists', artist, 'All - full name'];
    addCdsObject(obj, createContainerChain(chain));

上記の13行目は元々は、obj.title = temp + title;となっており、tempには、その直前に指定しているとおり、artist_fullとalbum_fullが入っています。アルバム名と曲名の間にtrackを挟むことで、

「アーティスト名 アルバム名 トラック番号 曲名」

という表示になり、アルバムの曲順通りに再生できるようになります。

そして、このバーチャルレイアウト、困るのが指定したディレクトリ配下にある音楽を全てimport.jsの指定通りの箱に入れようとします。そうすると、今までCDリッピングしまくったシングル曲、DATからリッピングした懐かしのユーロビート、自分はあまり聞かない妻のロック、有象無象がすべて同じところに格納され、Artist名は膨大な数になってしまい、スクロールするのも大変になってしまいます。
そこで、大まかなところまではディレクトリ名を反映させることにします。

ウチのサーバーの場合、
/home/mp3/Album
/home/mp3/Single
/home/mp3/SuperEurobeat
/home/mp3/Wife
という、4つのフォルダに分けて格納されています。この第3階層をバーチャルレイアウトに表示させようと思います。

変数宣言の最初の方で、適当な変数にフォルダ名を"/"(スラッシュ)で分けて配列格納し、第三階層が格納されている第3配列のみを取り出し、変数u_pathに格納します。

function addAudio(obj) {

    var desc = obj.location; //インポートファイルのフルパスを変数descに格納
    var arr = desc.split('/'); //フルパスをスラッシュで分離しarrという配列に格納
    var u_path = arr[3]; //arr配列の3番目を変数u_pathに格納
    var desc = ''; //変数descをnullに
    var artist_full;
    var album_full;

これを、この後に出てくる実際のバーチャルレイアウトへの格納時に、u_pathの階層をを作ってあげます。

    var chain = ['Audio', u_path, 'All Audio'];
    obj.title = title;
    addCdsObject(obj, createContainerChain(chain));

    chain = ['Audio', u_path, 'Artists', artist, 'All Songs'];
    addCdsObject(obj, createContainerChain(chain));

    chain = ['Audio', u_path, 'All - full name'];
    var temp = '';
    if (artist_full) {
        temp = artist_full;
    }

    if (album_full) {
        temp = temp + ' - ' + album_full + ' - ';
    } else {
        temp = temp + ' - ';
    }

    obj.title = temp + track + title;
    addCdsObject(obj, createContainerChain(chain));

    chain = ['Audio', u_path, 'Artists', artist, 'All - full name'];
    addCdsObject(obj, createContainerChain(chain));

    chain = ['Audio', u_path, 'Artists', artist, album];
    obj.title = track + title;
    addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CONTAINER_MUSIC_ALBUM);

    chain = ['Audio', u_path, 'Albums', album];
    obj.title = track + title;
    addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CONTAINER_MUSIC_ALBUM);

    chain = ['Audio', u_path, 'Genres', genre];
    addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CONTAINER_MUSIC_GENRE);

    chain = ['Audio', u_path, 'Year', date];
    addCdsObject(obj, createContainerChain(chain));

    chain = ['Audio', u_path, 'Composers', composer];
    addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CONTAINER_MUSIC_COMPOSER);
}

これで、"Audio"を選択した後に、"Album" "Single" "SuperEurobeat" "Wife"の階層が現れ、それぞれの階層ではそのフォルダに保存されている音楽しか表示されないので、アーティスト名が多すぎて検索が大変!! ということがなくなります。(それでもSingleフォルダは大変な多さですが・・・。)

Gerberaをほぼ音楽サーバーとしか使っていないので、VideoやPhotosはいじっていません。
できれば、mp3配下に入っているアルバムアートなどのJPGを除外し、本当に表示したい写真だけを配信できるようにしたいところですが、「写真をテレビに表示して見る!」ということもないので、当面実施しないことでしょう。

gerbera-1.4.0のemergeエラー

今までDLNAサーバーとして長年mediatombを使ってきましたが、今となってはアップデートされず、先日のemerge -uDN @worldでライブラリとの整合性も合わなくなり、ついに起動すらしなくなりました。
で、mediatombの後継、Gerberaを使おうとしてハマったので、防備録。

GerberaそのものもStableになっておりませんし、Gerbera-1.4.0が要求するlibupnpのバージョンが1.8.6以上と言うことで、それもTest中。ついでにduktapeも。そこで、これら3つに~amd64のキーワードを与えます。

# cat /etc/portage/package.accept_keywords
=net-misc/gerbera-1.4.0 ~amd64
>=net-libs/libupnp-1.8.3 ~amd64
dev-lang/duktape ~amd64

v
で、emerge =net-misc/gerbera-1.4.0すると、libupnpが最新版のnet-libs/libupnp-1.12.0-r1がemergeされ、Gerberaのコンパイル時にこんなエラーが出ます。

In file included from /var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/server.h:38,
                 from /var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/main.cc:47:
/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/request_handler.h:41:26: エラー: ‘IN’ has not been d  eclared
   41 |     virtual void getInfo(IN const char *filename, OUT UpnpFileInfo *info) = 0;
      |                          ^~
/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/request_handler.h:41:41: エラー: two or more data type  s in declaration of ‘filename’
   41 |     virtual void getInfo(IN const char *filename, OUT UpnpFileInfo *info) = 0;
      |                                         ^~~~~~~~
/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/request_handler.h:41:49: エラー: expected ‘)’ before   ‘,’ token
   41 |     virtual void getInfo(IN const char *filename, OUT UpnpFileInfo *info) = 0;
      |                         ~                       ^
      |                                                 )
/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/request_handler.h:41:51: エラー: 変数またはフィールド   ‘OUT’ が void と宣言されています
   41 |     virtual void getInfo(IN const char *filename, OUT UpnpFileInfo *info) = 0;
      |                                                   ^~~
/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/request_handler.h:41:51: エラー: メンバ宣言の最後には   ‘;’ が予期されます
   41 |     virtual void getInfo(IN const char *filename, OUT UpnpFileInfo *info) = 0;
      |                                                   ^~~
      |                                                      ;
/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/request_handler.h:41:69: エラー: メンバ宣言の最後には   ‘;’ が予期されます
   41 |     virtual void getInfo(IN const char *filename, OUT UpnpFileInfo *info) = 0;
      |                                                                     ^~~~
      |                                                                         ;
/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/request_handler.h:41:73: エラー: expected unqualified-  id before ‘)’ token
   41 |     virtual void getInfo(IN const char *filename, OUT UpnpFileInfo *info) = 0;
      |                                                                         ^
/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/request_handler.h:43:38: エラー: ‘IN’ has not been d  eclared
   43 |     virtual zmm::Ref<IOHandler> open(IN const char* filename, IN enum UpnpOpenFileMode mode, IN zmm::String r  ange) = 0;
      |                                      ^~
/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/request_handler.h:43:53: エラー: two or more data type  s in declaration of ‘filename’
   43 |     virtual zmm::Ref<IOHandler> open(IN const char* filename, IN enum UpnpOpenFileMode mode, IN zmm::String r  ange) = 0;
      |                                                     ^~~~~~~~
/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/request_handler.h:43:61: エラー: expected ‘)’ before   ‘,’ token
   43 |     virtual zmm::Ref<IOHandler> open(IN const char* filename, IN enum UpnpOpenFileMode mode, IN zmm::String r  ange) = 0;
      |                                     ~                       ^
      |                                                             )
/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/request_handler.h:43:5: エラー: ‘IN’ declared as a    ‘virtual’ field
   43 |     virtual zmm::Ref<IOHandler> open(IN const char* filename, IN enum UpnpOpenFileMode mode, IN zmm::String r  ange) = 0;
      |     ^~~~~~~
/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/request_handler.h:43:63: エラー: メンバ宣言の最後には   ‘;’ が予期されます
   43 |     virtual zmm::Ref<IOHandler> open(IN const char* filename, IN enum UpnpOpenFileMode mode, IN zmm::String r  ange) = 0;
      |                                                               ^~
      |                                                                 ;
/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/request_handler.h:43:94: エラー: メンバ宣言の最後には   ‘;’ が予期されます
   43 |     virtual zmm::Ref<IOHandler> open(IN const char* filename, IN enum UpnpOpenFileMode mode, IN zmm::String r  ange) = 0;
      |                                                                                              ^~
      |                                                                                                ;
/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/request_handler.h:43:94: エラー: redeclaration of ‘Up  npOpenFileMode RequestHandler::IN’
/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/request_handler.h:43:63: 備考: previous declaration ‘  zmm::Ref<IOHandler> RequestHandler::IN’
   43 |     virtual zmm::Ref<IOHandler> open(IN const char* filename, IN enum UpnpOpenFileMode mode, IN zmm::String r  ange) = 0;
      |                                                               ^~
/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/request_handler.h:43:109: エラー: メンバ宣言の最後には   ‘;’ が予期されます
   43 |     virtual zmm::Ref<IOHandler> open(IN const char* filename, IN enum UpnpOpenFileMode mode, IN zmm::String r  ange) = 0;
      |                                                                                                             ^  ~~~~
      |                                                                                                                    ;
/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/request_handler.h:43:114: エラー: expected unqualified  -id before ‘)’ token
   43 |     virtual zmm::Ref<IOHandler> open(IN const char* filename, IN enum UpnpOpenFileMode mode, IN zmm::String r  ange) = 0;
      |                                                                                                                    ^
[7/116] /usr/bin/x86_64-pc-linux-gnu-g++ -DHAVE_AVSTREAM_CODECPAR -DHAVE_FFMPEG -DHAVE_INOTIFY -DHAVE_JS -DHAVE_LIBEX  IF -DHAVE_MAGIC -DHAVE_MATROSKA -DHAVE_MYSQL -DHAVE_NL_LANGINFO -DHAVE_SETLOCALE -DHAVE_SQLITE3 -DHAVE_TAGLIB -DPACKA  GE_DATADIR=\"/usr/share/gerbera\" -DPACKAGE_NAME=\"Gerbera\" -DUPNP_HAS_EXTRA_HEADERS_LIST -DUPNP_HAS_REQUEST_COOKIES   -DVERSION=\"1.4.0\" -D__FILENAME__=\"src/autoscan_inotify.cc\" -I/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerber  a-1.4.0/src -I/usr/include/upnp -I/usr/include/mysql -I/usr/include/ffmpeg -I/usr/include/libexif -I/usr/include/ebml   -I/usr/include/matroska  -DNDEBUG -march=btver2 -mtune=btver2 -O3 -pipe -fomit-frame-pointer -Wall   -std=c++17 -MD   -MT CMakeFiles/libgerbera.dir/src/autoscan_inotify.cc.o -MF CMakeFiles/libgerbera.dir/src/autoscan_inotify.cc.o.d -o   CMakeFiles/libgerbera.dir/src/autoscan_inotify.cc.o -c /var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src  /autoscan_inotify.cc
/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/autoscan_inotify.cc: コンストラクタ ‘AutoscanInotify:  :AutoscanInotify()’ 内:
/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0/src/autoscan_inotify.cc:53:17: 警告: unused variable ‘max  _watches’ [-Wunused-variable]
   53 |             int max_watches = trim_string(read_text_file(_(INOTIFY_MAX_USER_WATCHES_FILE))).toInt();
      |                 ^~~~~~~~~~~
ninja: build stopped: subcommand failed.
 * ERROR: net-misc/gerbera-1.4.0::gentoo failed (compile phase):
 *   ninja -v -j2 -l0 failed
 *
 * Call stack:
 *     ebuild.sh, line  125:  Called src_compile
 *   environment, line 2600:  Called cmake_src_compile
 *   environment, line  931:  Called cmake_build
 *   environment, line  910:  Called eninja
 *   environment, line 1369:  Called die
 * The specific snippet of code:
 *       "$@" || die "${nonfatal_args[@]}" "${*} failed"
 *
 * If you need support, post the output of `emerge --info '=net-misc/gerbera-1.4.0::gentoo'`,
 * the complete build log and the output of `emerge -pqv '=net-misc/gerbera-1.4.0::gentoo'`.
 * The complete build log is located at '/var/tmp/portage/net-misc/gerbera-1.4.0/temp/build.log'.
 * The ebuild environment file is located at '/var/tmp/portage/net-misc/gerbera-1.4.0/temp/environment'.
 * Working directory: '/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0_build'
 * S: '/var/tmp/portage/net-misc/gerbera-1.4.0/work/gerbera-1.4.0'

これは、libupnpの1.8.6を使うことでエラーが出ずにemerge出来ます。

# emerge -C =net-libs/libupnp-1.12.0-r1
# emerge =net-libs/libupnp--1.8.6-r1

これで強力なインポート機能を持つmediatombの後継、Gerberaを利用することが出来るようになりました!

emerge: there are no ebuilds to satisfy "dev-lang/ruby:2.3".

うどんワールド(emerge -uDN @world)を実行した後、依存関係の修復のために"emergeに@preserved-rebuild"を実行しますよね。そうすると、こんなエラーが

emerge: there are no ebuilds to satisfy "dev-lang/ruby:2.3".

gentooではもうruby 2.3系はサポートされてないので、そりゃebuildsはないですよ。
/etc/potage/make.confでRUBY_TAGETS="ruby24 ruby25"に指定してもダメ。
eselect ruby listを実行すると

Available Ruby profiles:
  [1]   ruby22
  [2]   ruby23
  [3]   ruby24 (with Rubygems)
  [4]   ruby25 (with Rubygems) *

プロファイルが残ってらっしゃる。

Gentoo Wikiではmake.confのRUBY_TAGETSを書き換えたらemerge -uDN @worldでOKと書いてありますが、全然OKではありません。

そこで、depcleanしてみます。

# emerge --depclean -pv dev-lang/ruby:2.3

Calculating dependencies... done!
  dev-lang/ruby-2.3.7 pulled in by:
    dev-ruby/did_you_mean-1.0.2 requires dev-lang/ruby:2.3

>>> No packages selected for removal by depclean
Packages installed:   690
Packages in world:    149
Packages in system:   43
Required packages:    690
Number to remove:     0

そうですか、did_you_meanですか。ではこれを先に削除します。

# emerge -C =dev-ruby/did_you_mean-1.0.2
 * This action can remove important packages! In order to be safer, use
 * `emerge -pv --depclean <atom>` to check for reverse dependencies before
 * removing packages.

 dev-ruby/did_you_mean
    selected: 1.0.2
   protected: none
     omitted: 1.1.2 1.2.1

All selected packages: =dev-ruby/did_you_mean-1.0.2

>>> 'Selected' packages are slated for removal.
>>> 'Protected' and 'omitted' packages will not be removed.

>>> Waiting 5 seconds before starting...
>>> (Control-C to abort)...
>>> Unmerging in: 5 4 3 2 1
>>> Unmerging (1 of 1) dev-ruby/did_you_mean-1.0.2...

 * GNU info directory index is up-to-date.

これで、ruby 2.3を削除できるんでしょうか?

# emerge --depclean dev-lang/ruby:2.3

Calculating dependencies... done!
>>> Calculating removal order...

 dev-lang/ruby
    selected: 2.3.7
   protected: none
     omitted: 2.2.10 2.4.9 2.5.7

All selected packages: =dev-lang/ruby-2.3.7

>>> 'Selected' packages are slated for removal.
>>> 'Protected' and 'omitted' packages will not be removed.

>>> Waiting 5 seconds before starting...
>>> (Control-C to abort)...
>>> Unmerging in: 5 4 3 2 1
>>> Unmerging (1 of 1) dev-lang/ruby-2.3.7...
>>> needed   sym /usr/lib64/libruby23.so.2.3
>>> needed   obj /usr/lib64/libruby23.so.2.3.0
Nothing to clean up.
Packages installed:   688
Packages in world:    149
Packages in system:   43
Required packages:    688
Number removed:       1

 * GNU info directory index is up-to-date.

お! 削除できました。

しかし、emerge: there are no ebuilds to satisfy が他のパッケージでも出てくること・・・。

Perl CGIからメールが送られなくなる。

以前、PQI AirFlash AirWiFiへ接続が成功したら、IPアドレスをメールで報告させる仕組みを構築していました。

gentoolinux.hatenablog.com

しかし、サーバーを再起動してからというもの、WiFiの接続は成功している(写真がGoogle Photosにアップロードされている)のに、メールが一向に届かないという現象が発生しました。

サーバーのプロセスを見ていると、

apache    20001   9636   0 0:0 ?        00:00:00 /home/www/xxx/mail.cgi
apache    20011  20001  0 0:0 ?        00:00:00 /usr/sbin/sendmail

というプロセスがずっと残っていました。
これはCGIが古くて、動作しなくなったのかと思い、いろいろとCGIを組み直しましたが、一向に直りません。

そこで、apaheのエラーログを見ることにしました。

tail -f /var/log/apache2/error_log
[Sun Oct 20 22:42:01.108468 2019] [cgi:error] [pid 9639:tid 140420415723264] [client 192.168.0.6:37054] AH01215: postdrop: warning: mail_queue_enter: create file maildrop/108046.28992: Permission denied: /home/www/xxx/test.cgi

なんだか、maildropにファイルが作成できないエラーが出ています。
MTAはpostfixなので、まずは設定をチェック。

postfix check
postfix: Postfix is running with backwards-compatible default settings
postfix: See http://www.postfix.org/COMPATIBILITY_README.html for details
postfix: To disable backwards compatibility use "postconf compatibility_level=2" and "postfix reload"
postfix/postfix-script: warning: not owned by group postdrop: /usr/sbin/postqueue
postfix/postfix-script: warning: not owned by group postdrop: /usr/sbin/postdrop
postfix/postfix-script: warning: not set-gid or not owner+group+world executable: /usr/sbin/postqueue
postfix/postfix-script: warning: not set-gid or not owner+group+world executable: /usr/sbin/postdrop

あ、mail.cfの設定を古いまま使っているのがバレていますね。
で、いくつかグループオーナーが間違っていたり、実行設定が間違っているようです。

ここにある対処法を参考に、各パーミッション等を変更します。
linux.m2osw.com

chgrp postdrop /var/spool/postfix/maildrop
chgrp postdrop /usr/sbin/postqueue
chmod g+s /usr/sbin/postqueue
chmod g+s /usr/sbin/postdrop
chmod 3730 /var/spool/postfix/maildrop
chmod 2730 /var/spool/postfix/public

こうすると、/var/spool/postfix配下のls -al結果は次のようになりました。

# ls -al /var/spool/postfix/
合計 64
drwxr-xr-x 16 root    root     4096  34  2019 .
drwxr-xr-x  5 root    root     4096  323  2015 ..
-rw-r--r--  1 root    root        0  34  2019 .keep_mail-mta_postfix-0
drwx------  2 postfix root     4096 1020 23:00 active
drwx------  2 postfix root     4096  720  2017 bounce
drwx------  2 postfix root     4096  711  2011 corrupt
drwx------ 15 postfix root     4096  42  2017 defer
drwx------ 18 postfix root     4096  229  2012 deferred
drwx------  2 postfix root     4096  711  2011 flush
drwx------  2 postfix root     4096  711  2011 hold
drwx------  2 postfix root     4096 1020 23:00 incoming
drwx-ws--T  2 postfix postdrop 4096 1020 23:00 maildrop
drwxr-xr-x  2 root    root     4096  67  2014 pid
drwx------  2 postfix root     4096 1019 04:26 private
drwx-ws---  2 postfix postdrop 4096 1019 04:26 public
drwx------  2 postfix root     4096  711  2011 saved
drwx------  2 postfix root     4096  711  2011 trace

今動いているmail.cgisendmailはkill -9で強制終了する必要がありますが、その後に動作させたmail.cgiは、しっかりと標準入力の内容をメール本文に送ってくれました。

ちなみに、新しいmail.cgiは、CPANのモジュールを使って動作させています。

#!/usr/bin/perl

use URI::Escape;
use Email::Sender::Simple qw(sendmail);
use Email::Simple;
use Email::Simple::Creator;

read (STDIN, $inputescaped, $ENV{'CONTENT_LENGTH'});
$input = uri_unescape($inputescaped);

$subject = 'PQIAirCard'; # メールの件名

$input =~ s/  //g; # 空白2文字分を削除

$email = Email::Simple->create(
  header => [
    To      => '<to_user@to_mail_host.com>',
    From    => '<from_user@from_host.com>',
    Subject => "$subject",
  ],
  body => "$input",
);

sendmail($email);

print "OK";
exit;

だいぶシンプルになりました。

Braava Jetの分解

Braava Jetのパッド認識センサーの調子が良くないので、パッドセンサーの内側を掃除しようとして分解しました。

が、先に言っておきます。

「パッドセンサーは分解できないので内側を拭くことは出来ません。」

分解方法だけ共有できればと思います。

では、バンパーの白いカバーを外します。
まずは裏返しにして4カ所のネジを外します。
このネジは奥深いところにあるので、先が細長いドライバーが必要です。
(途中でホームセンターに買いに走りました。)

f:id:naoyukinagano:20190929161922j:plain
裏から見て左上の2カ所のネジ。

f:id:naoyukinagano:20190929162027j:plain
裏から見て右上の2カ所のネジ。

そうすると、しろいバンパーは前方に引いて外せるようになります。

f:id:naoyukinagano:20190929162232j:plain

続いて、ボディの白いカバーを外すために6カ所のネジを外します。
引き続き裏返したまま、まずはパッド取り付け部分にある2カ所の穴に長いプラスドライバを差してネジを外します。

f:id:naoyukinagano:20190929162648j:plain

続いて、パッド取り付け部分とタイヤの間にあるネジを2カ所外します。

f:id:naoyukinagano:20190929162903j:plain

最後に、最後部にある黒いシールをめくり、ねじ穴からドライバーを差し込みます。
内部が広いので、なかなかねじ頭にドライバーが嵌まらないなぁ、と、思ったら、そこはバッテリー取り付け部でした。
なので、後ろから見ながらねじ頭にドライバーをはめていけばいいだけです。

f:id:naoyukinagano:20190929163549j:plain

これで、ひっくり返していたのを元に戻し、カバーを垂直に引き抜くことが出来ます。

f:id:naoyukinagano:20190929163835j:plain

で、パッド取り付け部分にアクセスしたいので、メイン基板部分を外すために、メイン基板にある2本のネジを外します。

f:id:naoyukinagano:20190929164051j:plain

ネジを外したら、メイン基板を前方に倒すように外しますが、そのときにパッドリリース用のバネが外れるので、なくさないように&元に戻すときにしっかりと取り付けるようにしましょう。

f:id:naoyukinagano:20190929164303j:plain

さて、ここから先、パッド取り付け部分とその上にあるバンパーセンサー部分は、ネジではなくゴムで取り付けられています。
このゴムを外していきます。
バンパーセンサーを留めているゴムの突起を、小さめのマイナスドライバを使って周りから押し込み、最後に上から押し込んで、ゴムを下に押し込んでバンパーを外します。

f:id:naoyukinagano:20190929164806j:plain

バンパーを固定するゴム4カ所を押し込んで外したら、センサーケーブルに気をつけながら、バンパーをそっと前方に外します。

f:id:naoyukinagano:20190929164932j:plain

ゴムはそのまま下のパッド取り付け部分とつながっているので、さらにゴムを下に押し込んでボディからゴムを外していきます。

f:id:naoyukinagano:20190929165111j:plain

4本のゴムを全て下に押し込むと、ゴムとともにパッド取り付け部分がボロっと下に外れます。
このとき、パッドセンサーとモーターのケーブルが張るので、断線に気をつけます。

f:id:naoyukinagano:20190929165638j:plain

パッド取り付け部分の裏は埃だらけで汚いですね。
で、パッドセンサーを固定している3つのネジを外します。

f:id:naoyukinagano:20190929165815j:plain

上の写真は、パッドセンサーの裏側ですが、樹脂で固めてられており、内側を拭くことは出来ないようです。

f:id:naoyukinagano:20190929165930j:plain

表から見ても特に分解できそうにありません。
この部品だけを取り寄せて交換したいのですが、ルンバ500シリーズのように部品単位で販売しているわけでもなさそうです。

あきらめて戻すことにしました。
部品取りのBraava jetを入手することにしましょう。

GmailをPOP3クライアントにしたいが、dovecotとletsencryptの組み合わせでエラーが起きる対処法

スマホによってはEメールクライアントがプリインされていないことがあるんですね。
知らなかったのですが、Gmailはそんなときに、POP3クライアントとして、メールを受信して、Gmailアプリ上に表示したり、ブラウザ上のGmailに表示することが出来るようです。

しかし、dovecot + letsencryptの組み合わせだと、うまく設定できないようです。
どうも、Gmailクライアント(といっても、Googleのサーバーですが)では、うまくSSL/TLSを解釈出来ないようです。

Gmailクライアントが返した詳細のエラーはこれ↓

SSL error: No path found from the leaf certificate to any root. Maybe an intermediate certificate is missing?

これを改善するには、証明書を中間証明書付きのファイルに指定しなおします。

dovecotの10-ssl.conを書き直します。
gentooの場合

ssl_cert = </etc/letsencrypt/live/hogegoge.co.jp/cert.pem

を、中間証明書つきのフルチェイン証明書

ssl_cert = </etc/letsencrypt/live/hogegoge.co.jp/fullchain.pem

に、書き換えます。
もちろん、hogehoge.co.jpは正しいドメインというか、正しいパスに書き換えます。

これで、Gmailクライアントにメールを読ませられますし、通常のメールクライアントも今まで通りに受信できます。