Repository: xe5700/kvmd-armbian
Branch: master
Commit: ca73920f6cc7
Files: 25
Total size: 93.5 KB
Directory structure:
gitextract_k6lnbzxp/
├── .gitignore
├── LICENSE
├── README-zh-CN.MD
├── README.MD
├── amglogic-dtb-mod.py
├── armbian/
│ ├── armbian-motd
│ ├── opt/
│ │ ├── armbian-sysinfo
│ │ └── vcgencmd
│ └── udev/
│ └── rules.d/
│ └── 99-kvmd.rules
├── bin/
│ └── kvmd-helper-otgmsd-unlock
├── config.sh
├── dtb/
│ └── 4.4/
│ └── rk322x-box.dtb
├── install-mirror.sh
├── install.sh
├── libs/
│ ├── checksum.sh
│ ├── download_aria2.sh
│ └── download_wget.sh
└── patches/
├── custom/
│ └── old-kernel-msd/
│ ├── apply.sh
│ ├── v3.124-v3.142/
│ │ └── 0001-Apply-old-kernel-msd-patch-for-v3.134.patch
│ └── v3.84-v3.92/
│ ├── 0001-Revert-force-eject-feature-to-unlock-helper.patch
│ └── 0003-Allow-skip-some-features-unsupports-on-old-linux-ker.patch
├── disable_gpio/
│ ├── v3.47-v3.81/
│ │ └── 0001-Disable-GPIO-For-TV-Box.patch
│ ├── v3.82-v3.83/
│ │ └── 0001-Disable-GPIO-For-TV-Box.patch
│ └── v3.84-v3.134/
│ └── 0001-Disable-GPIO-For-TV-Box.patch
└── genernal/
└── v3.84-v3.92/
└── 0001-Allow-skip-some-features-unsupports-on-old-linux-ker.patch
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
workspace.code-workspace
tmp
.vscode
================================================
FILE: LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
================================================
FILE: README-zh-CN.MD
================================================
# 感谢由toss-a编写的中文教程
该教程未验证,可能需要使用 https://github.com/toss-a/pikvm-armbian 该分叉才能运行。
你可以尝试其他的项目基于pikvm
分支版本 kvmd-armbian https://github.com/srepac/kvmd-armbian
onekvm 项目 https://github.com/mofeng-git/One-KVM
# 硬件准备
## 开发版选择
建议选择能刷比较新的armbian的开发版作为PI-KVM
##### 1.选择原生带有OTG的开发版 例如:
- Orange Pi Prime(貌似已停产)
- Orange Pi Zero(需要制作一分二数据线 性能比较差 适合低成本1080P 30FPS方案)
- Orange Pi Zero LTS(和Orange Pi Zero一样)
- 等其他 未列举完
##### 2.选择非原生支持修改dtb来实现OTG功能的开发版 例如:
- King 3399 (1个USB3.0 和一个Type-c 3.0做为OTG 能够满足1080P 60FPS方案)
- phicomm n1 (理论可以 把刷机那USB作为OTG 未做测试 不建议购买 性价比并不高)
- 等其他 未列举完
## 视频采集设备选择 HDMI转USB
- 如果你的开发版只有USB 2.0 建议选择ms2109 而且价格便宜 tb 30 RMB左右的即可
- 如果你的开发版有USB 3.0 建议选择ms2130 淘宝偏贵点 可输出1080P 60FPS
- 以上设备我都已测试可以用 但是 部分主板可能使用这两款视频采集设备都会导致进BIOS颜色输出有问题(又不是不能用)
- 其他的视频采集设备也可以 你可以试试???
## OTG数据线准备
- 开发版OTG口为单独的Type-C口或Micro USB 那么 你只需要准备一根数据线即可
- 开发版OTG口为开发版供电 你需要手动制作一分二数据线 如下图

