1 line
66 KiB
JSON
1 line
66 KiB
JSON
{"/about/":{"data":{"":"Kushidou 什么都学,却什么都不精通的一个小白 :P\nGitHub Bilibili","技能与方向#技能与方向":"嵌入式开发 — Linux 系统开发、驱动调试、交叉编译 开源软件 — Docker、Hugo、各类 CLI 工具 网络与服务 — 自建 NAS、内网穿透、家庭服务器 摄影 — 风光 / 街拍 / 生活记录","自我介绍#自我介绍":"我是一名嵌入式工程师,平时喜欢折腾各种开源软件和硬件。这个博客用来记录技术探索过程中的笔记和心得,也包括一些日常生活和摄影的分享。"},"title":"关于我"},"/glossary":{"data":{},"title":"Glossary"},"/posts/210218-teamspeakwithdocker/":{"data":{"":"TeamSpeak的官网总是有些问题,无法下载其客户端,所以考虑使用Docker来部署一个ts服务器环境。","docker及其安装#Docker及其安装":"docker是一个容器,可以打包一个程序及其依赖,然后移植到任意系统运行而不报错。\n我的服务器的腾讯云轻量-Wordpress应用,没有自带docker,所以第一步先安装docker:\nsudo yum install docker\t#安装docker程序,会自动选择合适的 sudo systemctl start docker\t#启动docker服务 sudo systemctl enable docker\t#允许docker开机自启","docker安装ts#Docker安装TS":"docker run -dit -p 9987:9987/udp -p 10011:10011 -p 30033:30033 -e TS3SERVER_LICENSE=accept teamspeak\n直接运行这条指令,docker就会自动寻找下载ts的容器并启动。如果下载太慢则自行查找修改docker仓库源的方式。","teamspeak#Teamspeak":"TeamSpeak(简称ts)是一款实时语音聊天软件,是替换yy语音的一个很好的选择。ts唯一的缺点是其服务器在国外,不论下载客户端还是服务端都是一个很麻烦的事情,且下载服务端后需要诸多配置和环境依赖,如果哪天不用了卸载也是一个麻烦事儿。\n所以,选择docker安装ts就是一个很不错的选择。","端口#端口":"从指令可以看出,docker需要使用到9987,10011,30033三个端口,所以需要到服务器后台开启防火墙上对应端口。","管理员密钥#管理员密钥":"TS允许用户成为管理员,在首次运行的时候会在log中打印。不过docker运行时添加了-dit参数表示后台运行,所以查看参数需要额外的操作。\ndocker ps -a查找所有容器。\ndocker logs -f [CONTATINER ID]查看log,找到token即可。客户端设置之后再说。\n密钥只会在第一次运行时打印,注意保存。\n参考:https://woolio.cn/683/"},"title":"使用Docker安装TeamSpeak"},"/posts/210311-multitouchscreeninlinux/":{"data":{"":"由于需要使用新创平台配合多个显示器,触摸屏经常出现不准的情况。经过多次的查阅资料、测试和整合,总结了一个解决触摸的方法。一些测试过程中的弯路也保留了,作为记录。\n2021-03-22更新部分内容 2021-04-28再次更新内容\n2021-09-14 文章已有新版本,请访问《Linux处理多触屏的终极解决方案》","参考#参考:":"[1]https://blog.csdn.net/yuan_da_xian/article/details/72864008 [2]https://blog.csdn.net/qq_33406883/article/details/106649087 [3]https://segmentfault.com/a/1190000020334077","后续问题#后续问题":"当屏幕参数改变,如调整分辨率、调整顺序、插拔屏幕、换屏幕等,都会引发映射的失效,需要再次执行脚本。 当屏幕发生改变,需要调整脚本中固化的参数,或调整执行脚本的输入参数 如果屏幕使用了相同的驱动ic,会看到同样的VID,这样子会难以区分。这时候把[1]处的判断条件改成按名称或者其他不同的参数,也能够自动适配。但两块完全一样的屏幕,现阶段还没想到解决方法,只能自己手动映射试试了。","尝试解决#尝试解决":"首先使用xinput查看触摸设备及其序号$id。这里可以看到多个设备,可以通过单独插拔的方式找到每个设备。 然后xinput list-props $id查看设备的VID,这个在后续自动化处理有用。 xrandr查看$显示器名称","自动化处理#自动化处理":"# 2021-04-28更新: # 本部分后面的都可以不看了! xinput map-to-output \"DEVICE_NAME\" DISPLAY # 把这一段写入可以自动执行的脚本里面,比如/etc/rc.local, ~/.bashrc, /etc/profile, # 以及制作成service等。有几个触摸屏就写几行指令,比下面的简洁了太多~ 仅作归档!下面这些方法过于繁琐!\n利用VID和显示器名称作为参数,运行下面的脚本,或者直接手动执行重映射,即可解决触屏作用范围问题。bash this.sh VID1 VID2 ScreenID\n#!/bin/bash # 这段适合触屏硬件id不同的情况,如果遇到id不同需要其他方法。 # 2021-03-22更新:在前几天的实操中,发现字符串比较部分出现了问题,这个方案的可行性有待进一步探索。现在采用另一种方案。 MYID_FIRST=$1 MYID_SECOND=$2 OUT_PUT=$3 for I in $(xinput list --id-only) do #[1] CUR_FIRST=$(xinput list-props $I|grep \"Device Product ID\"|awk -F : '{print $2}'|awk -F , '{print $1}'|awk '{print $1}') CUR_SECOND=$(xinput list-props $I|grep \"Device Product ID\"|awk -F : '{print $2}'|awk -F , '{print $2}'|awk '{print $1}') if [ \"$MYID_FIRST\" == \"$CUR_FIRST\" ] \u0026\u0026 [ \"$MYID_SECOND\" == \"$CUR_SECOND\" ]; then MY_INDEX=$I break; fi done xinput map-to-output $MY_INDEX $OUT_PUT #./this.sh VID VID HDMI2 #./this.sh VID VID HDMI1 #!/bin/bash # 2021-03-22更新:这种方案只要四行就能实现一块的映射,需要时只要复制这个代码块即可,修改DEVICE_NAME 和 SCREEN_NAME 。如果名称中带有重复的部分,可以再加一个grep -v xxxx来排除关键词。但是如果遇到屏幕完全重名的情况,就不可解了。 TOUCH_ID=$(xinput | grep -iw DEVICE_NAME) TOUCH_ID=$(echo ${TOUCH_ID#*id=}) TOUCH_ID=$(echo ${TOUCH_ID%% *}) xinput map-to-output $TOUCH_ID SCREEN_NAME 此方法可以在直到触屏VID后,(一般多显示器使用的是不同的型号),使用自启动rc.local开机执行重映射指令,保证每次开机都能准确找到屏幕,且适用于系列产品不用单独找id。\n经测试rc.local由于只在开机执行,如果分辨率在开机的时候改变了(比如用了转接头分辨率会重新调整),映射关系还是会出错。我决定用一个取巧的办法,把执行脚本的命令放在~/.bashrc中,这样只需要打开一次终端,就可以实现屏幕重新映射。","触屏校准如果需要#触屏校准(如果需要)":"网上说的利用校准来区分多触摸屏的方法是完全错误的,仅适用于他们的产品而不是通用解决方案,很多人就是抄来抄去而已。但是如果遇到触摸偏移,还是有需要进行校准的,校准方法为(最后一步需要甄别,有些系统没有这个目录)\nsudo apt install xinput-calibrator,需要更新源 sudo xinput_calibrator 将校准信息保存到/usr/share/X11/xorg.conf.d/10-evdev.conf的\"Driver evdev”下面一行,重启生效。","问题来源#问题来源":"最近客户要求使用信创平台,即国产CPU+国产操作系统平台。现在这方面主要使用的操作系统为麒麟和通信uos。这两个的本质都是debian系的,所以很多地方的调试与使用都可以按乌班图的经验来操作。一款产品要使用三块显示器,其中两块是触屏。屏幕通过R5 420显卡,都转换成VGA连接。 接入设备后,发现触摸屏默认是映射到全屏幕,在任何显示器上操作都会按排列顺序在对应的区域触发。所以需要给每个显示器分别映射触摸。映射的基本指令为\nxinput map-to-output $触屏设备id $显示屏名称\n2021-04-28更新\nxinput map-to-output指令支持触摸屏名称作为参数,比如我通过xinput指令看到有一个触摸屏的设备名称为ILITEK XXXX,那么我映射的时候直接输入\nxinput map-to-output \"ILITEK XXX\" HDMI-1"},"title":"Linux多显示器触屏调试与暂行解决方案"},"/posts/210311-serialmodeandudevinlinux/":{"data":{"":"配置串口权限,顺便看一下linux的udev规则。","udev规则#udev规则":"udev是什么?udev是Linux下的设备文件管理方式,运行在用户侧(devfs在内核侧管理设备文件)。有了udev,/dev目录下的文件就都是真实存在的已连接的设备了。\nudev的规则都保存在/etc/udev/rules.d目录下,文件名的格式为数字-名称.rules,数字表示加载顺序,一般是从小往大加载;名称按功能自定义,最后以.rules结尾。这些规则会在设备接入时生效。\n规则文件按行执行,每行分为两个部分:匹配和赋值,每个参数使用逗号,分割。\n(这段复制自引用2,仅供参考)。 1、udev 规则的所有操作符 == 比较键、值,若等于,则该条件满足; != 比较键、值,若不等于,则该条件满足; = 对一个键赋值; += 为一个表示多个条目的键赋值。 := 对一个键赋值,并拒绝之后所有对该键的改动,防止后面的规则文件对该键重赋值。\n2、udev 规则的匹配键 ACTION 事件 (uevent) 的行为,例如:add、remove。 KERNEL 内核设备名称,例如:sda, cdrom。 DEVPATH 设备的 devpath 路径。 SUBSYSTEM 设备的子系统名称,例如:sda 的子系统为 block。 BUS 设备在 devpath 里的总线名称,例如:usb。 DRIVER 设备在 devpath 里的设备驱动名称,例如:ide-cdrom。 ID 设备在 devpath 里的识别号。 SYSFS{filename} 设备的 devpath 路径下,设备的属性文件“filename”里的内容。 ENV{key} 环境变量。在一条规则中,可以设定最多五条环境变量的 匹配键。 PROGRAM 调用外部命令。 RESULT 外部命令 PROGRAM 的返回结果。\n3、udev 的重要赋值键 NAME /dev目录下显示的文件名重命名 SYMLINK 为 /dev下文件进行符号链接,防止覆盖系统默认产生的文件 OWNER, GROUP, MODE 为设备设定权限。 ENV{key} 导入一个环境变量。\n4、udev 的值和可调用的替换操作符 Linux 用户可以随意地定制 udev 规则文件的值。例如:my_root_disk, my_printer。同时也可以引用下面的替换操作符: $kernel, %k 设备的内核设备名称,例如:sda、cdrom。 $number, %n 设备的内核号码,例如:sda3 的内核号码是 3。 $devpath, %p 设备的 devpath路径。 $id, %b 设备在 devpath里的 ID 号。 $sysfs{file}, %s{file} 设备的 sysfs里 file 的内容。其实就是设备的属性值。 $env{key}, %E{key} 一个环境变量的值。 $major, %M 设备的 major 号。 $minor %m 设备的 minor 号。 $result, %c PROGRAM 返回的结果。 $parent, %P 父设备的设备文件名。 $root, %r udev_root的值,默认是 /dev/。 $tempnode, %N 临时设备名。 %% 符号 % 本身。 $$ 符号 $ 本身。","xxxrules#xxx.rules":"sudo vi /etc/udev/rules.d/70-tty-usb-rules,写入以下内容:\nKERNEL==\"ttyS*\",MODE=\"0666\" KERNEL==\"ttyUSB*\",MODE=\"0666\" 这一段的意思是匹配所有ttyS和ttyUSB,插入时都赋予0666的权限,即所有用户都可读可写。重新加载一下设备,就可以按规则配置权限进行操作了。","串口的问题#串口的问题":"在现场开发的同事反映UOS工控机没有配置串口,每次都需要sudo才能使用。(明明在家里你们都会自己配置好环境与权限,为什么到了现场反而不会了需要我提供协助呢?)\n我之前没考虑过这个问题,认为串口就是得root权限操作才安全。但是既然提出了需求,就赶紧百度并测试一下吧。","参考#参考":"[1]https://www.cnblogs.com/qixianyu/p/6869744.html [2]https://www.cnblogs.com/cslunatic/p/3171837.html","赋予普通用户串口权限的两种方法#赋予普通用户串口权限的两种方法":"在百度上,给普通用户串口权限有两种主流方法(可能2会了,Google上不去),一种是将用户放入特殊的用户组,从而获得权限。另一种是加入udev规则,在串口插入时自动更改权限。\n我个人更倾向于使用第二种方案,因为公司中不同的人装系统就可能起不同的名字,之后进入生产环境可能又会起新的名字,所以采用第二种设置规则的办法,便于之后制作恢复镜像和一键部署。"},"title":"Linux串口和udev理解"},"/posts/210328-linuxchangemacip/":{"data":{"linux调整网卡mac地址指令#Linux调整网卡MAC地址(指令)":"当Linux的图形界面没有或失效的时候,该如何更改mac地址?\nLinux调整网卡MAC地址(指令)有的时候需要使用欺骗的方法为电脑设置新的mac,比如存在上网网卡限制,或者想要隐藏自己的真实mac地址。这里列举三种修改mac的方法,适用于Debian系的Linux,其他的应该类似。","备注#备注:":"以上两种方法是软件层面的修改,不会对硬件造成损伤,重启之后就能恢复如初。如果是要长期有效,可以把这些命令写入脚本开机自启。除了这两个,还有另一种软修改的方法,因为我总是提示失败就遗忘了。\n有些方法会提到修改/etc目录下的文件实现MAC地址的修改,但是我一个文件都没找到(UOS),这个是因系统而异的,不同的发行版可以选择性的编译这些文件,就会造成有人有有人没有,因为没有实践,所以就不写在这里了。","如果以上方法都无法修改则建议申请新的ip#如果以上方法都无法修改,则建议申请新的ip。。。":"文章首发于香风家的小别墅,转载请携带出处。","方法一ifconfig#方法一:ifconfig":"# ifconfig 查看网卡名称$NAME # 需要sudo权限 ifconfig $NAME down ifconfig $NAME hw ether $NEW_MAC ifconfig $NAME up # 使用ifconfig检查有没有改变","方法三ethtool慎用#方法三:ethtool(慎用)":"以上方法都失效,可以直接修改网卡的物理MAC地址,修改后无法恢复,慎用\n# 首先检查mac是否支持修改 ethtool -i $NAME # 如果 supports-eeprom-access: no,大概率不支持修改 # 查看网卡的mac寄存器 ethtool -e $NAME # 如果无法读取,大概率不支持修改 # 修改mac,按字节修改 ethtool -E $NAME offset 0 value 0xAA ethtool -E $NAME offset 1 value 0xBB ethtool -E $NAME offset 2 value 0xCC ...共六行 # 如果修改无效,则驱动不支持修改","方法二macchanger#方法二:macchanger":"sudo apt install macchanger,安装过程提示是否自启,随便。\nifconfig $NAME down macchanger -m $NEW_MAC $NAME ifconfig $NAME up ps:macchanger可以附加多种参数,如-m指定mac地址,-s查看状态,-r随机地址"},"title":"Linux修改mac地址"},"/posts/210420-linuxmorethan4serialport/":{"data":{"":"工控板安装Linux常常最多只能看到四个串口,通过修改引导文件可以显示所有的串口。","先说结论#先说结论":"# 1.修改开机grub文件 sudo vi /etc/default/grub # 2.在\"GRUB_CMDLINE_LINUX_DEFAULT=\"一行的结尾空格,添加内容 8250.nr_uarts=8 # 3.更新开机引导并重启 sudo update-grub","再说细节#再说细节":"给带有多串口的工控机安装国产Linux操作系统UOS,发现/dev/ttyS只有四个,而且一个都不通,其实这是Linux 的通病,如果发行商没有提前配置,我们只能看到四个不能用的串口。但是工控机都有8-16个串口,不得不想办法让他们能够正常使用,而许多串口芯片只需要基本的驱动就能运行,也不提供专有驱动的源代码编译(一般安装专用驱动后,串口名称会改变,比如xr17v358芯片的驱动安装后名称变成ttyXR0),我们只有从linux本身下手了。\n经过多番查找资料,虽然不知道为什么,但是我们应该修改/etc/default/grub文件,其中有一行是这样的:\nGRUB_CMDLINE_LINUX_DEFAULT=\"这里面 的内容 先不管 它\" 我看了UOS(含Deepin)、Ubuntu和服务器的Centos7都有,在这一行的最后添加8250.nr_uart=32,其中数字\u003c=32都行,效果如下:\nGRUB_CMDLINE_LINUX_DEFAULT=\"这里面 的内容 先不管 它 8250.nr_uarts=32\" 然后更新一下系统的引导\nsudo update-gurb reboot 重启完了你就能看到更多的串口啦!配合修改udev规则,你就可以用普通用户的权限使用串口通信了。但是请注意其他隐患,比如这个芯片配合基本驱动只能完成基础的收发功能,流控的RTS、CTS等还是需要专用驱动实现的!","参考#参考:":"https://blog.wjacobsen.dk/2019/05/03/enable-more-than-4-serial-ports-linux-unix/\n核心步骤就参考了这个,在Linux方面大家还是多用google,多用英文去搜索吧!","最后吐槽#最后吐槽":"为了串口问题我找了一下午的资料,最后才在外网找到了一个能用的。国内的教程都是说要修改/boot/gurb/gurb2,宝友,这可不兴改啊,这个改坏了系统可就没了啊!这些文件普通用户连浏览权限都没就可见其重要性。"},"title":"Linux启用四个以上的串口"},"/posts/210429-deepinautorun/":{"data":{"":"修正触屏的脚本总是运行失败,于是找到在Deepin下能够在桌面启动后自动运行的方法。这样的触屏映射就稳定了。经测试在Ubuntu 1604中也适用。","uosdeepin和ubuntu#UOS/Deepin和Ubuntu":"cp ~/Desktop/刚刚的.desktop ~/.config/autostart\n需要这个的原因主要是我执行触摸屏映射的指令经常会在桌面启动前(lightdm.service)执行,导致error从而无法进入桌面,将脚本放进/etc/profile.d之后第二天就失效了,所以需要一个在登录桌面后就实现自动执行的功能,多种方法对比下来还是放进桌面环境的开机自启文件夹比较靠谱。这样一般会在进入桌面后5-10秒自动执行,稳定性大幅提高。\n经过实际查阅资料和测试,Ubuntu1604也完全适用上面的步骤,只不过可能需要在~/.config/下手动创建一个autostart目录。由于1604已经停止支持,许多人转入了更新的ubuntu系统,猜测近几年的也可以尝试一下。","开始菜单#开始菜单":"sudo cp ~/Desktop/刚刚的.desktop /usr/share/applications,过一会或者注销重新登录就能看到开始菜单的响应类型下出现这个快捷方式了。","开机自动执行#开机自动执行":"","桌面快捷方式#桌面快捷方式":"deepin的桌面快捷方式是以*.desktop文件的形式实现的,所以我们需要添加自定义快捷方式的话,只要在桌面添加要给desktop格式的文本文件,编辑内容\n[Desktop Entry]\rName=ddd\rExec=\"/usr/sbin/xx.sh\"\rType=Application 其中Desktop Entry表示声明该文件为快捷方式文件。Name是这个文件要显示的名字,设置了之后就可以隐藏原名称和扩展名。Exec是程序的启动脚本,或者启动指令。Type是程序类型,在开始菜单的分类中可以体现。以上四行是必须要有的参数,还有一些其他的参数不影响执行。Exec的脚本必须赋予777权限以执行。\n把这个文件放在~/Desktop,就可以看到桌面上多了一个快捷方式了。","麒麟和其他使用x11桌面的linux#麒麟和其他使用X11桌面的Linux":"本条目包含UOS和Ubuntu、deepin系统\n自启动目录为/etc/xdg/autostart,同样的desktop文件放进去即可。但是麒麟中我使用上面的基础desktop报错,可能需要添加其他内容。"},"title":"deepin和UOS,快捷方式,开机自启动"},"/posts/210630-sudowithoutpasswd/":{"data":{"":"记录一种可以免密码使用sudo的方法。\n每次使用sudo提权,常常要输密码太烦了,所以想给自己赋予免密码的特权。\n首先登录root用户: sudo -i\n这个操作的核心文件是/etc/sudoers,可以看到这个文件是只读的,要修改他需要先赋予写入权限。\nchmod 666 /etc/sudoers 使用vim修改文件,vi /etc/sudoers,把当前用户和用户组加入,如图 # 表示为该用户免密码 yourname\tALL=(ALL:ALL) NOPASSWD:ALL # 表示为该用户组免密码 %yourname\tALL=(ALL:ALL) NOPASSWD:ALL # 不用严格按照次形式,与你的这个文件中root的格式对应即可。 :wq保存,把sodoers改回只读 chmod 440 /etc/sudoers 完成~~~ 把终端关掉再次打开就应该能看到效果了。 PS. 不可使用sudo chmod\n一定要直接sudo -i进入root用户,如果使用sudo chmod以普通用户的身份修改sudoers文件的话,改完会发现无法使用sudo指令把权限改回去了,提示“任何人可读写,无法找到有效的sudoers”。其实还有一种更加安全的操作,但是那个编辑器用起来没有vim顺手,\n参考:https://blog.csdn.net/wxqee/article/details/72718869"},"title":"免密码使用sudo"},"/posts/210719-gpuinfoinlinux/":{"data":{"":"在Linux下获得AMD GPU的状态和温度信息。\n在Linux下如果要查看Nvidia GPU的状态信息,可以使用Nvidia驱动自带的工具。而AMD显卡一般都是使用的开源驱动,这种情况下如何获得显卡的状态和占用呢?\n文章部分图片之后再附","1获取gpu信息#1、获取GPU信息":"如需获得GPU的信息(型号、驱动)等,如果系统提供类似*“设备管理器”*的工具可以打开查看。或者就是用lspci指令查看。\n# 获得所有PCIe设备,在其中找到AMD GPU [exam@ple]:~$ lspci 00:02.0 VGA compatible controller: xxxxxxxx [exam@ple]:~$ lspci -v -s 00:02.0 # 这里就会显示显卡的具体信息了,包括型号、驱动等,之后补充","2gpu占用率#2、GPU占用率":"显卡占用率是一个能反映负载的直观指标,AMD显卡可以通过安装radeontop软件查看。\n最上面是GPU管道使用,大概类似于总体使用率的东西;最下面是内存使用率,使用sudo权限能看到更多信息。其他项目可以到radeontop的Github页面查看。","3温度#3、温度":"特指GPU温度。查阅这篇文章所涉及的知识点的最初目的,也是确认机箱过热是否是GPU的问题。\nGPU温度使用第三方软件查看,并使其实时更新。查看温度使用sensors指令,通过安装lm-sensors实现。执行sensors时只会显示一次,我们可以利用watch指令定时刷新温度显示:\nwatch -n 2 sensors # 每隔2秒执行sensors指令显示结果 "},"title":"Linux中获得AMD显卡的状态信息"},"/posts/210824-linuxtouchscreenfin/":{"data":{"":"一般Linux操作系统接入多个触摸屏的最终解!\n从21年3月中旬开始,我就在不断探索Linux操作系统下接入多个触摸屏且为拓展显示的解决方案,随着我们遇到的问题不断变得复杂,那篇博客也越来越乱越来越难读。直到今天我把里面最复杂的方案尝试成功后,我感觉我已经获得了Linux触摸屏的终极奥义。\n重要: 本文全文基于软件xinput\n更重要: 如简介所说,仍有一种方法无法对应,具体为【两个触摸屏的 VID:PID 与 设备描述 完全一致时,即两个完全相同的显示器】,本文内容对这种情况仍然是无解的,个人认为只能通过硬件端口(/sys/class)来进行识别与调整,本文不涉及该方法(还没吃透)。","0核心xinput#0、核心:xinput":"xinput是Linux下的一款配置测试X输入设备的神器,具有以下功能(我们将会用到的)\nxinput (list) : 直接键入xinput或者跟上list参数,就会列出本机所有输入设备,包括名称、ID、层级\nxinput list –id-only : 仅仅列出设备ID(序号,每次开机都可能改变)\nxinput map-to-output : 将输入设备映射到输出,比如将触屏映射到某个屏幕\nxinput list-props : 列出某个设备的详细信息,后接参数为设备ID。","1简约两个完全不同的触摸显示器#1、简约:两个完全不同的触摸显示器":"xinput map-to-output \"$DEVICE NAME A\" PORT-A\n这里对应了两种情况,一是VID:PDI和设备描述符都不同,即毫无关系的两款;二是具有相同的VID:PID,但是设备描述符,这一般是同款芯片配了不同的固件。\n首先通过xinput查看所有的输入设备:\n~$ xinput ┌ Virtual core pointer\tid=2 [master pointer (3)] |\tILITEK TLITEK-TP\tid=9 [slave pointer (2)] |\tILITEK Multi-Touch\tid=7 [slave pointer (2)] (下略) 可以看到ILITEK ILITEK-TP和ILITEK Multi-Touch显示为两个不同名称的设备,那么不论其VID:PID具体如何,我们都可以按如下方式进行映射:\nxinput map-to-output \"ILITEK ILITEK-TP\" HDMI-0\nxinput map-to-output \"ILITEK Multi-Touch\" HDMI-1\n这种方式的要点是1.必须带英文\"\",2.引号内名称须完整。map-to-output所携带的第一个参数为输入设备,不一定要设备id,使用设备名也是能够实现。","2复杂但通用vidpid不同的显示器#2、复杂但通用:VID:PID不同的显示器":"不论usb设备还是PCI设备,他们都有一个唯一识别符VID:PID,这相当于设备的身份证,同功能的设备,不同的厂商、不同的型号,就会有不同的ID。我们可以通过指定设备的VID:PID,筛选出输入设备的编号id,进行映射。\n通过xinput list-props [id]可以得到某个设备的详细信息,其中就有十进制的VID,PID,如果这两个参数可以和指定的对应上,那么我们可以提取id映射到屏幕。list-props的结果示例如下:\n(后续再补) 其中Device Product ID一项有两个值,但不像是16进制的VID:PID,经过换算,他们其实是十进制的。利用grep+awk指令筛选出这两个值,和预先设定的比较,确定设备的id。写出来就是这样子:\n#!/bin/bash # 先通过lsusb/xinput/xrandr 等命令确定如下硬件信息: # 1、屏幕VID:PID(16进制)和显示接口,多屏重复本段 VIDA=222a PIDA=0001 PORTA=VGA-0 # 2、先修算出10进制。如果xinput list-props [n] 的“Device Product ID”为16进制的,注释这2行 # 或者这里直接填写Device Product ID里面的结果,先VID后PID。 # 字母O,不是数字0,多屏重复本段 VIDA_O=$((16#$VIDA)) PIDA_O=$((16#$PIDA)) # =========自动处理步骤,请勿随意修改========== for I in $(xinput list --id-only) do # 根据设备ID取其序号 CUR_FIRST=$(xinput list-props $I|grep \"Device Product ID\"|awk -F : '{print $2}'|awk -F , '{print $1}'|awk '{print $1}') CUR_SECOND=$(xinput list-props $I|grep \"Device Product ID\"|awk -F : '{print $2}'|awk -F , '{print $2}'|awk '{print $1}') # 3、屏映射,多屏重复本段 if [ \"$VIDA_O\" == \"$CUR_FIRST\" ] \u0026\u0026 [ \"$PIDA_O\" == \"$CUR_SECOND\" ]; then xinput map-to-output $I $PORTA fi done exit 0 这个脚本使用xinput list --id-only仅列出了设备的id序号,然后轮询所有的设备找出符合要求的编号,最后仍然使用map-to-output进行映射。这个脚本易于扩展,如果多个触摸屏只需要将3个有序号的注释后面的一块内容重复、修改名字就可以了。","32的进阶版#3、[2]的进阶版":"前面都是通过shell/bash脚本的方式实现的重映射,如果要自动映射还需要添加自启动。如果设备进行了插拔,这个设备的映射就失效了,需要手动重新跑一跑脚本。我尝试了编写udev-rules文件,当触摸的设备发生变化时就延时启动映射脚本,但无一例外都是失败的,我觉得是udev生效的必xinput更早,无论延时多久都是这样。\n在银河麒麟操作系统中我发现了它提供的触摸映射方法,使用的是pyudev库,采用第三方的方法实现udev-rules的效果,而且在这里延时不会影响系统的加载顺序,只需要系统额外安装python3+pyudev,并且使用desktop文件在开机时启动,即可。\n#!/usr/bin/python3 # -- coding: UTF-8 -- # -- Author: Blues -- import pyudev import os context = pyudev.Context() monitor = pyudev.Monitor.from_netlink(context) monitor.filter_by(subsystem='hid') for device in iter(monitor.poll, None): if device.driver != \"hid-multitouch\": continue if device.action == \"add\" or device.action == \"change\": os.system(\"/var/my-touchscreen/remap-screen\") 上面直接贴了麒麟自带的代码,就修改了一下脚本的路径,经过多次验证,在uos下可以正常使用。借此机会我也参照麒麟的代码修改了一下,用户不用看命令行那些多余的东西,只需要点击几个GUI窗口,程序就可以按照设备名、VID、UID、物理接口四大特征,自动映射到对应的显示屏上了。"},"title":"Linux处理多触屏的终极解决方案"},"/posts/210914-linuxbackupdd/":{"data":{"":"害,谁不是个DD (誰でも 大好き)了呢!\n但是这玩意儿太慢了。。。","dd备份#DD备份":"dd if=/dev/sda of=/dev/sdb\t=\u003e 备份整个磁盘到另外一个磁盘 dd if=/dev/sdb of=sda.img\t=\u003e 备份整个磁盘为某个文件 dd if=/dev/sda | gzip \u003e sda.img =\u003e 备份并且压缩 dd if=/dev/sda bs=1M | gzip \u003e sda.img\t=\u003e 指定块大小,备份并压缩(据说能提速)","dd复原#DD复原":"dd if=/dev/sdb of=/dev/sda\t=\u003e从另一个磁盘恢复回来 gzip -dc sda.img | dd of=/dev/sda\t=\u003e从压缩的文件恢复出来 gzip -dc sda.img | dd of=/dev/sda bs=1M\t=\u003e前面指定了块大小,这里也需要","dd说明#DD说明":"dd指令是一个简单的复制指令,它不管源和目标的编码、格式、数据结构,简单粗暴的把二进制数据从A复制到B。所以恢复的目标硬盘甚至不需要提前分区,因为dd会把分区信息也写入。\ndd指令依然是有多少数据占多少空间,所以我们可以使用gzip进行压缩。具体代码后面贴出来。\n实际使用中,发现dd指令除了方便,就没有其他优点了。它因为要读取硬盘所有数据(包括垃圾数据),即便用SSD,读盘速度还是会很慢,三刻钟才读了200GiB数据,平均75MB/s,而使用uos自带的deepin-clone,三个系统都备份完了。","参考#参考:":"本文参考(抄)了以下内容:\nLinux 下使用 dd 和 gzip 命令来代替 Ghost 做磁盘镜像\nlinux dd实现磁盘完整全盘镜像备份backup,恢复recover(restore)\n还有一些查找过程中作用不大的页面,就不贴出来了(诶嘿(╹ڡ╹ )","起因#起因":"使用UOS的时候经常需要备份镜像并分享给其他部门或者办事处的人。传统的方法是进入系统自带的Recovery分区,打开备份软件制作镜像,但是这存在两个问题:A. 镜像特别巨大,系统多大镜像就占多大。B. 必须先拥有系统,才能恢复镜像。最新版的系统中已经去掉了Recovery分区,而LiveCD镜像还不是很好用,于是有了这篇博客,试图寻找一个简单的方法来进行恢复和备份。"},"title":"使用dd指令备份和恢复Linux系统(硬盘级)"},"/posts/210914-mdadm/":{"data":{"":"解决Linux系统异地恢复后开机mdadm报错导致开机时间变长。","从这儿抄的#从这儿抄的:":"W: mdadm: no arrays found in config file or automatically导致开机变慢的解决方案(deepin)","方案#方案":"步骤一:删除mdadm.conf\nsudo rm /etc/mdadm/mdadm.conf 步骤二:生成新的mdadm.conf\nsudo update-initramfs -u ps:如果是swap分区问题导致等待90s开机慢,不归这儿管。","现象#现象":"使用deepin-clone恢复UOS镜像后,开机会不断跳一条日志:\nmdadm: no arrays found in config file or automatically 大概蹦个15条后,系统才真正开机。mdadm好像是一个磁盘raid管理工具,当磁盘变化后其配置也不适配了,必须等到超时才会加载默认配置。那么我们就为其生成一个新的配置即可解决问题。"},"title":"Linux恢复操作系统后mdadm导致开机变慢的方法"},"/posts/210928-rpm_package/":{"data":{"":"Linux如Centos使用的RPM打包方法。本文仅涉及二进制打包,且采用取巧的方法简化操作。(笔记,而非教程)\n正文开始"},"title":"RPM安装包制作方法"},"/posts/211019-dpkg_package_guide/":{"data":{"":"简单介绍deb打包的方法,包括目录树格式和打包注意事项。","control#control":"control文件用于写入安装包的识别信息,包括包名、版本、作者、简介等。没有严格的顺序要求。表格中列出常用的关键字和作用,图片展示了一个软件包的control信息。control文件最后需要添加一个空行。\nNAME Description Package 软件名,dpkg -l 列出的名字 Version 版本号-修订号 Section 软件类型,比如mail, test, x11等 Priority 优先级/重要性,比如optional 可选的 Architecture 软件架构,比如x86, arm64 Depends 依赖环境,用 , 隔开,用(\u003e=\u003c )指定版本号 Suggests 推荐安装,指非必要依赖,可以提供更多功能 Maintainer 作者 \u003c邮箱或者其他联系方式\u003e Descritprion 简介,可以换行书写","debian#DEBIAN":"DEBIAN目录下有一个control文件和至多四个脚本文件。","md5sums#md5sums":"为了防止安装包被篡改,可以计算每个二进制文件的md5值存放在这个文件里。非必要。","其他信息#其他信息":"一般公开发行的安装包应该包含其他信息,如版权信息、changelog、doc、man手册等。这些文件都有各自的编撰格式,主要是为了方便系统识别和二次开发,与用户直接体验无关。","打包#打包":"所有文件配置完成后,进入工作空间上级目录,执行指令\ndpkg -b ./PackageDIR packagename.deb deb包命名的一般规则为 软件名_版本-修订号_架构.deb","文件结构#文件结构":"首先创建一个目录作为工作空间,目录名可以使用软件名,deb包所有文件都将会存在这个目录下,这个目录就是安装时的根目录/。一个工作空间的目录树如下:\nPackageDIR\r├─DEBIAN\r├─opt\r│ └─kushidou-touchscreen\r│ └─desktops\r├─usr\r│ ├─bin\r│ └─share\r└─var 其中,DEBIAN目录放置了安装包的信息、配置、控制文件等,其他文件都放在目录的相对位置里,安装时就会根据这些相对位置,把程序与文件直接拷贝到对应的地方。","额外脚本#额外脚本":"DEBIAN目录下之多放置四个可执行脚本,包括安装前preinst、安装后postinst、卸载前prerm、卸载前postrm,四个脚本都需要以#!/bin/bash开头,内容与普通脚本无异,文件名不需要后缀。\n这些脚本主要实现复制快捷方式、建立软连接、添加环境变量、添加额外的文件和配置等操作。这些脚本是以root身份运行,注意他们创建文件的访问权限。inst创建的文件无法被dpkg删除,需要使用rm脚本自行处理。\n此外postinst可以用来启动已安装的程序,prerm常用来停止正在运行的程序。"},"title":"DEB打包方法简介"},"/posts/211115-fixnasdriver/":{"data":{"":"更新家里的NAS,手滑把原来NAS硬盘的分区信息删掉了。如何拯救盘里的数据?\n图片稍后补充。","v-0-起因#v 0 起因":"双十一买了两块新的4T紫盘,打算升级一下家里的黑群晖。原来黑群晖是用一台N手工控机+1TB希捷笔记本硬盘(看缓存和速度肯定是SMR盘了),数据安全几乎为0.\n考虑到小工控机的电源带不动那么多硬盘,机箱也没有空间,就把家里闲置的i3台式机整了过来,拆掉原来的硬盘装上紫盘组新nas了。顺手拆了一个捡来的监控机上的1TB西数紫盘。\n为了节约迁移系统和数据的时间,我打算拿两个sata易驱线,用DiskGenuies进行克隆。后来网上冲浪发现群晖系统是认硬盘SN的,也就是说我克隆的数据没有一丁点用,加上手头上没有2.5转3.5的转接件,就考虑把笔记本盘放回老nas,然后直接拷贝或者备份到新nas。","v-1-曙光#v 1 曙光":"群晖使用的BTRFS格式不是什么群晖专用格式,而是SUN(Oracle收购)开发的新一代文件系统,针对ext3/4进行优化升级。所以比较新的Linux系统都支持使用这个格式;装个驱动也能轻易读取。\n我本来笔记本是有Deepin系统的,上次win10损毁了我就格掉装了win11。后来想起来我还有块树莓派正跑着linux系统。但是没有分区的硬盘上了Linux也啥都读不到。恰好这时候新nas的系统已经起来了,1T紫盘上的独立分区也建立好了。两款空间一样的盘,同样版本的群晖系统,建立一样的存储空间后,那不就是连分区也一模一样了么?!\n开搞,ssh连上群晖,用sudo blkid看到硬盘实际的分区信息,它正好是显示的扇区起止、大小。打开DG,手动分区,按照群晖的磨样给小硬盘手动分区。DG不支持btrfs分区,那我随便挂一个ext4吧。分区过程和保存的时候,千万不要格式化了。\n把小硬盘用易驱线连上树莓派,lsblk看到这个硬盘有三个分区,其中/dev/sda3下面还有一个md127,不知道是啥,查看发现是raid。群晖的数据区,哪怕是单盘basic也是以raid方式存在的,方便以后升级raid模式吧大概。也就是说,虽然我分区表是瞎分的,Linux还是能够正确读取到原来的分区和文件系统。","v-1-杯具#v-1 杯具":"当我按下取消的时候,惨剧发生了。其实整盘克隆的时候,DG会删除所有分区,克隆完了再重建分区。我取消克隆,然后退出DG。它提示我是否保存分区更改,我以为是1T紫盘的分区,顺手点了个否。当我重启DG的时候,发现希捷笔记本盘只剩一条灰色,未分区的区域。","v-2-尝试#v-2 尝试":"DG有个功能是搜索重建分区表,我第一时间进行搜索。此时还没有网盘内写入任何内容,也没有格式化。数据应该是都在的,只要按照原来的样子重新分区应该就能重新读写数据了。\n为什么不手动分区?因为群晖会在硬盘上先建立一个系统分区,然后建立swap分区,空一段空间后再建立数据分区。每个分区开始和结束的位置都是未知的,网络上也没有可以参考的内容。\n经过一个多小时的搜索,除了第一个2.4GB的系统分区被找到以外,一无所获。我怀疑是不是我期间制作黑裙启动盘影响了,又搜索了一遍,好家伙还是没有。\n搜索期间网上冲浪找前人的肩膀,结果他们要么是分区没被删直接装Windows下btrfs驱动(gitee开源)读取(群晖坏了),要么是DG轻松搜出全部分区(和群晖无关)。我还尝试查找丢失文件,依然一无所获。\n难道就这么放弃了么?","v-2-得到数据#v 2 得到数据":"安装mdadm软件包,我的树莓派不带这个,然后就能挂载raid盘了。\nsudo mount /dev/md127 ~/disk disk目录提前建立好了,把机械盘挂载上去,cd到目录里,然后我就发现了新世界的大门。盘里有个NasData目录,这正是我当时保存文件的地方。cd进去,在!都还在!","v-3-移动数据#v 3 移动数据":"我打算直接把就数据拷贝到新NAS里去了,烤到移动硬盘再复制到nas大费周章的。\n在NAS里的主共享文件夹启动NFS服务,映射为root,允许所有来源的读写,然后到树莓派中挂载nfs\nsudo mount -t nfs 10.x.x.x:/volume2/NasData ~/Nasdata 主目录下提前建立Nasdata目录,挂载完成后新Nas的内容也都出现了。不想一个个复制文件,CP指令不支持排除不想要的文件(毕竟还有部分文件依然保存在移动硬盘和笔记本里,树莓派只支持2.4GHz的wifi太慢),最终我选择了rsync指令进行“本地复制”。\nrsync -vrultD --exclude '文件名' --exclude '目录名' ~/disk/NasData/* ~/Nasdata/临时目录 # -v 详细输出 -r 递归拷贝(保留目录结构) -u 仅更新,防止中断再开后重新拷贝 -l 保留软连接 -t 保留时间信息 -D 保持设备文件信息 # 不用-a 是因为对拷过去的文件赋权限时疯狂报错失败 经历树莓派三次死机两次中断后,我终于抢救了500G数据中的50G(另外450包括百度云同步、移动硬盘依然保存着的动漫视频等)。","v-4-结论#v 4 结论":"现在数据和小姐姐们都住在一个raid1备份的空间中,应该轻易不会发生无家可归的情况了。\n这次事件完全是我自己作死,群晖其实提供了备份功能,可以完整的把数据、部分设置乃至我的Docker容器都完整备份到新NAS里(只要两台都在线),而且树莓派的wifi只有5MiB/s,比起家里千兆的内网,速度慢了数十倍,时间也花了我整整一下午。\n总之硬盘出了事故不要慌,只要不是物理损坏,都有机会修复。除了事故后第一时间就要停止读写,更不要格式化,先尝试重建分区表,失败了换个系统试试。说不定我不重建,放到Linux上也能看到正常的三个分区呢?"},"title":"记一次拯救NAS硬盘"},"/posts/211203-linuxchangeusername/":{"data":{"":"如何在Linux下完整修改当前用户名和主目录,还不影响其他文件?\nLinux的用户名是一个用户的字符串表示,是可以修改的。只要用户的id不改变就不会被系统认作新用户,所有的权限都可以继承。下面介绍如何修改用户的名称、所属组,并更改主目录的名称与对应关系。","一进入单用户模式#一、进入“单用户模式”":"为了修改用户名时不影响程序运行,需要把当前用户打开的所有程序都关闭。该方法可以快速注销当前用户。\ninit 1 执行后输入当前用户密码 进入黑屏终端后需要输入root密码,可以使用sudo passwd 提前设置 对于屏蔽init指令的系统,一般情况下注销用户就可以了,但是有些GUI桌面环境就是以当前用户的身份运行的,所以提供如下几个方式关闭当前用户,挨个尝试即可。\n# 1 桌面环境中点击注销 # 2 杀掉当前用户所有进程 pkill -kill -u old_name # 3 杀掉进程后可能桌面重启,关闭Lightdm管理器 # Ctrl + Alt + F2 进入第二页面,以root用户登录(可能需要提前设置root密码) systemctl stop lightdm # 然后再次执行第二步","二修改信息#二、修改信息":"init 0可以直接进入黑屏的终端,或者使用 ctrl + alt + f2进入(远程连接可以),以root用户登录。\n# 1 修改组的名称 groupmod -n new_name old_name # 2 修改用户名 -l 改名字 -d 改目录 -g 改组 usermod -l new_name -d /home/new_name -g new_name old_name # 3 修改主目录 mv /home/old_name /home/new_name 最后回到图形化界面,输入init 5 ,或者重启电脑。\n修改完主目录后记得检查是不是有其他软连接指向旧目录,需要进行更新,否则还会遇到问题。","参考#参考:":"# linux用户家目录怎么修改,Linux 更改用户名,用户组和主目录\n# 菜鸟教程-usermod指令\n# linux组的管理:修改组名字,删除组,使用sudo权限"},"title":"在Linux环境下修改用户名和主目录"},"/posts/220104-diylinuxiso/":{"data":{"":"想要在原版的Linux镜像上添加自定义的软件,但是不想、不会编译,那么就可以基于Linux的iso文件进行修改,定制自己的安装试用镜像。\n起因是因为对付信创操作系统的备份恢复时,UOS、麒麟自带的工具都超级不好用,两个系统的镜像不统一,导致实际使用的时候各种问题和不方便。所以使用clonezilla再生龙工具自己做一个PE镜像。这个镜像不仅可以备份、安装系统,还能够修改硬盘大小、应急拯救系统等多种功能。并且它是一个完整的系统可以安装使用。","基本计划#基本计划":"之前尝试过使用deepin魔改lub工具制作系统的完整镜像,但是启动总是失败。LUB全称是Live Ubuntu Backup,是Ubuntu的一个工具,到了同为Debian系的deepin魔改的UOS上就水土不服了。(好绕,套娃呢搁这儿\n所以采取另一种办法,用已有的Linux iso,通过解压其系统文件filesystem.squashfs,然后替换关键文件,最后实现自定义系统。","解压修改打包linux文件系统#解压、修改、打包Linux文件系统":"首先把Linux iso挂载到系统中。把里面的filesystem.squashfs文件复制出来(因为iso是只读的,复制出来后也方便管理和备份)。我这里以UOS1040为例,其文件系统在./live目录下\nsudo mount -o loop /xxx/xxx.iso /media/usrname/isofolder cd /media/usrname/isofolder/live/ cp ./filesystem.squashfs ~ 安装squashfs-tools工具,用来压缩解压归档文件。\nsudo apt install squashfs-tools #回到主目录后,解压filesystem.squashfs文件 sudo unsquashfs filesystem.squashfs 解压后可以看到主目录多一个squashfs-root目录,里面存放的就是一个Linux的文件系统了。这时候把你需要的文件拷贝进去,比如我替换了/usr、/opt、/etc三个目录,这三个目录保存了我安装的clonezilla应用及其配置程序,以及我编写的辅助脚本和自启动脚本。\n修改好了就可以打包了。第一个参数是刚刚解压出来修改好的文件系统,第二个参数是输出的名称。建议把之前拷贝出来的squashfs文件改名进行保存。\nsudo mksquashfs squashfs-root/ filesystem.squashfs","重建linux-iso#重建Linux iso":"最后我们需要重建ISO文件。由于我们是基于原来的ISO修改的,所以只需要替换iso里面的filesystem.squashfs文件即可。否则还需要更换系统内核img/lz、重写引导。\n把新生成的filesystem.squashfs文件拷贝到Windows系统里,打开UltraISO软件,直接替换Live目录下的filesystem.squashfs文件。同时我们也可以修改EFI/grub.cfg文件,毕竟这个系统主要是使用而不是安装。我调换了安装和试用的次序,并把等待时间增加到60s。\n最后进行修改ISO名称等小操作,保存为ISO文件就可以了。\n新生成的ISO文件既可以用rufus等工具烧录到U盘中制作PE盘,也可以试用ventoy工具制作成多系统启动盘,甚至可以烧录一张光盘来使用。"},"title":"定制自己的Linux ISO镜像"},"/posts/220223-deepin_partsinddefilemanager/":{"data":{"":"Deepin/UOS 里处理文件管理器显示太多盘符的问题。","原理原因#原理/原因":"这是因为系统/etc/udev/rules.d文件夹做了非法修改。有些人盲目替换了文件夹文件,导致配置文件变化,系统无法正确执行隐藏操作。","处理方法#处理方法":"打开/etc/udev/rules.d目录,查看是否有一个《80-udisks2.rules》文件。如果该文件不存在,请创建。\n打开终端,使用root权限打开编辑\nsudo deepin-editor /etc/udev/rules.d/80-udisk2.rules 打开新的终端,输入执行 blkid -f ,记录LABLE、UUID两列\n\t对比80-udisks2.rules的内容,将里面的ENV{ID_FS_UUID}后面引号中内容换成第3步中显示的新的UUID。\n(#号后面内容即为盘符,对应3中的LABEL,双等号后面就是UUID,四行都需要替换)\n\t保存文件并重启计算机,即可看到效果。\n该方法对Deepin系统也有效。对于其他使用了dde-file-manager的应该也是有作用的。","现象#现象":"在使用UOS操作系统时,有时候打开文件管理器,发现除了平常常见的“系统盘”、“数据盘”外,出现了更多的盘符(不属于移动u盘)。在/etc/fstab文件添加或删除“”并没有效果。"},"title":"Deepin/UOS文件管理器隐藏不需要的盘符"},"/posts/220714-unpackclonezillaimage/":{"data":{"":"从clonezilla的镜像直接提取文件,免于先全盘全区恢复。\n再生龙(clonezilla)是一个常用的Linux系统备份工具,适用于多个版本、多种CPU架构的电脑。\n再生龙生成的镜像是比较特殊的格式,如果想要从里面提取文件,通常只能进行镜像恢复后进入系统提取。但是往往我们没有那么多硬盘来恢复系统。\n再生龙的原理简单来说就是把硬盘分区使用partclone工具打包成img文件,然后使用gzip进行分卷压缩。我们只需要逆向操作,利用工具,把镜像解包挂载,直接在当前系统挂载,就可以得到原分区的文件了。","1-环境需求#1. 环境需求":"我们操作再生龙镜像时,最好是使用Linux环境。这个环境中,需要安装partclone(也就是再生龙生成镜像的核心工具)。\nsudo apt install partclone # 以Debian系为例 并且我们需要准备一个足够大的硬盘,用来存储镜像包和解包出的img文件。硬盘/分区的空间需要大于镜像本来的分区空间。","2-合并镜像#2. 合并镜像":"再生龙默认情况下会把一个硬盘分区分按4GB的大小进行分包,通常以gz.aa、gz.ab等结尾,我们需要把这些包重新整合成一个gz包。\n整合成gz包后,我们就可以解压gz来得到镜像img了。我们可以把两个步骤用流的方式写入一条命令,节省硬盘空间。\ncat sda1.ext4-ptcl-img.gz.* | gzip -d -c \u003e sda1.img 这一步生成的img文件不能直接使用(google上也有说能用的,但是我试下来不能),需要进行一次转换。经过实际操作,这个文件所占用的空间是镜像原分区的大小,但是统计硬盘使用量时却只计算实际大小,希望了解的人可以帮忙解释一下。\npartclone.extfs -r -s sda1.img -o sda1-ex.img --restore_raw_file 当然上面两条指令也可以使用流的方式再次封装到一条,但是消耗的时间、失败后重新来过的时间,都会更长。","3挂载镜像#3.挂载镜像":"将最后生成的img镜像挂载到我们的/mnt(或其他)目录,进入这个目录就可以看到原来全部的文件了。\nsudo mount -o loop -t ext4 sda1-ex.img /mnt 最后我们只需要进入 /mnt 目录,就可以想直接操作硬盘一样把文件复制出来了。","挂载方法#挂载方法:":""},"title":"从再生龙(clonezilla)镜像直接提取文件"},"/posts/230508-remake-deb/":{"data":{"":"Debian系操作系统采用dpkg作为包管理器,在安装软件后会存储deb包信息,是否可以提取这些信息并且重新打deb包转移到其他平台使用?\n之前有一个需求,要从UOS里面提取一个软件,并且将其安装到另一台设备中。当时找了一圈都没有找到相关的提取教程。但是从逻辑上来讲,dpkg安装的软件会保存deb包的相关信息,所以理论上讲是可以提取出软件包的所有内容,然后我们重新打包的。\n今天在一个机缘巧合下(其实是懒得研究dpkg原理,瞎猫撞上死耗子),发现了dpkg保存文件信息的地点,于是接下来可以展开畅想:提取已经安装的软件并重新打包。","局限性#局限性":"以上毕竟只是设想,没有进行试验,所以估计会出现这些问题,希望有需要的人尝试后可以解决。\n提取信息的难度: 由于/usr/lib/dpkg-db/status文件是一个包含几乎所有deb信息的文本文件,体积大内容乱,对于自动化脚本来说有些难度。加上一些软件的衍生品会在软件名上直接加后缀,对于提取的脚本来讲可能造成混淆,提取出不必要的东西。\n获取源文件的难度: 不排除一些软件安装时会删除、修改自身的一些文件,可能打包会后会缺失内容。一些软件安装过程中会进行手动配置从而造成内容改变,重做出来的软件包不一定完整。\n签名问题: 我们打包的软件没有原作者的数字签名,可能无法安装,也可能时候安装官方软件时冲突。\n这个方案只能处理普通的软件,一些deb打包源码,安装时进行编译的,应该是不能用这种方案复原的。(apt的deb-src源)\n最后,希望有大佬可以验证一下这个方案。","文件的保存地点#文件的保存地点":"我在找fcitx有关的配置文件进行全盘搜索的时候,找到了一条目录/usr/lib/dpkg-db/info,这个目录里面保留了fcitx的\"conffiles\", “md5sums”, “postinst”, “prerm\"四个文件,以及一个list文件。恰好fcitx.deb解包出来的DEBIAN文件夹内也是这四个文件加上额外的control文件,。\n那么合理猜测,dpkg安装软件的时候,不仅把软件本身的文件移动到对应位置,还把DEBIAN里面的信息和脚本也转移到/usr/lib/dpkg-db/里面保存了。\n而fcitx.list文件中记录的是所有的文件及其路径。想必这里面就是全部的文件了。\n至于control文件,则都被保存到了/usr/lib/dpkg-db/status这个文本文件中。","流程设想#流程设想":"既然deb包所有必要的文件都找到了,那么就可以尝试一下还原过程了。在这篇文章里我研究过deb包的组成、格式和打包方法。\n比如对于软件包A:\n创建一个工作目录,并在其中新建DEBIAN目录。\n将/usr/lib/dpkg-db/info中所有该软件的脚本和信息(除了A.list)转移到DEBIAN中,并重命名成规范名称。\n将/usr/lib/dpkg-db/status中与软件A有关的部分提取出来,保存到DEBIAN/control文件中。\n根据A.list文件,找到软件包含的所有文件,将其按原样整理到工作目录内。\n使用dpkg -b指令重新打包。"},"title":"讨论在Debian系操作系统中重新提取已安装的软件并重新打包"},"/posts/230908-py-post/":{"data":{"":"使用Python搭建简单服务器的时候,只能收到headers,收不到POST内容的情况\n最近做了一个简单的http服务器,用于接收IoT端上传的json格式的日志。\n服务端使用socket中的方法接收原始数据,再对原始数据单独进行处理,根据报文头部的GET或者POST等方法进行具体的操作。\nsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind((self.host, self.port)) sock.listen(128) (client, address) = self.sock.accept() th = Thread(target=self.accept_request, args=(client, address)) def accept_request(client, address): data = client_sock.recv(8192) req = data.decode(\"utf-8\") # 处理数据的具体方法 response = process_response(req, client_addr) client_sock.send(response) # clean up client_sock.shutdown(1) client_sock.close() 上面的代码是大概的处理流程。在这个流程中,我发现处理POST的数据的时候,经常只能收到headers部分,payload部分的数据不管发几次都是空的。而且接收缓冲区已经扩大到了8192字节,headers部分的长度只有200多字节,IoT端上传的payload也不过上百字节,不应该是超出缓冲区的问题。\n=====2024.01.04更新=======\n下面的方法突然某一天就失效了,我不清楚是不是python的环境变化导致的。\n其实用flask接收和处理数据会更加方便快捷:\nfrom flask import Flask, request # 实例化flask app = Flask(__name__) # 接收和处理post的方法 @app.route('/test', methods=['POST']) def recv_file_www(): # post的传入参数 print(request.args.to_dict()) # post所承载的数据 print(request.data) return 'OK' if __name__ == '__main__': app.run(port=31408, host=\"0.0.0.0\",debug=True) 上面就是一个完整的post接收和处理程序了,不需要调试socket,也不需要自己处理ResponseBuilder,最重要的是能保证获取到post数据。\n======以下是原来的内容==========\n经过网上搜索与自己尝试,发现socket.recv返回的时候是分段返回的,貌似会按照实际内容切割返回,必须不断的recv才能完整接收数据。有一种解决方案是POST传送之前先确定报文的完整擦换个年度,然后利用while循环,接收到对应长度才结束。\n但是POST发送的一个不定长的数据,如果每次都通过http报文先传送post完整长度的话,有些浪费资源。于是我想到了这么一个方案:\nPOST的报文头会包含一个Content-length的数据,记录的是payload的长度。那我在接收阶段就对headers部分进行解码和处理,获取到content-length后,在加上本次获取headers的长度就是POST的完整长度了。\n那么将上面代码的client_sock.recv()部分改写成下面的方法:\ndef recv(self, client_sock): lrecved = 8192 # 记录每次接收的长度 lrecv_all=0 # 记录数据总长度 data_body = bytes() # 接收的所有数据存入这里 payload_len = 0 # 解析的payload长度 payload_flag = 0 # 用于记录是否接收到了payload,以及实时记录接收到payload的长度 while True : part_body= client_sock.recv(8192) # 循环接收数据 data_body += part_body # 将接收的数据写入data_body lrecved = len(part_body) # 获取本次接收长度 lrecv_all += lrecved # 计算总长度 if payload_flag == 0: # 没有接收到payload部分时,才进入下面的判断流程 if data_body[0:3].decode() == 'GET': # 由于我get方法没出现过断开的问题,因此直接返回即可。 break elif data_body[0:4].decode() == 'POST': payload_len = count_payload_len(data_body) # 解析头部,计算payload部分的长度 if lrecved \u003c payload_len: # 偶尔会出现能接收到payload的情况,所以多加了一个判断。 # 能接收payload肯定总长度大于payload_len的 print(\"no payloads, keep recving...\") # 计算post报文的总长度,借用payload_flag变量 payload_flag = lrecved + payload_len # 当接收到的总长度 \u003e= POST的计算长度,表示所有数据接收完成,退出 if payload_flag \u003c= lrecv_all: break return data_body 里面解析headers的代码如下:\ndef count_payload_len(data): for d in data.split(b'\\r\\n'): # 通过\\r\\n来分隔报文头 if \"LENGTH\" in d.upper().decode(): # 如果报文头部有length关键词,当然可以写完整,我的heasers没有其他的length就简化了 return int(d.decode().split(\":\")[1]) # 分隔出payload长度并返回 return 0 上面的代码其实写的很复杂,因为我解析POST整体报文的功能已经写完并且通过第三方http报文调试工具验证过了,上IoT设备实验的时候才发现了问题,本着少改一点是一点的原则,就把这一部分复杂化了,但确实解决了我的问题,就OK了。\n对了,这篇博客就是利用这个这个方案改造的新服务端进行上传同步的,之前用GitHub Actions进行同步博客,每次运营商都会发一条高危访问的短信和邮件通知我,太烦了。"},"title":"Python socket 收取POST协议内容时没有payload"},"/posts/231127-vncserver/":{"data":{"":"(笔记)在Linux系统里安装远程桌面VNC客户端并连接。","1-安装nvc服务端#1. 安装NVC服务端":"sudo apt install x11vnc","2-设置远程连接密码#2. 设置远程连接密码":"x11vnc --storepasswd # 输入两次连接密码以设定 # 询问 Write password to /home/xxx/.vnc/passwd # 时,输入y并回车保存密码。 该步骤不需要使用sudo!","3-使vnc服务开机自启动#3. 使VNC服务开机自启动":"使用service的方法,将vnc作为一个服务开机启动\n创建/lib/systemd/system/x11vnc.service文件并填入下面的内容\n[Unit] Description=Start x11vnc at startup. After=multi-user.target [Service] Type=simple ExecStart=/usr/bin/x11vnc -auth guess -rfbauth /home/xxx/.vnc/passwd [Install] WantedBy=multi-user.target 注意,/home/xxx 需要替换成实际的用户名!","使用vnc客户端连接#使用vnc客户端连接":"我使用Windows上的VncViewer,官网RealVNC,这个软件假冒的很多,下载需要注意甄别。"},"title":"Linux安装VNC服务端"},"/posts/231225-dockernote/":{"data":{"":"学习docker,使用docker,编写docker","docker-compose#docker-compose":"docker compose是通过ymal配置文件来启动容器的,它支持将多个容器组合启动,并自动处理依赖关系。在docker compose中我们不需要拉取镜像,直接在配置文件中指定镜像名,在启动后会自动拉取。\n首先创建一个工作目录,并创建一个docker-compose.yml的文件,默认情况下docker compose指令只认这个文件名。\nversion: '3'\rservices:\r[NAME1]:\rimage: \"image/name\"\rports:\r- 81:80\r- 8080:8080\renvironment:\rHOSTNAME: \"cc\"\rPORT: 8181\rvolumes:\r- nginx-data:/etc/nginx\r[NAME2]:\rimage: 'xxx' docker compose的ymal文件可以实现十分复杂的功能,我暂时也没搞懂,就只放一个基础结构的文件在这里。与docker run指令相同,ports字段指定了内外端口的映射,即’外部:内部’,卷映射同理。environment不需要 - 开头。\n编写完ymal文件,就可以启动容器组了。首先切换到文件所在的目录,即工作目录,然后执行指令直接启动\ndocker compose up 启动容器,查找当前目录下的ymal文件。-d 参数可以转入后台运行。 -f参数可以指定ymal文件。\ndocker compose down 停止容器,并删除对应的容器和网络\ndocker compose exec NAME command 在ymal文件内其中一个容器里运行指令\ndocker compose指令必须是要有ymal文件才能运行的,它通过这个文件来寻找有关的网络和容器。\n目前浅学了一下,只有学一点更新一点吧。","docker-基本使用方法#docker 基本使用方法":"使用一个docker镜像的步骤是【拉取镜像、创建容器、运行容器、停止容器】,一般创建和运行通过同一条指令实现。\n# 拉取一个镜像 docker pull xxx/yyy # 创建容器并运行 docker run --name aaa xxx/yyy # 停止容器 docker stop docker-id 关于运行容器,有很多常用的参数:\n-d 容器转入后台运行\n-e 设置容器的环境变量\n–name 容器名称\n-p 80:80 将暴露的端口映射到容器内端口,外部:内部\n-v f:c 将一个文件(卷)映射到容器内部的文件,支持文件和文件夹。外:内\n-e、-p、-v 参数都可以多次使用,达到添加多个变量的目的。\n停止容器支持多种类型的参数,包括容器ID和容器名称。容器ID可以只写出部分,能够区分容器即可。\n查询容器id,可以使用指令docker ps。docker还有其他几个查询和控制指令\ndocker exec 容器 指令 允许在外部执行docker内的指令,添加 -d 参数转入后台运行。\ndocker ps 列出正在运行的docker容器信息。添加 -a 参数查看所有容器,包括已经停止的。\ndocker images 列出已经下载的镜像列表。与 docker image 指令不同。\ndocker kill 容器名/id 杀死一个无法stop的容器\ndocker rm 容器 删除一个容器\ndocker rmi 镜像名 删除一个镜像\ndocker restart 容器ID 重启一个容器,毕竟我们不需要每次都创建新容器。\n关于docker运行时需要哪些端口,可以通过镜像的docker hub页面进行判断。","前言#前言":"祝自己圣诞节快乐,去年的愿望是“明年不要一个人过圣诞”,今年的愿望也是“明年不要一个人过圣诞”。\n不扯了,docker,又称容器,是一种高效的虚拟化技术,能够在不启动虚拟机的情况下,创建一套虚拟环境,方便调试程序,配置环境,乃至直接抄别人的配置。docker还有一个进阶的docker compose,支持多个容器之间组合互联组成一套完整环境。\n由于docker比较复杂,又没有官方支持的gui界面~~(在官网看好像有了?但是就当他没有吧。)~~;中文环境的文档、教程都冗长复杂不想看,因此docker一直是我学习路上的一个绕路点。今天打算突破它,记录最简单的docker指令和方法。","安装docker和docker-compose#安装docker和docker compose":"虽然阿里ECS之类的云主机大多预装了docker,但是海外主机、自己装的linux系统大多还是没有docker的,我们从安装开始。以ubuntu为例。\napt仓库提供的docker-io等软件包是社区构建的非官方版本,要安装官方版,需要多几个步骤。\n# 添加docker官方的gpg curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg # 在/etc/apt/source.list.d 里面添加docker的源地址,借用官网的一行指令直接添加 echo \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release \u0026\u0026 echo \"$VERSION_CODENAME\") stable\" | sudo tee /etc/apt/sources.list.d/docker.list \u003e /dev/null # 我这边添加的结果是 deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu jammy stable 然后可以通过apt源安装docker了\nsudo apt update sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin *注意,上面的指令同时安装了docker-compose。如果不安装docker,直接安装docker-compose也是可以的。\nwget https://github.com/docker/compose/releases/download/v2.5.0/docker-compose-linux-x86_64 sudo cp ./docker-compose-linux-x86_64 /usr/bin/docker-compose 更加具体的步骤和细节可以到官网查看:docker安装、docker-compose安装","更换docker镜像源#更换docker镜像源":"和apt源、github一样,docker镜像源服务器在国外,国内访问可能很慢,遇到这个情况可以更换成国内的镜像源。\n修改/etc/docker/daemon.json文件,添加下面的内容:\n{ \"registry-mirrors\": [ \"https://docker.mirrors.ustc.edu.cn\" ] } 编辑完成后需要重启docker服务。\n具体的源地址可以进行搜索和尝试,我访问速度还行就没有更换。"},"title":"docker简单笔记"},"/posts/about_hugo_website/":{"data":{"hugo的安装与首次创建#hugo的安装与首次创建":"安装使用chocolatey,一个windows下的仿apt、yum的软件包管理器。安装好chocolatey后,根据hugo官网的内容,choco install hugo -confirm安装基础的hugo(好处是不用再配置环境变量了)。\n为hugo创建目录,进入后hugo site new website,hugo会自动建立它所需要的层级结构。\n添加第一个页面,`hugo new xxx/xxx.md’,创建的内容会出现在content下,创建多级目录也适合将来归类。","主题皮肤#主题/皮肤":"主题放在themes下,我在知乎上找到了一个高赞且顺眼的,有哪些好看的Hugo主题? - 飞雪无情的回答 - 知乎,文章中附了github连接,那么我们直接git过来就完事了。","关于使用hugo建立博客#关于使用HUGO建立博客":"使用hugo建立本站的规划和记录。\n关于使用HUGO建立博客在经历了worldpress的性能消耗和慢速加载后,我现在决定换用hugo+caddy的建站模式。昨天已经完成了caddy2的基础设置,现在开始测试使用hugo。","生成网站#生成网站":"文章+主题都有了,现在可以生成第一个网站了(虽然写这些字的时候,网站还没生成)。hugo就能直接产生网页,保存至public文件夹。hugo server可以启动一个服务器预览静态网页。","编写文章#编写文章":"hugo的文章是基于markdown文档的,创建的文章会自动加入以下抬头\n--- title: \"$文章标题\" date: $时间 draft: true --- 这个可以修改为json或ymal格式,理应可以添加更多项目,这个之后再研究。"},"title":"关于使用HUGO建立博客站点"}} |