- 开发版OTG口为USB 修改dtb后实现的 你需要准备USB-A 转 USB-A 线缆
建议切断 USB 线的电源线,它可能会导致 OTG 断开连接。
#### 第一步
- 刷入 armbian 用于您的开发版或电视盒(如果内核不支持 otg,您应该构建一个启用 otg 功能的内核)
- 如果你的开发版或者电视机或者支持从SD卡启动或者U盘启动 那么你需要把armbian写入到可移动存储介质上,写入完成后将一部分空闲分区划分为10G左右的空间格式化为EXT4 作为PI KVM 镜像储存分区(可选 非必须)
#### 第二步
- 修改您的 dtb 文件以启用 otg 功能。对于 otg USB 端口,将 dr_mode 从host更改为peripheral。
- 修改方法(Linux 推荐 Ubuntu)
- sudo apt install device-tree-compiler
- dtc 你开发版dtb -I dtb -O dts -o 输出的名称.dts
- 修改 将dr_mode = "host" 修改为dr_mode = "peripheral"
- dtc 刚刚修改的dts.dts -I dts -O dtb -o 你开发版.dtb
- 替换,然后重启你的开发版
#### 第三步
- ```
git clone https://github.com/toss-a/pikvm-armbian.git
cd pikvm-armbian
./install.sh
```
- 我们内核比较新 不需要 所以按n
- 重启
#### 第四步
- 重启后再次运行刚刚运行的./install.sh
- 安装完成!!!
#### 启用大容量存储设备
需要格式化为EXT4
- 1.开发版或电视盒从U盘或者SD卡启动 使用内置emmc做为PI KVM 镜像存储
- 2.在armbian启动之前划分了PI KVM 镜像存储分区
- 3.再插入一个SD卡或U盘格式化为EXT4做为PI KVM 镜像存储
- 修改挂载点
- ```
vim /etc/fstab
```
- 添加(/dev/sda1需要修改为你的存储介质dev路径)
- ```
/dev/sda1 /var/lib/kvmd/msd ext4 nodev,nosuid,noexec,ro,errors=remount-ro,data=journal,X-kvmd.otgmsd-root=/var/lib/kvmd/msd,X-kvmd.otgmsd-user=kvmd 0 0
```
- ```
vim /etc/kvmd/override.yaml
```
- 删除以下两行
- ```
msd:
type:disable
```
- 重启
#### 修复重启后视频采集设备无法采集到视频
- 1.以root用户登陆后克隆
- ```
git clone https://github.com/jkulesza/usbreset
```
- 2.打开克隆的目录
- ```
cd usbreset
```
- 3.将源码编译成可执行文件(如果报错请安装gcc)
- ```
cc usbreset.c -o usbreset
```
- 4.赋予可执行权限
- ```
chmod +x usbreset
```
- 4.获取需要重置的视频采集设备的总线和设备 ID
- ```
lsusb
```
- 我的输出内容为输出:
- ```
root@king3399:~# lsusb
Bus 002 Device 002: ID 345f:2130 UltraSemi USB3 Video
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 003: ID 0c45:768a Microdia USB DEVICE
Bus 003 Device 002: ID 05e3:0608 Genesys Logic, Inc. Hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 006 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
root@king3399:~#
```
- 5.尝试重启你的视频采集设备(我的设备为UltraSemi USB3 Video 对应为002/002)
- ```
./usbreset /dev/bus/usb/002/002
```
- 6.成功重启USB设备后添加到开机自启动
- ```
vim /etc/rc.local
```
- 添加内容
- ```
sleep 5
/root/usbreset /dev/bus/usb/002/002
```
- 7.重启开发版再次查看
#### 更改PI KVM 登陆密码
- ```
kvmd-htpasswd set admin
```
- 输入你需要的密码即可
#### 感谢,如果没有他们我不可能做到
- [kvmd-armbian](https://github.com/xe5700/kvmd-armbian)
- [peacokswiss](https://github.com/xe5700/kvmd-armbian/issues/12)
- [armkvm](https://github.com/wxjiyc/amlogic-s9xxx-armbian/blob/main/rebuild#L629)
- [usbreset](https://github.com/jkulesza/usbreset)
================================================
FILE: README.MD
================================================
# KVMD-ARMBIAN
This project support non Raspberry Pi device to running pikvm on armbian
You can try other project based on pikvm
fork version of kvmd-armbian https://github.com/srepac/kvmd-armbian
onekvm project https://github.com/mofeng-git/One-KVM
# Chinese installation steps
Chinese installation steps by toss-a [https://github.com/xe5700/pikvm-armbian/blob/master/README-zh-CN.MD]
# Install
KVMD Install for armbian
It support Allwinner, Amlogic and Rockchip based tv box, tested on phicomm n1, mxq pro 4k, tqc a01.
Chipset needs support USB OTG feature, lots of old amglogic chipset not support otg feature, such as s805 and s905.
You should install armbian with debian buster or bullseye.
Then running this script to install pikvm.
Install scripts is fork from @srepac rasbian pikvm install script.
Original Script [https://kvmnerds.com/RPiKVM/install-pikvm-raspbian.sh]
# Hardware for kvmd-armbian project
* A tv box/arm board supports otg feature:
- Tests on phicomm n1(Amlogic s905d), mxq pro 4k (rk322x), tqc a01(Allwinner H6).
- If you are use arm board you can remove gpio patch to enable gpio feature.
* Video capture device:
- HDMI to USB dongle (30 RMB On taobao, 10$ on aliexpress.)
cheap hdmi to usb dongle all use physics USB2.0 port, but fake USB3.0(USB 5GBPS, USB3.2GEN1) version supports 720P 60FPS,
usb 2.0 version only supports 720P 30FPS.
* USB-A to USB-A cable:
- Recommended cut off usb cable's power line, it might causes otg disconnect.
## Step 1
- Flash armbian debian [Recommended bullseye] for your tv box (If kernel not support otg you should build a kernel enable otg features)
## Step 2
- Modify your dtb file to enable otg feature. Change dr_mode from host to peripheral for otg usb port.
- If you use rk322x (rk3228A rk3228B rk3229) series chipset, you can use dtb/4.4/rk332x-box.dtb
## Step 3
```
git clone https://github.com/xe5700/kvmd-armbian.git
cd kvmd-armbian
./install.sh
```
(If very slow, you can use install-mirror.sh to boost install speed.)
## Step 4
- running install.sh or install-mirror.sh after reboot os then running again.
- Enjoy
# Tested device
- Phicomm N1
- TQC A01 (Ethernet port not working, only support wireless.)
- RK322x based tvbox (MXQ, V88)
- S905L2 based tvbox
- Orange pi zero (tested by @MrSuicideParrot)
# Update log
## Version 1.0
## Version 2.0
Now support download hook, config file, diffrent version of kvmd, and fix lots of bug.
## Version 2.1
Fix #8 #7 #15, allow custom apt manager tools.
================================================
FILE: amglogic-dtb-mod.py
================================================
================================================
FILE: armbian/armbian-motd
================================================
#!/bin/sh
/etc/update-motd.d/10-armbian-header
/etc/update-motd.d/30-armbian-sysinfo
/etc/update-motd.d/41-armbian-config
================================================
FILE: armbian/opt/armbian-sysinfo
================================================
#!/bin/bash
#
# Copyright (c) Authors: http://www.armbian.com/authors
#
# This file is licensed under the terms of the GNU General Public
# License version 2. This program is licensed "as is" without any
# warranty of any kind, whether express or implied.
#
# DO NOT EDIT THIS FILE but add config options to /etc/default/armbian-motd
# generate system information
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
THIS_SCRIPT="sysinfo"
MOTD_DISABLE=""
STORAGE=/dev/sda1
SHOW_IP_PATTERN="^bond.*|^[ewr].*|^br.*|^lt.*|^umts.*|^lan.*"
CPU_TEMP_LIMIT=60
HDD_TEMP_LIMIT=60
AMB_TEMP_LIMIT=40
[[ -f /etc/default/armbian-motd ]] && . /etc/default/armbian-motd
for f in $MOTD_DISABLE; do
[[ $f == $THIS_SCRIPT ]] && exit 0
done
# don't edit below here
function display() {
# $1=name $2=value $3=red_limit $4=minimal_show_limit $5=unit $6=after $7=acs/desc{
# battery red color is opposite, lower number
if [[ "$1" == "Battery" ]]; then local great="<"; else local great=">"; fi
if [[ -n "$2" && "$2" > "0" && (( "${2%.*}" -ge "$4" )) ]]; then
printf "%-14s%s" "$1:"
if awk "BEGIN{exit ! ($2 $great $3)}"; then echo -ne "\e[0;91m $2"; else echo -ne "\e[0;92m $2"; fi
printf "%-1s%s\x1B[0m" "$5"
printf "%-11s%s\t" "$6"
return 1
fi
} # display
function getboardtemp() {
if [ -f /etc/armbianmonitor/datasources/soctemp ]; then
read raw_temp </etc/armbianmonitor/datasources/soctemp 2>/dev/null
if [ ! -z $(echo "$raw_temp" | grep -o "^[1-9][0-9]*\.\?[0-9]*$") ] && (( $(echo "${raw_temp} < 200" |bc -l) )); then
# Allwinner legacy kernels output degree C
board_temp=${raw_temp}
else
board_temp=$(awk '{printf("%d",$1/1000)}' <<<${raw_temp})
fi
elif [ -f /etc/armbianmonitor/datasources/pmictemp ]; then
# fallback to PMIC temperature
board_temp=$(awk '{printf("%d",$1/1000)}' </etc/armbianmonitor/datasources/pmictemp)
fi
} # getboardtemp
function batteryinfo() {
# Battery info for Allwinner
mainline_dir="/sys/power/axp_pmu"
legacy_dir="/sys/class/power_supply"
if [[ -e "$mainline_dir" ]]; then
read status_battery_connected < $mainline_dir/battery/connected 2>/dev/null
if [[ "$status_battery_connected" == "1" ]]; then
read status_battery_charging < $mainline_dir/charger/charging
read status_ac_connect < $mainline_dir/ac/connected
read battery_percent< $mainline_dir/battery/capacity
# dispay charging / percentage
if [[ "$status_ac_connect" == "1" && "$battery_percent" -lt "100" ]]; then
status_battery_text=" charging"
elif [[ "$status_ac_connect" == "1" && "$battery_percent" -eq "100" ]]; then
status_battery_text=" charged"
else
status_battery_text=" discharging"
fi
fi
elif [[ -e "$legacy_dir/axp813-ac" ]]; then
read status_battery_connected < $legacy_dir/axp20x-battery/present
if [[ "$status_battery_connected" == "1" ]]; then
status_battery_text=" "$(awk '{print tolower($0)}' < $legacy_dir/axp20x-battery/status)
read status_ac_connect < $legacy_dir/axp813-ac/present
read battery_percent< $legacy_dir/axp20x-battery/capacity
fi
elif [[ -e "$legacy_dir/battery" ]]; then
if [[ (("$(cat $legacy_dir/battery/voltage_now)" -gt "5" )) ]]; then
status_battery_text=" "$(awk '{print tolower($0)}' < $legacy_dir/battery/status)
read battery_percent <$legacy_dir/battery/capacity
fi
fi
} # batteryinfo
function ambienttemp() {
# define where w1 usually shows up
W1_DIR="/sys/devices/w1_bus_master1/"
if [ -f /etc/armbianmonitor/datasources/ambienttemp ]; then
read raw_temp </etc/armbianmonitor/datasources/ambienttemp 2>/dev/null
amb_temp=$(awk '{printf("%d",$1/1000)}' <<<${raw_temp})
echo $amb_temp
elif [[ -d $W1_DIR && $ONE_WIRE == yes ]]; then
device=$(ls -1 $W1_DIR | grep -Eo '^[0-9]{1,4}' | head -1)
if [[ -n $device ]]; then
if [[ -d ${W1_DIR}${device}/hwmon/hwmon0 ]]; then hwmon=0; else hwmon=1; fi
read raw_temp < ${W1_DIR}${device}/hwmon/hwmon${hwmon}/temp1_input 2>/dev/null
amb_temp=$(awk '{printf("%d",$1/1000)}' <<<${raw_temp})
echo $amb_temp
fi
else
# read ambient temperature from USB device if available
if [[ ! -f /usr/bin/temper ]]; then
echo ""
return
fi
amb_temp=$(temper -c 2>/dev/null)
case ${amb_temp} in
*"find the USB device"*)
echo ""
;;
*)
amb_temp=$(awk '{print $NF}' <<<$amb_temp | sed 's/C//g')
echo -n "scale=1;${amb_temp}/1" | grep -oE "\-?[[:digit:]]+\.[[:digit:]]"
esac
fi
} # ambienttemp
function get_ip_addresses() {
local ips=()
for f in /sys/class/net/*; do
local intf=$(basename $f)
# match only interface names starting with e (Ethernet), br (bridge), w (wireless), r (some Ralink drivers use ra<number> format)
if [[ $intf =~ $SHOW_IP_PATTERN ]]; then
local tmp=$(ip -4 addr show dev $intf | awk '/inet/ {print $2}' | cut -d'/' -f1)
# add both name and IP - can be informative but becomes ugly with long persistent/predictable device names
#[[ -n $tmp ]] && ips+=("$intf: $tmp")
# add IP only
[[ -n $tmp ]] && ips+=("$tmp")
fi
done
echo "${ips[@]}"
} # get_ip_addresses
function storage_info() {
# storage info
RootInfo=$(df -h /)
root_usage=$(awk '/\// {print $(NF-1)}' <<<${RootInfo} | sed 's/%//g')
root_total=$(awk '/\// {print $(NF-4)}' <<<${RootInfo})
StorageInfo=$(df -h $STORAGE 2>/dev/null | grep $STORAGE)
if [[ -n "${StorageInfo}" && ${RootInfo} != *$STORAGE* ]]; then
storage_usage=$(awk '/\// {print $(NF-1)}' <<<${StorageInfo} | sed 's/%//g')
storage_total=$(awk '/\// {print $(NF-4)}' <<<${StorageInfo})
if [[ -n "$(command -v smartctl)" ]]; then
DISK="${STORAGE::-1}"
storage_temp+=$(sudo smartctl -A $DISK 2> /dev/null | grep -i temperature | awk '{print $(NF-2)}')
fi
fi
} # storage_info
# query various systems and send some stuff to the background for overall faster execution.
# Works only with ambienttemp and batteryinfo since A20 is slow enough :)
amb_temp=$(ambienttemp &)
ip_address=$(get_ip_addresses &)
batteryinfo
storage_info
getboardtemp
critical_load=80
# get uptime, logged in users and load in one take
UPTIME=$(LC_ALL=C uptime)
UPT1=${UPTIME#*'up '}
UPT2=${UPT1%'user'*}
users=${UPT2//*','}
users=${users//' '}
time=${UPT2%','*}
time=${time//','}
time=$(echo $time | xargs)
load=${UPTIME#*'load average: '}
load=${load//','}
load=$(echo $load | cut -d" " -f1)
[[ $load == 0.0* ]] && load=0.10
cpucount=$(grep -c processor /proc/cpuinfo)
load=$(awk '{printf("%.0f",($1/$2) * 100)}' <<< "$load $cpucount")
# memory and swap
mem_info=$(LC_ALL=C free -w 2>/dev/null | grep "^Mem" || LC_ALL=C free | grep "^Mem")
memory_usage=$(awk '{printf("%.0f",(($2-($4+$6+$7))/$2) * 100)}' <<<${mem_info})
mem_info=$(echo $mem_info | awk '{print $2}')
memory_total=$(( mem_info / 1024 ))
swap_info=$(LC_ALL=C free -m | grep "^Swap")
swap_usage=$( (awk '/Swap/ { printf("%3.0f", $3/$2*100) }' <<<${swap_info} 2>/dev/null || echo 0) | tr -c -d '[:digit:]')
swap_total=$(awk '{print $(2)}' <<<${swap_info})
if [[ ${memory_total} -gt 1000 ]]; then
memory_total=$(awk '{printf("%.2f",$1/1024)}' <<<${memory_total})"G"
else
memory_total+="M"
fi
if [[ ${swap_total} -gt 500 ]]; then
swap_total=$(awk '{printf("%.2f",$1/1024)}' <<<${swap_total})"G"
else
swap_total+="M"
fi
================================================
FILE: armbian/opt/vcgencmd
================================================
#!/bin/bash
cd `dirname $0`
source armbian-sysinfo
case $1 in
get_throttled) echo "throttled=0x0";;
measure_temp) echo "temp=$board_temp'C";;
get_config)
case $2 in
total_mem)
KB=$( grep 'Memory:' /var/log/dmesg* | awk '{print $5}' | cut -d'/' -f2 | sed 's/K//g' | head -1 )
MB=$( echo $KB / 1024 | bc )
echo "total_mem=$MB";;
*)
echo "invalid option";;
esac
;;
esac
================================================
FILE: armbian/udev/rules.d/99-kvmd.rules
================================================
# https://unix.stackexchange.com/questions/66901/how-to-bind-usb-device-under-a-static-name
# https://wiki.archlinux.org/index.php/Udev#Setting_static_device_names
KERNEL=="video[1-9]*", SUBSYSTEM=="video4linux", PROGRAM="/usr/bin/kvmd-udev-hdmiusb-check rpi4 1-1.4:1.0", ATTR{index}=="0", GROUP="kvmd", SYMLINK+="kvmd-video"
KERNEL=="hidg0", GROUP="kvmd", SYMLINK+="kvmd-hid-keyboard"
KERNEL=="hidg1", GROUP="kvmd", SYMLINK+="kvmd-hid-mouse"
KERNEL=="hidg2", GROUP="kvmd", SYMLINK+="kvmd-hid-mouse-alt"
================================================
FILE: bin/kvmd-helper-otgmsd-unlock
================================================
#!/usr/sbin/python
# KVMD-ARMBIAN
from kvmd.helpers.unlock import main
if __name__ == "__main__":
main()
================================================
FILE: config.sh
================================================
export APT_EXE="apt-get" #If you installed apt-fast can change it to apt-fast to boost install speed.
export GIT_EXE="git"
export MIRROR_GITHUB="https://github.com" # Use a github mirror to boost download speed in some place has no github cdn
export MIRROR_GITHUB_API="https://api.github.com"
export PIKVMREPO="https://files.pikvm.org/repos/arch/rpi4"
export PIKVMREPO_PKG="/"
#export PIKVMREPO=""
#export KVMD_VERSION="3.47" # LEGECY KVMD VERSION SUPPORTS MSD AND RUNNING ON DEBIAN BULLSEYE OR BUSTER WITHOUT PATCH
# export KVMD_VERSION=""
export KVMD_COMMON_PKG_URL="$MIRROR_GITHUB/xe5700/kvmd-armbian-repo/raw/master/kvmd-common.tar.xz"
export CUSTOM_KVMD_VERSION=1 # If you want install lastest version of kvmd set to 0
export KVMD_VERSION="3.142" # LAST KVMD VERSION SUPPORTS PYTHON3.9
export PIKVM_KEY="912C773ABBD1B584"
export USE_GPIO=0
export DEBIAN_PYTHON=1
export KVMDCACHE="/var/cache/kvmd"
export PKGINFO="${KVMDCACHE}/packages.txt"
export DOWNLOAD_FUNC="./libs/download_wget.sh" # can change to ./lib/download_aria2.sh to boost download speed.
export GIT_CLONE_WITH_DEPTH="--depth=1"
export USE_JANUS=0
export USE_CSI=0
#export HID_MODE="" # Allow otg, ch9329, arduino, bluetooth mode
export USE_MSD=0
export USE_UDEV=0
#export PLATFORM_PATCH # Apply patch for board platform
================================================
FILE: install-mirror.sh
================================================
# Github 增强加速脚本
# 加速地址参考github 增强加速下载脚本
# Created by xe5700
# @namespace https://greasyfork.org/scripts/412245
# @supportURL https://github.com/XIU2/UserScript
# @homepageURL https://github.com/XIU2/UserScript
url_clone="";
url_raw="";
url_raw2="";
clone_mirror(){
printf "Choose github clone mirror\n
0. github.com [Orginal]
1. hub.fastgit.org [China Hong Kong] \n
2. gitclone.com [China Zhe Jiang] \n
3. github.com.cnpmjs.org [Singapore]\n
4. kgithub.com \n
5. hub.njuu.cf \n
6. hub.yzuu.cf \n
"
tryagain=1
while [ $tryagain -eq 1 ]; do
read -p "Please type [0-3]: " capture
case $capture in
0) url_clone="https:\\/\\/github.com\\/"; tryagain=0;;
1) url_clone="https:\\/\\/hub.fastgit.org\\/"; tryagain=0;;
2) url_clone="https:\\/\\/gitclone.com\\/github.com\\/"; tryagain=0;;
3) url_clone="https:\\/\\/github.com.cnpmjs.org\\/"; tryagain=0;;
4) url_clone="https:\\/\\/kgithub.com\\/"; tryagin=0;;
5) url_clone="https:\\/\\/hub.njuu.cf\\/"; tryagin=0;;
6) url_clone="https:\\/\\/hub.yzuu.cf\\/"; tryagin=0;;
*) printf "\nTry again.\n"; tryagain=1;;
esac
echo
echo "Github clone URL -> $url_clone"
echo
done
}
raw_mirror(){
printf "Choose github raw mirror\n
0. https://raw.githubusercontent.com [Orginal]
1. https://raw.fastgit.org [China Hong Kong]
2. https://cdn.staticaly.com [Global]
3. https://ghproxy.com [South Korea]
"
#1. https://cdn.jsdelivr.net [Global]
tryagain=1
while [ $tryagain -eq 1 ]; do
read -p "Please type [0-3]: " capture
case $capture in
0) url_raw="https:\\/\\/raw.githubusercontent.com\\/";url_raw2="https://raw.githubusercontent.com/"; tryagain=0;;
1) url_raw="https:\\/\\/raw.fastgit.org\\/";url_raw2="https://raw.fastgit.org/"; tryagain=0;;
2) url_raw="https:\\/\\/cdn.staticaly.com\\/gh\\/";url_raw2="https://cdn.staticaly.com/gh/"; tryagain=0;;
3) url_raw="https:\\/\\/ghproxy.com\\/https:\\/\\/raw.githubusercontent.com\\/";url_raw2="https://ghproxy.com/https://raw.githubusercontent.com/"; tryagain=0;;
*) printf "\nTry again.\n"; tryagain=1;;
esac
echo
echo "Github raw URL -> $url_raw"
echo
done
}
clone_mirror
raw_mirror
appPath=$(dirname $0)
cd $appPath
cat install.sh | sed "s/https:\\/\\/raw.githubusercontent.com\\//$url_raw/" | sed "s/https:\\/\\/github.com\\//$url_clone/" | tee .tmp.kvmd-install.sh > /dev/null
chmod +x .tmp.kvmd-install.sh
./.tmp.kvmd-install.sh
rm -f .tmp.kvmd-install.sh
================================================
FILE: install.sh
================================================
#!/bin/bash
# modified by xe5700 2021-11-04 xe5700@outlook.com
# modified by NewbieOrange 2021-11-04
# created by @srepac 08/09/2021 srepac@kvmnerds.com
# Scripted Installer of Pi-KVM on Raspbian (32-bit) meant for RPi4
#
# *** MSD is disabled by default ***
#
# Mass Storage Device requires the use of a USB thumbdrive or SSD and will need to be added in /etc/fstab
: '
# SAMPLE /etc/fstab entry for USB drive with only one partition formatted as ext4 for the entire drive:
/dev/sda1 /var/lib/kvmd/msd ext4 nodev,nosuid,noexec,ro,errors=remount-ro,data=journal,X-kvmd.otgmsd-root=/var/lib/kvmd/msd,X-kvmd.otgmsd-user=kvmd 0 0
'
# NOTE: This was tested on a new install of raspbian desktop and lite versions, but should also work on an existing install.
#
# Last change 20210818 1830 PDT
# VER=1.0
source config.sh
source $DOWNLOAD_FUNC
set +x
APP_PATH=$(readlink -f $(dirname $0))
export KVMD_BV=`echo $KVMD_VERSION | awk '{print substr($1,1,1)}'`
export KVMD_SV=`echo $KVMD_VERSION | awk '{print substr($1,3)}'`
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
echo "usage: $0 [-f] where -f will force re-install new pikvm platform"
exit 1
fi
WHOAMI=$( whoami )
if [ "$WHOAMI" != "root" ]; then
echo "$WHOAMI, please run script as root."
exit 1
fi
press-enter() {
echo
read -p "Press ENTER to continue or CTRL+C to break out of script."
} # end press-enter
gen-ssl-certs() {
cd /etc/kvmd/nginx/ssl
openssl ecparam -out server.key -name prime256v1 -genkey
openssl req -new -x509 -sha256 -nodes -key server.key -out server.crt -days 3650 \
-subj "/C=US/ST=Denial/L=Denial/O=Pi-KVM/OU=Pi-KVM/CN=$(hostname)"
cp server* /etc/kvmd/vnc/ssl/
cd ${APP_PATH}
} # end gen-ssl-certs
create-override() {
if [ $( grep ^kvmd: /etc/kvmd/override.yaml | wc -l ) -eq 0 ]; then
if [[ $( echo $platform | grep usb | wc -l ) -eq 1 ]]; then
cat <<USBOVERRIDE >> /etc/kvmd/override.yaml
kvmd:
hid:
mouse_alt:
device: /dev/kvmd-hid-mouse-alt # allow absolute/relative mouse mode
msd:
type: disabled
atx:
type: disabled
streamer:
forever: true
cmd_append:
- "--slowdown" # for usb dongle (so target doesn't have to reboot)
resolution:
default: 1280x720
USBOVERRIDE
else
cat <<CSIOVERRIDE >> /etc/kvmd/override.yaml
kvmd:
hid:
mouse_alt:
device: /dev/kvmd-hid-mouse-alt
msd:
type: disabled
streamer:
forever: true
CSIOVERRIDE
fi
fi
} # end create-override
install-python-packages() {
pkgs=""
for i in $( echo "aiofiles appdirs asn1crypto async-timeout bottle cffi chardet click
colorama cryptography dateutil dbus dev hidapi idna libgpiod marshmallow more-itertools multidict netifaces
packaging passlib pillow ply psutil pycparser pyelftools pyghmi pygments pyparsing requests semantic-version
setproctitle setuptools six spidev systemd tabulate urllib3 wrapt xlib yaml yarl" )
do
pkgs="$pkgs python3-$i"
done
echo "-> Install python packages"
$APT_EXE install $pkgs -y > /dev/null
# U
pip3 install dbus_next==0.2.3 zstandard==0.18.0 pyserial==3.5 aiohttp==3.8.3
} # end install python-packages
otg-devices() {
modprobe libcomposite
if [ ! -e /sys/kernel/config/usb_gadget/kvmd ]; then
mkdir -p /sys/kernel/config/usb_gadget/kvmd/functions
cd /sys/kernel/config/usb_gadget/kvmd/functions
mkdir hid.usb0 hid.usb1 hid.usb2 mass_storage.usb0
fi
cd ${APP_PATH}
} # end otg-device creation
install-tc358743() {
### CSI Support for Raspbian ###
wget -O- -q https://www.linux-projects.org/listing/uv4l_repo/lpkey.asc | apt-key add -
echo "deb https://www.linux-projects.org/listing/uv4l_repo/raspbian/stretch stretch main" | tee /etc/apt/sources.list.d/uv4l.list
apt-get update > /dev/null
echo "$APT_EXE install uv4l-tc358743-extras -y"
$APT_EXE install uv4l-tc358743-extras -y > /dev/null
} # install package for tc358743
boot-files() {
if [[ $( grep srepac /boot/config.txt | wc -l ) -eq 0 ]]; then
if [[ $( echo $platform | grep usb | wc -l ) -eq 1 ]]; then
# Armbian does not support config.txt, remove it.
# amlogic does not support CSI, skip the following
# add the tc358743 module to be loaded at boot for CSI
# if [[ $( grep -w tc358743 /etc/modules | wc -l ) -eq 0 ]]; then
# echo "tc358743" >> /etc/modules
# fi
# install-tc358743
:
fi
fi # end of check if entries are already in /boot/config.txt
# Remove OTG serial (Orange pi zero's kernel not support it)
sed -i '/^g_serial/d' /etc/modules
# /etc/modules required entries for DWC2, HID and I2C
if [[ $( grep -w dwc2 /etc/modules | wc -l ) -eq 0 ]]; then
echo "dwc2" >> /etc/modules
fi
if [[ $( grep -w libcomposite /etc/modules | wc -l ) -eq 0 ]]; then
echo "libcomposite" >> /etc/modules
fi
if [[ $( grep -w i2c-dev /etc/modules | wc -l ) -eq 0 ]]; then
echo "i2c-dev" >> /etc/modules
fi
# printf "\n/boot/config.txt\n\n"
# cat /boot/config.txt
printf "\n/etc/modules\n\n"
cat /etc/modules
} # end of necessary boot files
get-packages() {
printf "\n\n-> Getting Pi-KVM packages from ${PIKVMREPO}\n\n"
mkdir -p "${KVMDCACHE}"
#echo "wget ${PIKVMREPO} -O ${PKGINFO}"
rm -f "${PKGINFO}"
download "${PIKVMREPO}${PIKVMREPO_PKG}" "${PKGINFO}"
echo "import Pi-Kvm Repo Key"
gpg --keyserver keyserver.ubuntu.com --recv-keys $PIKVM_KEY
gpg -a --export $PIKVM_KEY | apt-key add -
# Download each of the pertinent packages for Rpi4, webterm, and the main service
PIKVM_PKGS_CMD="egrep 'janus|kvmd' \"${PKGINFO}\" | grep -v sig | cut -d'>' -f1 | cut -d'\"' -f2 | egrep -v 'fan|oled' | egrep 'janus|pi4|webterm|kvmd-[0-9]'"
if [ $CUSTOM_KVMD_VERSION -eq 1 ]; then
PIKVM_PKGS_CMD="$PIKVM_PKGS_CMD | egrep -v 'kvmd-[0-9]'"
fi
PIKVM_PKGS=`$PIKVM_PKGS_CMD`
for pkg in $PIKVM_PKGS
do
rm -f "${KVMDCACHE}/$pkg.sig"
download "${PIKVMREPO}/$pkg.sig" "${KVMDCACHE}/$pkg.sig"
download "${PIKVMREPO}/$pkg ${KVMDCACHE}/$pkg gpg ${KVMDCACHE}/$pkg.sig"
done
echo
echo "ls -l ${KVMDCACHE}"
ls -l "${KVMDCACHE}"
echo
} # end get-packages function
get-platform() {
# tryagain=1
# while [ $tryagain -eq 1 ]; do
# # amglogic tv box only has usb port, use usb dongle.
# # printf "Choose which capture device you will use:\n\n 1 - USB dongle\n 2 - v2 CSI\n 3 - V3 HAT\n"
# # read -p "Please type [1-3]: " capture
# capture=1;
# done
case $USE_CSI in
0) platform="kvmd-platform-v2-hdmiusb-rpi4"; tryagain=0;;
# 2) platform="kvmd-platform-v2-hdmi-rpi4"; tryagain=0;;
1) platform="kvmd-platform-v3-hdmi-rpi4"; tryagain=0;;
*) printf "\nTry again.\n"; tryagain=1;;
esac
echo
echo "Platform selected -> $platform"
echo
} # end get-platform
install-kvmd-pkgs() {
cd /
INSTLOG="${KVMDCACHE}/installed_ver.txt"; rm -f "$INSTLOG"
date > $INSTLOG
# # uncompress platform package first
# for i in $( ls "${KVMDCACHE}/${platform}-*.tar.xz" )
# do
# echo "-> Extracting package $i into /" >> "$INSTLOG"
# tar -vxf "$i"
# done
# then uncompress, kvmd-{version}, kvmd-webterm, and janus packages
for i in $PIKVM_PKGS
do
echo "-> Extracting package $i into /" >> "$INSTLOG"
tar -vxf $i
done
if [ $CUSTOM_KVMD_VERSION -eq 1 ]; then
# Use custom kvmd version replace kvmd offical package
download "${KVMD_COMMON_PKG_URL}" "${KVMDCACHE}/kvmd-common.tar.gz"
echo "-> Extracting common kvmd package into /" >> "$INSTLOG"
tar -vxf "${KVMDCACHE}/kvmd-common.tar.gz"
echo "-> Install custom version kvmd" >> "$INSTLOG"
$APT_EXE install python3-setuptools -y
download "${MIRROR_GITHUB}/pikvm/kvmd/archive/refs/tags/v$KVMD_VERSION.tar.gz" "${KVMDCACHE}/kvmd.tar.gz"
mkdir -p "${KVMDCACHE}/kvmd-tmp"
tar axf "${KVMDCACHE}/kvmd.tar.gz" -C "${KVMDCACHE}/kvmd-tmp"
cd "${KVMDCACHE}/kvmd-tmp/kvmd-$KVMD_VERSION/"
./setup.py install
cd "$APP_PATH"
rm -rf "${KVMDCACHE}/kvmd-tmp"
fi
cd "${APP_PATH}"
cp bin/* /usr/bin/
} # end install-kvmd-pkgs
fix-udevrules() {
# for hdmiusb, replace %b with 1-1.4:1.0 in /etc/udev/rules.d/99-kvmd.rules
sed -i -e 's+\%b+1-1.4:1.0+g' /etc/udev/rules.d/99-kvmd.rules
echo
cat /etc/udev/rules.d/99-kvmd.rules
} # end fix-udevrules
enable-kvmd-svcs() {
# enable KVMD services but don't start them
echo "-> Enabling kvmd-nginx kvmd-webterm kvmd-otg and kvmd services, but do not start them."
systemctl enable kvmd-nginx kvmd-webterm kvmd-otg kvmd
# in case going from CSI to USB, then disable kvmd-tc358743 service (in case it's enabled)
if [[ $USE_CSI -eq 0 ]]; then
systemctl disable --now kvmd-tc358743
else
systemctl enable kvmd-tc358743
fi
} # end enable-kvmd-svcs
build-ustreamer() {
printf "\n\n-> Building ustreamer\n\n"
# Install packages needed for building ustreamer source
echo "$APT_EXE install -y libevent-dev libjpeg-dev libbsd-dev libgpiod-dev libsystemd-dev janus-dev janus"
$APT_EXE install -y libevent-dev libjpeg-dev libbsd-dev libsystemd-dev
if [[ $USE_GPIO -eq 1 ]]; then
$APT_EXE install -y libgpiod-dev
fi
if [[ $USE_JANUS -eq 1 ]]; then
$APT_EXE install -y janus-dev janus
fi
# Download ustreamer source and build it
cd /tmp
$GIT_EXE clone $GIT_CLONE_WITH_DEPTH "$MIRROR_GITHUB/pikvm/ustreamer"
cd ustreamer/
# if [[ $( uname -m ) == "aarch64" ]]; then
# make WITH_OMX=0 WITH_GPIO=1 WITH_SETPROCTITLE=1 # ustreamer doesn't support 64-bit hardware OMX
# else
# make WITH_OMX=1 WITH_GPIO=1 WITH_SETPROCTITLE=1 # hardware OMX support with 32-bit ONLY
# fi
make WITH_GPIO=$USE_GPIO WITH_SYSTEMD=1 WITH_JANUS=$USE_JANUS -j
make install
# kvmd service is looking for /usr/bin/ustreamer
ln -s /usr/local/bin/ustreamer /usr/bin/
} # end build-ustreamer
install-dependencies() {
echo
echo "-> Installing dependencies for pikvm"
apt-get update > /dev/null
# for i in $( echo "" )
# do
# echo "$APT_EXE install -y $i"
# $APT_EXE install -y $i > /dev/null
# done
echo "-> Install basic packages"
$APT_EXE install -y nginx python3 bc expect v4l-utils gpiod dialog git python3-pip tesseract-ocr tesseract-ocr-chi-sim jq
install-python-packages
echo "-> Make tesseract data link"
ln -s /usr/share/tesseract-ocr/*/tessdata /usr/share/tessdata
echo "-> Install TTYD"
$APT_EXE install -y ttyd
if [ ! -e /usr/bin/ttyd ]; then
echo "-> Download from apt failed, try download offical lastest version binary file."
# Build and install ttyd
# cd /tmp
# $APT_EXE install -y build-essential cmake git libjson-c-dev libwebsockets-dev
# git clone --depth=1 https://github.com/tsl0922/ttyd.git
# cd ttyd && mkdir build && cd build
# cmake ..
# make -j && make install
# Install binary from GitHub
arch=$(dpkg --print-architecture)
latest=$(wget -q -O- $MIRROR_GITHUB_API/repos/tsl0922/ttyd/releases/latest | jq -r ".tag_name")
if [ $arch = arm64 ]; then
arch='aarch64'
fi
if [ $arch = amd64 ]; then
arch='x86_64'
fi
wget "$MIRROR_GITHUB/tsl0922/ttyd/releases/download/$latest/ttyd.$arch" -O /usr/bin/ttyd
chmod +x /usr/bin/ttyd
fi
echo "-> Install ustreamer"
if [ ! -e /usr/bin/ustreamer ]; then
# apt install ustreamer
cd /tmp/
$APT_EXE install -y libevent-2.1-7 libevent-core-2.1-7 libevent-pthreads-2.1-7 build-essential
# ### required dependent packages for ustreamer ###
build-ustreamer
cd ${APP_PATH}
fi
} # end install-dependencies
python-pkg-dir() {
# debian system python3 no alias
# create quick python script to show where python packages need to go
cat << MYSCRIPT > /tmp/syspath.py
#!$(which python3)
import sys
print (sys.path)
MYSCRIPT
chmod +x /tmp/syspath.py
export PYTHONDIR_SYS=$( /tmp/syspath.py | grep packages | sed -e 's/, /\n/g' -e 's/\[//g' -e 's/\]//g' -e "s+'++g" | tail -1 )
export PYTHONDIR_PIP=$( python3 -c "import site; print(site.getsitepackages()[0])" )
} # end python-pkg-dir
fix-nginx-symlinks() {
# disable default nginx service since we will use kvmd-nginx instead
echo
echo "-> Disabling nginx service, so that we can use kvmd-nginx instead"
systemctl disable --now nginx
# setup symlinks
echo
echo "-> Creating symlinks for use with kvmd python scripts"
if [ ! -e /usr/bin/nginx ]; then ln -s /usr/sbin/nginx /usr/bin/; fi
if [ ! -e /usr/sbin/python ]; then ln -s /usr/bin/python3 /usr/sbin/python; fi
if [ ! -e /usr/bin/iptables ]; then ln -s /usr/sbin/iptables /usr/bin/iptables; fi
# if [ ! -e /opt/vc/bin/vcgencmd ]; then mkdir -p /opt/vc/bin/; ln -s /usr/bin/vcgencmd /opt/vc/bin/vcgencmd; fi
python-pkg-dir
if [ ! -e $PYTHONDIR_PIP/kvmd ]; then
# Debian python版本比 pikvm官方的低一些
ln -s /usr/lib/python3.10/site-packages/kvmd* ${PYTHONDIR_PIP}
fi
} # end fix-nginx-symlinks
fix-python-symlinks(){
python-pkg-dir
if [ ! -e $PYTHONDIR_PIP/kvmd ]; then
# Debian python版本比 pikvm官方的低一些
ln -s /usr/lib/python3.10/site-packages/kvmd* ${PYTHONDIR_PIP}
fi
}
apply-custom-patch(){
read -p "Do you want apply old kernel msd patch? [y/n]" answer
case $answer in
n|N|no|No)
echo 'You skiped this patch.'
;;
y|Y|Yes|yes)
./patches/custom/old-kernel-msd/apply.sh
;;
*)
echo "Try again.";;
esac
}
fix-kvmd-for-tvbox-armbian(){
# 打补丁来移除一些对armbian和电视盒子不太支持的特性
python-pkg-dir
if [[ "$CUSTOM_KVMD_VERSION" -eq 1 ]]; then
cd "$PYTHONDIR_PIP/kvmd-$KVMD_VERSION-py${PYTHON_VERSION}.egg"
else
cd $PYTHONDIR_PIP
fi
# if [[ "$DEBIAN_PYTHON" -eq 1 ]]; then
# if [ `$KVMD_VERSION < 3.134` -eq ]; then
# PATCH_VER="v3.90"
# fi
# if [ `$KVMD_VERSION \>= 3.134` -eq 1 ]; then
# PATCH_VER="v3.134"
# fi
# if [ ! -z "$PATCH_VER" ]; then
# $GIT_EXE apply ${APP_PATH}/patches/debian_python/$PATCH_VER/*.patch
# fi
# fi
if [[ "$USE_GPIO" -eq 0 ]] && [[ "$KVMD_BV" -eq "3" ]] ; then
PATCH_VER=""
if [ `expr $KVMD_SV \<= 81` -eq 1 ]; then
PATCH_VER="v3.47-v3.81"
fi
if [ `expr $KVMD_SV \>= 82` -eq 1 ] && [ `expr $KVMD_SV \<= 83` -eq 1 ]; then
PATCH_VER="v3.82-v3.83"
fi
if [ `expr $KVMD_SV \>= 84` -eq 1 ] && [ `expr $KVMD_SV \<= 134` -eq 1 ]; then
PATCH_VER="v3.84-v3.134"
fi
if [ ! -z "$PATCH_VER" ]; then
sh -c "$GIT_EXE apply '${APP_PATH}/patches/disable_gpio/$PATCH_VER/*.patch'"
fi
fi
if [ `expr $KVMD_SV \>= 84` -eq 1 ] && [ `expr $KVMD_SV \<= 92` -eq 1 ]; then
PATCH_VER="v3.84-v3.92"
sh -c "$GIT_EXE apply '${APP_PATH}/patches/genernal/$PATCH_VER/*.patch'"
fi
cd ${APP_PATH}
read -p "Do you want to apply custom patches? [y/n] " answer
case $answer in
n|N|no|No)
return;
;;
y|Y|Yes|yes)
apply-custom-patch;
return;
;;
*)
echo "Try again.";;
esac
}
fix-webterm() {
echo
echo "-> Creating kvmd-webterm homedir"
mkdir -p /home/kvmd-webterm
chown kvmd-webterm /home/kvmd-webterm
ls -ld /home/kvmd-webterm
} # end fix-webterm
create-kvmdfix() {
# Create kvmd-fix service and script
cat <<ENDSERVICE > /lib/systemd/system/kvmd-fix.service
[Unit]
Description=KVMD Fixes
After=network.target network-online.target nss-lookup.target
Before=kvmd.service
[Service]
User=root
Type=simple
ExecStart=/usr/bin/kvmd-fix
[Install]
WantedBy=multi-user.target
ENDSERVICE
cat <<SCRIPTEND > /usr/bin/kvmd-fix
#!/bin/bash
# Written by @srepac
# 1. Properly set group ownership of /dev/gpio*
# 2. fix /dev/kvmd-video symlink to point to /dev/video1 (Amglogic Device video0 is not usb device)
#
### These fixes are required in order for kvmd service to start properly
#
set -x
chgrp gpio /dev/gpio*
chmod 660 /dev/gpio* ### this is required in case gpio (wiringpi) is installed
ls -l /dev/gpio*
ls -l /dev/kvmd-video
rm /dev/kvmd-video
# Need to use video0 for orange pi (if you don't, the video capture won't work)
ln -s video1 /dev/kvmd-video
SCRIPTEND
chmod +x /usr/bin/kvmd-fix
} # end create-kvmdfix
set-ownership() {
# set proper ownership of password files and kvmd-webterm homedir
cd /etc/kvmd
chown kvmd:kvmd htpasswd
chown kvmd-ipmi:kvmd-ipmi ipmipasswd
chown kvmd-vnc:kvmd-vnc vncpasswd
chown kvmd-webterm /home/kvmd-webterm
# add kvmd user to video group (this is required in order to use CSI bridge with OMX and h264 support)
usermod -a -G video kvmd
} # end set-ownership
check-kvmd-works() {
# check to make sure kvmd -m works before continuing
invalid=1
while [ $invalid -eq 1 ]; do
kvmd -m
read -p "Did kvmd -m run properly? [y/n] " answer
case $answer in
n|N|no|No)
echo "Please install missing packages as per the kvmd -m output in another ssh/terminal."
;;
y|Y|Yes|yes)
invalid=0
;;
*)
echo "Try again.";;
esac
done
} # end check-kvmd-works
start-kvmd-svcs() {
#### start the main KVM services in order ####
# 1. nginx is the webserver
# 2. kvmd-otg is for OTG devices (keyboard/mouse, etc..)
# 3. kvmd is the main daemon
systemctl restart kvmd-nginx kvmd-otg kvmd-webterm kvmd
# systemctl status kvmd-nginx kvmd-otg kvmd-webterm kvmd
} # end start-kvmd-svcs
fix-motd() {
rm /etc/motd
cp armbian/armbian-motd /usr/bin/
sed -i 's/cat \/etc\/motd/armbian-motd/g' /lib/systemd/system/kvmd-webterm.service
systemctl daemon-reload
# systemctl restart kvmd-webterm
} # end fix-motd
# 安装armbian的包
armbian-packages() {
mkdir -p /opt/vc/bin/
#cd /opt/vc/bin
# Install vcgencmd for armbian platform
cp -rf armbian/opt/* /opt/vc/bin
#cp -rf armbian/udev /etc/
cd ${APP_PATH}
#
} #end armbian-packages
$APT_EXE update
$APT_EXE -y install python3 xz-utils tar wget aria2 curl
### MAIN STARTS HERE ###
# Install is done in two parts
# First part requires a reboot in order to create kvmd users and groups
# Second part will start the necessary kvmd services
# added option to re-install by adding -f parameter (for use as platform switcher)
export PYTHON_VERSION=$( python3 -V | awk '{print $2}' | cut -d'.' -f1,2 )
if [[ $( grep kvmd /etc/passwd | wc -l ) -eq 0 || "$1" == "-f" ]]; then
printf "\nRunning part 1 of PiKVM installer script for Raspbian by @srepac\n"
get-packages
get-platform
boot-files
install-kvmd-pkgs
create-override
gen-ssl-certs
fix-udevrules
install-dependencies
otg-devices
armbian-packages
systemctl disable --now janus
fix-kvmd-for-tvbox-armbian
# Fix paste-as-keys if running python 3.7
if [[ $( python3 -V | awk '{print $2}' | cut -d'.' -f1,2 ) == "3.7" ]]; then
sed -i -e 's/reversed//g' $PYTHONDIR/kvmd/keyboard/printer.py
fi
sync
echo "-> Synced data, you can reboot system safety."
printf "\n\nReboot is required to create kvmd users and groups.\nPlease re-run this script after reboot to complete the install.\n"
# Ask user to press CTRL+C before reboot or ENTER to proceed with reboot
press-enter
reboot
else
printf "\nRunning part 2 of PiKVM installer script for Raspbian by @srepac\n"
fix-nginx-symlinks
fix-python-symlinks
fix-webterm
fix-motd
set-ownership
create-kvmdfix
check-kvmd-works
enable-kvmd-svcs
start-kvmd-svcs
sync
printf "\nCheck kvmd devices\n\n"
ls -l /dev/kvmd*
printf "\nYou should see devices for keyboard, mouse, and video.\n"
printf "\nPoint a browser to https://$(hostname)\nIf it doesn't work, then reboot one last time.\nPlease make sure kvmd services are running after reboot.\n"
fi
================================================
FILE: libs/checksum.sh
================================================
checksum(){
export sumRet=0
case $1 in
gpg) checksum_gpg $2 $3;;
esac
}
checksum_gpg(){
gpg --verify $2 $1 2> /dev/null
case $? in
1) export sumRet=0;echo bad signature, skip checksum.;;
*) export sumRet=$?;;
esac
return;
}
================================================
FILE: libs/download_aria2.sh
================================================
#!/bin/bash
source libs/checksum.sh
download(){
tryCount=0
echo Downloading $1 To $2
download2 $1 $2 $3 $4
unset tryCount
}
download2() {
filename=$(readlink -f $2)
echo "aria2c -x 16 -s 16 --file-allocation=falloc --min-split-size 2M $1 -o $filename -d /"
if [ ! -f "$2" ]; then
aria2c -x 16 -s 16 --file-allocation=falloc --min-split-size 2M $1 -o $filename -d /
else
if [ ! -n "$3" ]; then
echo "File $2 is exists, skip download."
return
fi
fi
echo "Checksum for $2"
checksum $3 $2 $4
if [ "$sumRet" != 0 ]; then
echo "File checksum failed, try redownload file. Result is $sumRet"
if [[ "$tryCount" -lt 3 ]]; then
tryCount=`expr $tryCount + 1`
rm $2
download2 $1 $2 $3 $4
else
echo "Try $tryCount times, download failed."
fi
else
echo "File checksum successful."
fi
unset sumRet
}
================================================
FILE: libs/download_wget.sh
================================================
#!/bin/bash
source libs/checksum.sh
download(){
tryCount=0
echo Downloading $1 To $2
download2 $1 $2 $3 $4
unset tryCount
}
download2() {
if [ ! -f "$2" ]; then
echo "wget $1 -O $2"
wget $1 -O $2
else
if [ ! -n "$3" ]; then
echo "File $2 is exists, skip download."
return
fi
fi
echo "Checksum for $2"
checksum $3 $2 $4
if [ "$sumRet" != 0 ]; then
echo "File checksum failed, try redownload file. Result is $sumRet"
if [[ "$tryCount" -lt 3 ]]; then
tryCount=`expr $tryCount + 1`
rm $2
download2 $1 $2 $3 $4
else
echo "Try $tryCount times, download failed."
fi
else
echo "File checksum successful."
fi
unset sumRet
}
================================================
FILE: patches/custom/old-kernel-msd/apply.sh
================================================
#!/bin/bash
# PYTHON_VERSION=$( python3 -V | awk '{print $2}' | cut -d'.' -f1,2 )
APP_PATH=$(readlink -f $(dirname $0))
echo "-> Apply patches"
if [[ "$CUSTOM_KVMD_VERSION" -eq 1 ]]; then
cd $PYTHONDIR_PIP/kvmd-$KVMD_VERSION-py${PYTHON_VERSION}.egg/
else
cd $PYTHONDIR_PIP
fi
PATCH_VER=""
if [ `expr $KVMD_SV \>= 84` -eq 1 ] && [ `expr $KVMD_SV \<= 92` -eq 1 ]; then
PATCH_VER="v3.84-v3.134"
fi
if [ `expr $KVMD_SV \>= 124` -eq 1 ] && [ `expr $KVMD_SV \<= 142` -eq 1 ]; then
PATCH_VER="v3.124-v3.142"
fi
git apply ${APP_PATH}/${PATCH_VER}/*.patch
cd ${APP_PATH}
# echo "-> Add otgmsd unlock link"
# cp kvmd-helper-otgmsd-unlock /usr/bin/
echo "-> Add sudoer"
echo "kvmd ALL=(ALL) NOPASSWD: /usr/bin/kvmd-helper-otgmsd-unlock" >> /etc/sudoers.d/99_kvmd
echo "-> Apply old kernel msd patch done."
================================================
FILE: patches/custom/old-kernel-msd/v3.124-v3.142/0001-Apply-old-kernel-msd-patch-for-v3.134.patch
================================================
From 18723b4c8e13a5cd0049982cfbbf61b4409ba159 Mon Sep 17 00:00:00 2001
From: xe5700 <9338143+xe5700@users.noreply.github.com>
Date: Mon, 15 Aug 2022 19:31:45 +0800
Subject: [PATCH] Apply old kernel msd patch for v3.134
---
kvmd/aiohelpers.py | 31 ++++++++++++-----
kvmd/apps/otg/__init__.py | 3 +-
kvmd/apps/otgmsd/__init__.py | 25 +++++++++++++-
kvmd/helpers/unlock/__init__.py | 58 ++++++++++++++++++++++++++++++++
kvmd/helpers/unlock/__main__.py | 24 +++++++++++++
kvmd/plugins/msd/otg/__init__.py | 20 +++++++----
kvmd/plugins/msd/otg/drive.py | 5 +--
7 files changed, 145 insertions(+), 21 deletions(-)
create mode 100644 kvmd/helpers/unlock/__init__.py
create mode 100644 kvmd/helpers/unlock/__main__.py
diff --git a/kvmd/aiohelpers.py b/kvmd/aiohelpers.py
index ae943d23..e0e27fd3 100644
--- a/kvmd/aiohelpers.py
+++ b/kvmd/aiohelpers.py
@@ -40,11 +40,26 @@ async def remount(name: str, base_cmd: List[str], rw: bool) -> bool:
]
logger.info("Remounting %s storage to %s: %s ...", name, mode.upper(), tools.cmdfmt(cmd))
try:
- proc = await aioproc.log_process(cmd, logger)
- if proc.returncode != 0:
- assert proc.returncode is not None
- raise subprocess.CalledProcessError(proc.returncode, cmd)
- except Exception as err:
- logger.error("Can't remount %s storage: %s", name, tools.efmt(err))
- return False
- return True
+ await _run_helper(cmd)
+ except Exception:
+ logger.error("Can't remount internal storage")
+ raise
+
+
+async def unlock_drive(base_cmd: List[str]) -> None:
+ logger = get_logger(0)
+ logger.info("Unlocking the drive ...")
+ try:
+ await _run_helper(base_cmd)
+ except Exception:
+ logger.error("Can't unlock the drive")
+ raise
+
+
+# =====
+async def _run_helper(cmd: List[str]) -> None:
+ logger = get_logger(0)
+ logger.info("Executing helper %s ...", cmd)
+ proc = await aioproc.log_process(cmd, logger)
+ if proc.returncode != 0:
+ logger.error(f"Error while helper execution: pid={proc.pid}; retcode={proc.returncode}")
diff --git a/kvmd/apps/otg/__init__.py b/kvmd/apps/otg/__init__.py
index 9b6f5e69..af6327b2 100644
--- a/kvmd/apps/otg/__init__.py
+++ b/kvmd/apps/otg/__init__.py
@@ -186,7 +186,6 @@ class _GadgetConfig:
_chown(join(func_path, "lun.0/cdrom"), user)
_chown(join(func_path, "lun.0/ro"), user)
_chown(join(func_path, "lun.0/file"), user)
- _chown(join(func_path, "lun.0/forced_eject"), user)
_symlink(func_path, join(self.__profile_path, func))
name = ("Mass Storage Drive" if self.__msd_instance == 0 else f"Extra Drive #{self.__msd_instance}")
self.__create_meta(func, name)
@@ -295,7 +294,7 @@ def _cmd_stop(config: Section) -> None:
logger.info("Disabling gadget %r ...", config.otg.gadget)
_write(join(gadget_path, "UDC"), "\n")
- _unlink(join(gadget_path, "os_desc", usb.G_PROFILE_NAME), optional=True)
+ _unlink(join(gadget_path, "os_desc", usb.G_PROFILE_NAME), True)
profile_path = join(gadget_path, usb.G_PROFILE)
for func in os.listdir(profile_path):
diff --git a/kvmd/apps/otgmsd/__init__.py b/kvmd/apps/otgmsd/__init__.py
index 0d32331b..26db4c8e 100644
--- a/kvmd/apps/otgmsd/__init__.py
+++ b/kvmd/apps/otgmsd/__init__.py
@@ -21,12 +21,15 @@
import os
+import signal
import errno
import argparse
from typing import List
from typing import Optional
+import psutil
+
from ...validators.basic import valid_bool
from ...validators.basic import valid_int_f0
from ...validators.os import valid_abs_file
@@ -56,6 +59,21 @@ def _set_param(gadget: str, instance: int, param: str, value: str) -> None:
raise
+def _unlock() -> None:
+ # https://github.com/torvalds/linux/blob/3039fad/drivers/usb/gadget/function/f_mass_storage.c#L2924
+ found = False
+ for proc in psutil.process_iter():
+ attrs = proc.as_dict(attrs=["name", "exe", "pid"])
+ if attrs.get("name") == "file-storage" and not attrs.get("exe"):
+ try:
+ proc.send_signal(signal.SIGUSR1)
+ found = True
+ except Exception as err:
+ raise SystemExit(f"Can't send SIGUSR1 to MSD kernel thread with pid={attrs['pid']}: {err}")
+ if not found:
+ raise SystemExit("Can't find MSD kernel thread")
+
+
# =====
def main(argv: Optional[List[str]]=None) -> None:
(parent_parser, argv, config) = init(
@@ -71,6 +89,8 @@ def main(argv: Optional[List[str]]=None) -> None:
)
parser.add_argument("-i", "--instance", default=0, type=valid_int_f0,
metavar="<N>", help="Drive instance (0 for KVMD drive)")
+ parser.add_argument("--unlock", action="store_true",
+ help="Send SIGUSR1 to MSD kernel thread")
parser.add_argument("--set-cdrom", default=None, type=valid_bool,
metavar="<1|0|yes|no>", help="Set CD-ROM flag")
parser.add_argument("--set-rw", default=None, type=valid_bool,
@@ -90,8 +110,11 @@ def main(argv: Optional[List[str]]=None) -> None:
set_param = (lambda param, value: _set_param(config.otg.gadget, options.instance, param, value))
get_param = (lambda param: _get_param(config.otg.gadget, options.instance, param))
+ if options.unlock:
+ _unlock()
+
if options.eject:
- set_param("forced_eject", "")
+ set_param("file", "")
if options.set_cdrom is not None:
set_param("cdrom", str(int(options.set_cdrom)))
diff --git a/kvmd/helpers/unlock/__init__.py b/kvmd/helpers/unlock/__init__.py
new file mode 100644
index 00000000..140e0e7c
--- /dev/null
+++ b/kvmd/helpers/unlock/__init__.py
@@ -0,0 +1,58 @@
+# ========================================================================== #
+# #
+# KVMD - The main PiKVM daemon. #
+# #
+# Copyright (C) 2018-2022 Maxim Devaev <mdevaev@gmail.com> #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <https://www.gnu.org/licenses/>. #
+# #
+# ========================================================================== #
+
+
+import sys
+import signal
+
+import psutil
+
+
+# =====
+_PROCESS_NAME = "file-storage"
+
+
+# =====
+def _log(msg: str) -> None:
+ print(msg, file=sys.stderr)
+
+
+def _unlock() -> None:
+ # https://github.com/torvalds/linux/blob/3039fad/drivers/usb/gadget/function/f_mass_storage.c#L2924
+ found = False
+ for proc in psutil.process_iter():
+ attrs = proc.as_dict(attrs=["name", "exe", "pid"])
+ if attrs.get("name") == _PROCESS_NAME and not attrs.get("exe"):
+ _log(f"Sending SIGUSR1 to MSD {_PROCESS_NAME!r} kernel thread with pid={attrs['pid']} ...")
+ try:
+ proc.send_signal(signal.SIGUSR1)
+ found = True
+ except Exception as err:
+ raise SystemExit(f"Can't send SIGUSR1 to MSD kernel thread with pid={attrs['pid']}: {err}")
+ if not found:
+ raise SystemExit(f"Can't find MSD kernel thread {_PROCESS_NAME!r}")
+
+
+# =====
+def main() -> None:
+ if len(sys.argv) != 2 or sys.argv[1] != "unlock":
+ raise SystemExit(f"Usage: {sys.argv[0]} [unlock]")
+ _unlock()
diff --git a/kvmd/helpers/unlock/__main__.py b/kvmd/helpers/unlock/__main__.py
new file mode 100644
index 00000000..3849d1b9
--- /dev/null
+++ b/kvmd/helpers/unlock/__main__.py
@@ -0,0 +1,24 @@
+# ========================================================================== #
+# #
+# KVMD - The main PiKVM daemon. #
+# #
+# Copyright (C) 2018-2022 Maxim Devaev <mdevaev@gmail.com> #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <https://www.gnu.org/licenses/>. #
+# #
+# ========================================================================== #
+
+
+from . import main
+main()
diff --git a/kvmd/plugins/msd/otg/__init__.py b/kvmd/plugins/msd/otg/__init__.py
index 5a8b86a6..d4de24b8 100644
--- a/kvmd/plugins/msd/otg/__init__.py
+++ b/kvmd/plugins/msd/otg/__init__.py
@@ -144,6 +144,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
storage_path: str,
remount_cmd: List[str],
+ unlock_cmd: List[str],
initial: Dict,
@@ -159,6 +160,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
self.__meta_path = os.path.join(self.__storage_path, "meta")
self.__remount_cmd = remount_cmd
+ self.__unlock_cmd = unlock_cmd
self.__initial_image: str = initial["image"]
self.__initial_cdrom: bool = initial["cdrom"]
@@ -184,10 +186,8 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
"storage": Option("/var/lib/kvmd/msd", type=valid_abs_dir, unpack_as="storage_path"),
- "remount_cmd": Option([
- "/usr/bin/sudo", "--non-interactive",
- "/usr/bin/kvmd-helper-otgmsd-remount", "{mode}",
- ], type=valid_command),
+ "remount_cmd": Option([*sudo, "/usr/bin/kvmd-helper-otgmsd-remount", "{mode}"], type=valid_command),
+ "unlock_cmd": Option([*sudo, "/usr/bin/kvmd-helper-otgmsd-unlock", "unlock"], type=valid_command),
"initial": {
"image": Option("", type=valid_printable_filename, if_empty=""),
@@ -250,6 +250,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
async def reset(self) -> None:
async with self.__state.busy(check_online=False):
try:
+ await self.__unlock_drive()
self.__drive.set_image_path("")
self.__drive.set_cdrom_flag(False)
self.__drive.set_rw_flag(False)
@@ -314,6 +315,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
if not os.path.exists(self.__state.vd.image.path):
raise MsdUnknownImageError()
+ await self.__unlock_drive()
self.__drive.set_rw_flag(self.__state.vd.rw)
self.__drive.set_cdrom_flag(self.__state.vd.cdrom)
if self.__state.vd.rw:
@@ -323,6 +325,8 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
else:
if not (self.__state.vd.connected or self.__drive.get_image_path()):
raise MsdDisconnectedError()
+
+ await self.__unlock_drive()
self.__drive.set_image_path("")
await self.__remount_rw(False, fatal=False)
@@ -529,6 +533,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
if os.path.exists(path):
logger.info("Setting up initial image %r ...", self.__initial_image)
try:
+ await self.__unlock_drive()
self.__drive.set_rw_flag(False)
self.__drive.set_cdrom_flag(self.__initial_cdrom)
self.__drive.set_image_path(path)
@@ -597,5 +602,8 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
async def __remount_rw(self, rw: bool, fatal: bool=True) -> None:
if not (await aiohelpers.remount("MSD", self.__remount_cmd, rw)):
- if fatal:
- raise MsdError("Can't execute remount helper")
+ pass
+ #raise MsdError("Can't execute remount helper")
+
+ async def __unlock_drive(self) -> None:
+ await aiohelpers.unlock_drive(self.__unlock_cmd)
diff --git a/kvmd/plugins/msd/otg/drive.py b/kvmd/plugins/msd/otg/drive.py
index 11af7f81..ee54e5e9 100644
--- a/kvmd/plugins/msd/otg/drive.py
+++ b/kvmd/plugins/msd/otg/drive.py
@@ -53,10 +53,7 @@ class Drive:
# =====
def set_image_path(self, path: str) -> None:
- if path:
- self.__set_param("file", path)
- else:
- self.__set_param("forced_eject", "")
+ self.__set_param("file", path)
def get_image_path(self) -> str:
return self.__get_param("file")
--
2.34.1.windows.1
================================================
FILE: patches/custom/old-kernel-msd/v3.84-v3.92/0001-Revert-force-eject-feature-to-unlock-helper.patch
================================================
From 3d137882ac38ac046b7d09cada1883b304b04319 Mon Sep 17 00:00:00 2001
From: xe5700 <9338143+xe5700@users.noreply.github.com>
Date: Fri, 20 May 2022 18:34:21 +0800
Subject: [PATCH] Revert force eject feature to unlock helper
---
kvmd/aiohelpers.py | 31 ++++++++++++-----
kvmd/apps/otg/__init__.py | 3 +-
kvmd/apps/otgmsd/__init__.py | 25 +++++++++++++-
kvmd/helpers/unlock/__init__.py | 58 ++++++++++++++++++++++++++++++++
kvmd/helpers/unlock/__main__.py | 24 +++++++++++++
kvmd/plugins/msd/otg/__init__.py | 19 ++++++++---
kvmd/plugins/msd/otg/drive.py | 5 +--
7 files changed, 145 insertions(+), 20 deletions(-)
create mode 100644 kvmd/helpers/unlock/__init__.py
create mode 100644 kvmd/helpers/unlock/__main__.py
diff --git a/kvmd/aiohelpers.py b/kvmd/aiohelpers.py
index 6357764c..37a5d4b9 100644
--- a/kvmd/aiohelpers.py
+++ b/kvmd/aiohelpers.py
@@ -40,11 +40,26 @@ async def remount(name: str, base_cmd: List[str], rw: bool) -> bool:
]
logger.info("Remounting %s storage to %s: %s ...", name, mode.upper(), cmd)
try:
- proc = await aioproc.log_process(cmd, logger)
- if proc.returncode != 0:
- assert proc.returncode is not None
- raise subprocess.CalledProcessError(proc.returncode, cmd)
- except Exception as err:
- logger.error("Can't remount %s storage: %s", name, tools.efmt(err))
- return False
- return True
+ await _run_helper(cmd)
+ except Exception:
+ logger.error("Can't remount internal storage")
+ raise
+
+
+async def unlock_drive(base_cmd: List[str]) -> None:
+ logger = get_logger(0)
+ logger.info("Unlocking the drive ...")
+ try:
+ await _run_helper(base_cmd)
+ except Exception:
+ logger.error("Can't unlock the drive")
+ raise
+
+
+# =====
+async def _run_helper(cmd: List[str]) -> None:
+ logger = get_logger(0)
+ logger.info("Executing helper %s ...", cmd)
+ proc = await aioproc.log_process(cmd, logger)
+ if proc.returncode != 0:
+ raise MsdError(f"Error while helper execution: pid={proc.pid}; retcode={proc.returncode}")
diff --git a/kvmd/apps/otg/__init__.py b/kvmd/apps/otg/__init__.py
index cbf7a197..d0ed0554 100644
--- a/kvmd/apps/otg/__init__.py
+++ b/kvmd/apps/otg/__init__.py
@@ -182,7 +182,6 @@ class _GadgetConfig:
_chown(join(func_path, "lun.0/cdrom"), user)
_chown(join(func_path, "lun.0/ro"), user)
_chown(join(func_path, "lun.0/file"), user)
- _chown(join(func_path, "lun.0/forced_eject"), user)
_symlink(func_path, join(self.__profile_path, func))
name = ("Mass Storage Drive" if self.__msd_instance == 0 else f"Extra Drive #{self.__msd_instance}")
self.__create_meta(func, name)
@@ -291,7 +290,7 @@ def _cmd_stop(config: Section) -> None:
logger.info("Disabling gadget %r ...", config.otg.gadget)
_write(join(gadget_path, "UDC"), "\n")
- _unlink(join(gadget_path, "os_desc", usb.G_PROFILE_NAME), optional=True)
+ _unlink(join(gadget_path, "os_desc", usb.G_PROFILE_NAME), True)
profile_path = join(gadget_path, usb.G_PROFILE)
for func in os.listdir(profile_path):
diff --git a/kvmd/apps/otgmsd/__init__.py b/kvmd/apps/otgmsd/__init__.py
index f57b3107..78f8e3c7 100644
--- a/kvmd/apps/otgmsd/__init__.py
+++ b/kvmd/apps/otgmsd/__init__.py
@@ -21,12 +21,15 @@
import os
+import signal
import errno
import argparse
from typing import List
from typing import Optional
+import psutil
+
from ...validators.basic import valid_bool
from ...validators.basic import valid_int_f0
from ...validators.os import valid_abs_file
@@ -56,6 +59,21 @@ def _set_param(gadget: str, instance: int, param: str, value: str) -> None:
raise
+def _unlock() -> None:
+ # https://github.com/torvalds/linux/blob/3039fad/drivers/usb/gadget/function/f_mass_storage.c#L2924
+ found = False
+ for proc in psutil.process_iter():
+ attrs = proc.as_dict(attrs=["name", "exe", "pid"])
+ if attrs.get("name") == "file-storage" and not attrs.get("exe"):
+ try:
+ proc.send_signal(signal.SIGUSR1)
+ found = True
+ except Exception as err:
+ raise SystemExit(f"Can't send SIGUSR1 to MSD kernel thread with pid={attrs['pid']}: {err}")
+ if not found:
+ raise SystemExit("Can't find MSD kernel thread")
+
+
# =====
def main(argv: Optional[List[str]]=None) -> None:
(parent_parser, argv, config) = init(
@@ -70,6 +88,8 @@ def main(argv: Optional[List[str]]=None) -> None:
)
parser.add_argument("-i", "--instance", default=0, type=valid_int_f0,
metavar="<N>", help="Drive instance (0 for KVMD drive)")
+ parser.add_argument("--unlock", action="store_true",
+ help="Send SIGUSR1 to MSD kernel thread")
parser.add_argument("--set-cdrom", default=None, type=valid_bool,
metavar="<1|0|yes|no>", help="Set CD-ROM flag")
parser.add_argument("--set-rw", default=None, type=valid_bool,
@@ -89,8 +109,11 @@ def main(argv: Optional[List[str]]=None) -> None:
set_param = (lambda param, value: _set_param(config.otg.gadget, options.instance, param, value))
get_param = (lambda param: _get_param(config.otg.gadget, options.instance, param))
+ if options.unlock:
+ _unlock()
+
if options.eject:
- set_param("forced_eject", "")
+ set_param("file", "")
if options.set_cdrom is not None:
set_param("cdrom", str(int(options.set_cdrom)))
diff --git a/kvmd/helpers/unlock/__init__.py b/kvmd/helpers/unlock/__init__.py
new file mode 100644
index 00000000..140e0e7c
--- /dev/null
+++ b/kvmd/helpers/unlock/__init__.py
@@ -0,0 +1,58 @@
+# ========================================================================== #
+# #
+# KVMD - The main PiKVM daemon. #
+# #
+# Copyright (C) 2018-2022 Maxim Devaev <mdevaev@gmail.com> #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <https://www.gnu.org/licenses/>. #
+# #
+# ========================================================================== #
+
+
+import sys
+import signal
+
+import psutil
+
+
+# =====
+_PROCESS_NAME = "file-storage"
+
+
+# =====
+def _log(msg: str) -> None:
+ print(msg, file=sys.stderr)
+
+
+def _unlock() -> None:
+ # https://github.com/torvalds/linux/blob/3039fad/drivers/usb/gadget/function/f_mass_storage.c#L2924
+ found = False
+ for proc in psutil.process_iter():
+ attrs = proc.as_dict(attrs=["name", "exe", "pid"])
+ if attrs.get("name") == _PROCESS_NAME and not attrs.get("exe"):
+ _log(f"Sending SIGUSR1 to MSD {_PROCESS_NAME!r} kernel thread with pid={attrs['pid']} ...")
+ try:
+ proc.send_signal(signal.SIGUSR1)
+ found = True
+ except Exception as err:
+ raise SystemExit(f"Can't send SIGUSR1 to MSD kernel thread with pid={attrs['pid']}: {err}")
+ if not found:
+ raise SystemExit(f"Can't find MSD kernel thread {_PROCESS_NAME!r}")
+
+
+# =====
+def main() -> None:
+ if len(sys.argv) != 2 or sys.argv[1] != "unlock":
+ raise SystemExit(f"Usage: {sys.argv[0]} [unlock]")
+ _unlock()
diff --git a/kvmd/helpers/unlock/__main__.py b/kvmd/helpers/unlock/__main__.py
new file mode 100644
index 00000000..3849d1b9
--- /dev/null
+++ b/kvmd/helpers/unlock/__main__.py
@@ -0,0 +1,24 @@
+# ========================================================================== #
+# #
+# KVMD - The main PiKVM daemon. #
+# #
+# Copyright (C) 2018-2022 Maxim Devaev <mdevaev@gmail.com> #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <https://www.gnu.org/licenses/>. #
+# #
+# ========================================================================== #
+
+
+from . import main
+main()
diff --git a/kvmd/plugins/msd/otg/__init__.py b/kvmd/plugins/msd/otg/__init__.py
index 409b899a..1342c6b4 100644
--- a/kvmd/plugins/msd/otg/__init__.py
+++ b/kvmd/plugins/msd/otg/__init__.py
@@ -140,6 +140,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
storage_path: str,
remount_cmd: List[str],
+ unlock_cmd: List[str],
initial: Dict,
@@ -154,6 +155,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
self.__meta_path = os.path.join(self.__storage_path, "meta")
self.__remount_cmd = remount_cmd
+ self.__unlock_cmd = unlock_cmd
self.__initial_image: str = initial["image"]
self.__initial_cdrom: bool = initial["cdrom"]
@@ -178,10 +180,8 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
"storage": Option("/var/lib/kvmd/msd", type=valid_abs_dir, unpack_as="storage_path"),
- "remount_cmd": Option([
- "/usr/bin/sudo", "--non-interactive",
- "/usr/bin/kvmd-helper-otgmsd-remount", "{mode}",
- ], type=valid_command),
+ "remount_cmd": Option([*sudo, "/usr/bin/kvmd-helper-otgmsd-remount", "{mode}"], type=valid_command),
+ "unlock_cmd": Option([*sudo, "/usr/bin/kvmd-helper-otgmsd-unlock", "unlock"], type=valid_command),
"initial": {
"image": Option("", type=valid_printable_filename, if_empty=""),
@@ -241,6 +241,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
async def reset(self) -> None:
async with self.__state.busy(check_online=False):
try:
+ await self.__unlock_drive()
self.__drive.set_image_path("")
self.__drive.set_rw_flag(False)
self.__drive.set_cdrom_flag(False)
@@ -290,12 +291,15 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
if not os.path.exists(self.__state.vd.image.path):
raise MsdUnknownImageError()
+ await self.__unlock_drive()
self.__drive.set_cdrom_flag(self.__state.vd.cdrom)
self.__drive.set_image_path(self.__state.vd.image.path)
else:
if not (self.__state.vd.connected or self.__drive.get_image_path()):
raise MsdDisconnectedError()
+
+ await self.__unlock_drive()
self.__drive.set_image_path("")
self.__state.vd.connected = connected
@@ -474,6 +478,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
if os.path.exists(path):
logger.info("Setting up initial image %r ...", self.__initial_image)
try:
+ await self.__unlock_drive()
self.__drive.set_cdrom_flag(self.__initial_cdrom)
self.__drive.set_image_path(path)
except Exception:
@@ -541,4 +546,8 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
async def __remount_storage(self, rw: bool) -> None:
if not (await aiohelpers.remount("MSD", self.__remount_cmd, rw)):
- raise MsdError("Can't execute remount helper")
+ pass
+ #raise MsdError("Can't execute remount helper")
+
+ async def __unlock_drive(self) -> None:
+ await helpers.unlock_drive(self.__unlock_cmd)
\ No newline at end of file
diff --git a/kvmd/plugins/msd/otg/drive.py b/kvmd/plugins/msd/otg/drive.py
index 11af7f81..ee54e5e9 100644
--- a/kvmd/plugins/msd/otg/drive.py
+++ b/kvmd/plugins/msd/otg/drive.py
@@ -53,10 +53,7 @@ class Drive:
# =====
def set_image_path(self, path: str) -> None:
- if path:
- self.__set_param("file", path)
- else:
- self.__set_param("forced_eject", "")
+ self.__set_param("file", path)
def get_image_path(self) -> str:
return self.__get_param("file")
--
2.34.1.windows.1
================================================
FILE: patches/custom/old-kernel-msd/v3.84-v3.92/0003-Allow-skip-some-features-unsupports-on-old-linux-ker.patch
================================================
From 840b9af2bc6f65851bd45eeb0cb4d629aed3423a Mon Sep 17 00:00:00 2001
From: Frank Zhang <xe5700@outlook.com>
Date: Thu, 19 May 2022 22:48:49 +0800
Subject: [PATCH] Allow skip some features unsupports on old linux kernel
---
kvmd/apps/otg/__init__.py | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/kvmd/apps/otg/__init__.py b/kvmd/apps/otg/__init__.py
index d0ed0554..4aaeb3f8 100644
--- a/kvmd/apps/otg/__init__.py
+++ b/kvmd/apps/otg/__init__.py
@@ -78,8 +78,11 @@ def _unlink(path: str, optional: bool=False) -> None:
os.unlink(path)
-def _write(path: str, value: Union[str, int]) -> None:
+def _write(path: str, value: Union[str, int], optional: bool=False) -> None:
get_logger().info("WRITE --- %s", path)
+ if optional and not os.access(path, os.F_OK):
+ get_logger().info("SKIP ---- %s", path)
+ return
with open(path, "w") as param_file:
param_file.write(str(value))
@@ -158,9 +161,9 @@ class _GadgetConfig:
func = f"hid.usb{self.__hid_instance}"
func_path = join(self.__gadget_path, "functions", func)
_mkdir(func_path)
- _write(join(func_path, "no_out_endpoint"), "1")
+ _write(join(func_path, "no_out_endpoint"), "1", optional=True)
if remote_wakeup:
- _write(join(func_path, "wakeup_on_write"), "1")
+ _write(join(func_path, "wakeup_on_write"), "1", optional=True)
_write(join(func_path, "protocol"), hid.protocol)
_write(join(func_path, "subclass"), hid.subclass)
_write(join(func_path, "report_length"), hid.report_length)
--
2.34.1.windows.1
================================================
FILE: patches/disable_gpio/v3.47-v3.81/0001-Disable-GPIO-For-TV-Box.patch
================================================
From 368eaa19ef1cc187c8012c00b95ad97f260d61c3 Mon Sep 17 00:00:00 2001
From: xe5700 <9338143+xe5700@users.noreply.github.com>
Date: Sun, 23 Oct 2022 11:10:24 +0800
Subject: [PATCH] Disable-GPIO-For-TV-Box
---
kvmd/apps/kvmd/ugpio.py | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/kvmd/apps/kvmd/ugpio.py b/kvmd/apps/kvmd/ugpio.py
index a8fc9224..8bf17fff 100644
--- a/kvmd/apps/kvmd/ugpio.py
+++ b/kvmd/apps/kvmd/ugpio.py
@@ -281,16 +281,10 @@ class UserGpio:
await self.__notifier.wait()
def sysprep(self) -> None:
- get_logger().info("Preparing User-GPIO drivers ...")
- for (_, driver) in tools.sorted_kvs(self.__drivers):
- driver.prepare()
+ pass
async def systask(self) -> None:
- get_logger(0).info("Running User-GPIO drivers ...")
- await asyncio.gather(*[
- driver.run()
- for (_, driver) in tools.sorted_kvs(self.__drivers)
- ])
+ await asyncio.Event().wait()
async def cleanup(self) -> None:
for driver in self.__drivers.values():
--
2.34.1.windows.1
================================================
FILE: patches/disable_gpio/v3.82-v3.83/0001-Disable-GPIO-For-TV-Box.patch
================================================
From 960b30ec20b370269ee43282f1867861e714e33f Mon Sep 17 00:00:00 2001
From: xe5700 <9338143+xe5700@users.noreply.github.com>
Date: Thu, 19 May 2022 23:01:20 +0800
Subject: [PATCH] Disable-GPIO-For-TV-Box
---
kvmd/apps/kvmd/ugpio.py | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/kvmd/apps/kvmd/ugpio.py b/kvmd/apps/kvmd/ugpio.py
index cea60bb9..9328496a 100644
--- a/kvmd/apps/kvmd/ugpio.py
+++ b/kvmd/apps/kvmd/ugpio.py
@@ -282,15 +282,15 @@ class UserGpio:
def sysprep(self) -> None:
get_logger(0).info("Preparing User-GPIO drivers ...")
- for (_, driver) in tools.sorted_kvs(self.__drivers):
- driver.prepare()
+# for (_, driver) in tools.sorted_kvs(self.__drivers):
+# driver.prepare()
async def systask(self) -> None:
get_logger(0).info("Running User-GPIO drivers ...")
- await asyncio.gather(*[
- driver.run()
- for (_, driver) in tools.sorted_kvs(self.__drivers)
- ])
+# await asyncio.gather(*[
+# driver.run()
+# for (_, driver) in tools.sorted_kvs(self.__drivers)
+# ])
async def cleanup(self) -> None:
for driver in self.__drivers.values():
--
2.34.1.windows.1
================================================
FILE: patches/disable_gpio/v3.84-v3.134/0001-Disable-GPIO-For-TV-Box.patch
================================================
From 960b30ec20b370269ee43282f1867861e714e33f Mon Sep 17 00:00:00 2001
From: xe5700 <9338143+xe5700@users.noreply.github.com>
Date: Thu, 19 May 2022 23:01:20 +0800
Subject: [PATCH] Disable-GPIO-For-TV-Box
---
kvmd/apps/kvmd/ugpio.py | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/kvmd/apps/kvmd/ugpio.py b/kvmd/apps/kvmd/ugpio.py
index cea60bb9..9328496a 100644
--- a/kvmd/apps/kvmd/ugpio.py
+++ b/kvmd/apps/kvmd/ugpio.py
@@ -282,15 +282,16 @@ class UserGpio:
def sysprep(self) -> None:
get_logger(0).info("Preparing User-GPIO drivers ...")
- for (_, driver) in tools.sorted_kvs(self.__drivers):
- driver.prepare()
+# for (_, driver) in tools.sorted_kvs(self.__drivers):
+# driver.prepare()
async def systask(self) -> None:
get_logger(0).info("Running User-GPIO drivers ...")
- await asyncio.gather(*[
- driver.run()
- for (_, driver) in tools.sorted_kvs(self.__drivers)
- ])
+# await asyncio.gather(*[
+# driver.run()
+# for (_, driver) in tools.sorted_kvs(self.__drivers)
+# ])
+ await asyncio.Event().wait()
async def cleanup(self) -> None:
for driver in self.__drivers.values():
--
2.34.1.windows.1
================================================
FILE: patches/genernal/v3.84-v3.92/0001-Allow-skip-some-features-unsupports-on-old-linux-ker.patch
================================================
From 840b9af2bc6f65851bd45eeb0cb4d629aed3423a Mon Sep 17 00:00:00 2001
From: Frank Zhang <xe5700@outlook.com>
Date: Thu, 19 May 2022 22:48:49 +0800
Subject: [PATCH] Allow skip some features unsupports on old linux kernel
---
kvmd/apps/otg/__init__.py | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/kvmd/apps/otg/__init__.py b/kvmd/apps/otg/__init__.py
index d0ed0554..4aaeb3f8 100644
--- a/kvmd/apps/otg/__init__.py
+++ b/kvmd/apps/otg/__init__.py
@@ -78,8 +78,11 @@ def _unlink(path: str, optional: bool=False) -> None:
os.unlink(path)
-def _write(path: str, value: Union[str, int]) -> None:
+def _write(path: str, value: Union[str, int], optional: bool=False) -> None:
get_logger().info("WRITE --- %s", path)
+ if optional and not os.access(path, os.F_OK):
+ get_logger().info("SKIP ---- %s", path)
+ return
with open(path, "w") as param_file:
param_file.write(str(value))
@@ -158,9 +161,9 @@ class _GadgetConfig:
func = f"hid.usb{self.__hid_instance}"
func_path = join(self.__gadget_path, "functions", func)
_mkdir(func_path)
- _write(join(func_path, "no_out_endpoint"), "1")
+ _write(join(func_path, "no_out_endpoint"), "1", optional=True)
if remote_wakeup:
- _write(join(func_path, "wakeup_on_write"), "1")
+ _write(join(func_path, "wakeup_on_write"), "1", optional=True)
_write(join(func_path, "protocol"), hid.protocol)
_write(join(func_path, "subclass"), hid.subclass)
_write(join(func_path, "report_length"), hid.report_length)
--
2.34.1.windows.1
gitextract_k6lnbzxp/
├── .gitignore
├── LICENSE
├── README-zh-CN.MD
├── README.MD
├── amglogic-dtb-mod.py
├── armbian/
│ ├── armbian-motd
│ ├── opt/
│ │ ├── armbian-sysinfo
│ │ └── vcgencmd
│ └── udev/
│ └── rules.d/
│ └── 99-kvmd.rules
├── bin/
│ └── kvmd-helper-otgmsd-unlock
├── config.sh
├── dtb/
│ └── 4.4/
│ └── rk322x-box.dtb
├── install-mirror.sh
├── install.sh
├── libs/
│ ├── checksum.sh
│ ├── download_aria2.sh
│ └── download_wget.sh
└── patches/
├── custom/
│ └── old-kernel-msd/
│ ├── apply.sh
│ ├── v3.124-v3.142/
│ │ └── 0001-Apply-old-kernel-msd-patch-for-v3.134.patch
│ └── v3.84-v3.92/
│ ├── 0001-Revert-force-eject-feature-to-unlock-helper.patch
│ └── 0003-Allow-skip-some-features-unsupports-on-old-linux-ker.patch
├── disable_gpio/
│ ├── v3.47-v3.81/
│ │ └── 0001-Disable-GPIO-For-TV-Box.patch
│ ├── v3.82-v3.83/
│ │ └── 0001-Disable-GPIO-For-TV-Box.patch
│ └── v3.84-v3.134/
│ └── 0001-Disable-GPIO-For-TV-Box.patch
└── genernal/
└── v3.84-v3.92/
└── 0001-Allow-skip-some-features-unsupports-on-old-linux-ker.patch
Condensed preview — 25 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (104K chars).
[
{
"path": ".gitignore",
"chars": 38,
"preview": "workspace.code-workspace\r\ntmp\r\n.vscode"
},
{
"path": "LICENSE",
"chars": 18091,
"preview": " GNU GENERAL PUBLIC LICENSE\n Version 2, June 1991\n\n Copyright (C) 1989, 1991 Fr"
},
{
"path": "README-zh-CN.MD",
"chars": 4027,
"preview": "# 感谢由toss-a编写的中文教程\r\n该教程未验证,可能需要使用 https://github.com/toss-a/pikvm-armbian 该分叉才能运行。\r\n\r\n你可以尝试其他的项目基于pikvm\r\n分支版本 kvmd-armbi"
},
{
"path": "README.MD",
"chars": 2530,
"preview": "# KVMD-ARMBIAN\nThis project support non Raspberry Pi device to running pikvm on armbian\nYou can try other project based "
},
{
"path": "amglogic-dtb-mod.py",
"chars": 0,
"preview": ""
},
{
"path": "armbian/armbian-motd",
"chars": 128,
"preview": "#!/bin/sh\r\n/etc/update-motd.d/10-armbian-header\r\n/etc/update-motd.d/30-armbian-sysinfo\r\n/etc/update-motd.d/41-armbian-co"
},
{
"path": "armbian/opt/armbian-sysinfo",
"chars": 7450,
"preview": "#!/bin/bash\r\n#\r\n# Copyright (c) Authors: http://www.armbian.com/authors\r\n#\r\n# This file is licensed under the terms of t"
},
{
"path": "armbian/opt/vcgencmd",
"chars": 628,
"preview": "#!/bin/bash\r\ncd `dirname $0`\r\nsource armbian-sysinfo\r\n\r\ncase $1 in\r\n get_throttled) echo \"throttled=0x0\";;\r\n "
},
{
"path": "armbian/udev/rules.d/99-kvmd.rules",
"chars": 510,
"preview": "# https://unix.stackexchange.com/questions/66901/how-to-bind-usb-device-under-a-static-name\r\n# https://wiki.archlinux.or"
},
{
"path": "bin/kvmd-helper-otgmsd-unlock",
"chars": 111,
"preview": "#!/usr/sbin/python\n# KVMD-ARMBIAN\n\nfrom kvmd.helpers.unlock import main\n\nif __name__ == \"__main__\":\n main()\n"
},
{
"path": "config.sh",
"chars": 1293,
"preview": "export APT_EXE=\"apt-get\" #If you installed apt-fast can change it to apt-fast to boost install speed.\nexport GIT_EXE=\"gi"
},
{
"path": "install-mirror.sh",
"chars": 2497,
"preview": "# Github 增强加速脚本\r\n# 加速地址参考github 增强加速下载脚本\r\n# Created by xe5700\r\n# @namespace https://greasyfork.org/scripts/412245\r\n# "
},
{
"path": "install.sh",
"chars": 19611,
"preview": "#!/bin/bash\n# modified by xe5700 \t\t2021-11-04\txe5700@outlook.com\n# modified by NewbieOrange\t2021-11-04\n# created by @sre"
},
{
"path": "libs/checksum.sh",
"chars": 275,
"preview": "checksum(){\n export sumRet=0\n case $1 in\n gpg) checksum_gpg $2 $3;;\n esac\n}\nchecksum_gpg(){\n gpg --ve"
},
{
"path": "libs/download_aria2.sh",
"chars": 979,
"preview": "#!/bin/bash\nsource libs/checksum.sh\ndownload(){\n tryCount=0\n echo Downloading $1 To $2\n download2 $1 $2 $3 $4\n "
},
{
"path": "libs/download_wget.sh",
"chars": 810,
"preview": "#!/bin/bash\nsource libs/checksum.sh\ndownload(){\n tryCount=0\n echo Downloading $1 To $2\n download2 $1 $2 $3 $4\n "
},
{
"path": "patches/custom/old-kernel-msd/apply.sh",
"chars": 814,
"preview": "#!/bin/bash\n# PYTHON_VERSION=$( python3 -V | awk '{print $2}' | cut -d'.' -f1,2 )\nAPP_PATH=$(readlink -f $(dirname $0))\n"
},
{
"path": "patches/custom/old-kernel-msd/v3.124-v3.142/0001-Apply-old-kernel-msd-patch-for-v3.134.patch",
"chars": 14579,
"preview": "From 18723b4c8e13a5cd0049982cfbbf61b4409ba159 Mon Sep 17 00:00:00 2001\nFrom: xe5700 <9338143+xe5700@users.noreply.github"
},
{
"path": "patches/custom/old-kernel-msd/v3.84-v3.92/0001-Revert-force-eject-feature-to-unlock-helper.patch",
"chars": 14414,
"preview": "From 3d137882ac38ac046b7d09cada1883b304b04319 Mon Sep 17 00:00:00 2001\nFrom: xe5700 <9338143+xe5700@users.noreply.github"
},
{
"path": "patches/custom/old-kernel-msd/v3.84-v3.92/0003-Allow-skip-some-features-unsupports-on-old-linux-ker.patch",
"chars": 1637,
"preview": "From 840b9af2bc6f65851bd45eeb0cb4d629aed3423a Mon Sep 17 00:00:00 2001\nFrom: Frank Zhang <xe5700@outlook.com>\nDate: Thu,"
},
{
"path": "patches/disable_gpio/v3.47-v3.81/0001-Disable-GPIO-For-TV-Box.patch",
"chars": 1123,
"preview": "From 368eaa19ef1cc187c8012c00b95ad97f260d61c3 Mon Sep 17 00:00:00 2001\nFrom: xe5700 <9338143+xe5700@users.noreply.github"
},
{
"path": "patches/disable_gpio/v3.82-v3.83/0001-Disable-GPIO-For-TV-Box.patch",
"chars": 1266,
"preview": "From 960b30ec20b370269ee43282f1867861e714e33f Mon Sep 17 00:00:00 2001\nFrom: xe5700 <9338143+xe5700@users.noreply.github"
},
{
"path": "patches/disable_gpio/v3.84-v3.134/0001-Disable-GPIO-For-TV-Box.patch",
"chars": 1304,
"preview": "From 960b30ec20b370269ee43282f1867861e714e33f Mon Sep 17 00:00:00 2001\nFrom: xe5700 <9338143+xe5700@users.noreply.github"
},
{
"path": "patches/genernal/v3.84-v3.92/0001-Allow-skip-some-features-unsupports-on-old-linux-ker.patch",
"chars": 1637,
"preview": "From 840b9af2bc6f65851bd45eeb0cb4d629aed3423a Mon Sep 17 00:00:00 2001\nFrom: Frank Zhang <xe5700@outlook.com>\nDate: Thu,"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the xe5700/kvmd-armbian GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 25 files (93.5 KB), approximately 28.9k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.