﻿17年圣诞节网站的服务器出现问题需要使用引导盘进入救援模式, 奈何随身带的两个引导盘(Ubuntu 16.04 和 CentOS 6.8)都不能引导服务器, 反倒是后来找到的一个使用PE工具刻录的Windows PE盘能正常引导并启动, 联想到机器是06年的老古董, 遂决定自己制作MBR引导的启动盘. 1. 选择操纵系统加载引导器 有很多的系统引导加载程序都支持MBR引导, 所以针对不同的操作系统, 可以有多种不同的引导加载器可供选择, 例如Windows系统可以使用NTLDR、grub2、grub4dos等等, Linux系统则可以使用isolinux、grub2、grub4dos等等, Hackintosh的引导加载器只有变色龙支持mbr. 我个人选择的是grub4dos 2. 将系统加载引导程序写入mbr扇区 工具 : 在Windows上使用工具bootice(下载地址请百度之); 在Linux上可以使用grubinst(针对grub4dos)、bootlace.com(针对grub)、grub-install(针对grub2)甚至dd(大胆的想法), 总之Linux环境下要比Windows麻烦就是了. 实操: Windows下使用bootice很简单, 以grub4dos为例: bootice主界面如下图示: 在目标磁盘选择要操作的磁盘(U盘或硬盘自己看着办) 点击主引导记录, 如图示: 可以看出我的U盘已经安装过grub4dos, 务必确认目标磁盘是要操作的磁盘 选择grub4dos并点击"安装/配置" 具体配置自行决定, 对于不明白的选项可以大胆尝试, 数据丢失这种小事请自行承担后果. 配置完之后点击"写入磁盘" 安装成功: Linux下建议自己大胆去飞, 不多言. 注意: 只有将引导加载程序写入了mbr扇区它才能被BIOS引导并发挥作用. 一般来说, 小小的mbr扇区是无法完全容纳操作系统引导加载程序的, 所以很多引导加载程序只是在mbr分区写入了一小段"加载代码", 真正的引导加载程序往往放置在某分区根目录下. 3. 复制引导加载程序主体 如上所述, 我们还需要将引导加载程序的主体程序放置在合适的位置(例如将GRLDR放置在启动盘某分区根目录下). 以grub4dos为例: 首先到grub4dos下载页面下载grub4dos. 找到grldr文件并将其放置到启动盘的根目录下 4. 将镜像文件提取到启动盘 提取并不是刻录, 只需要将镜像文件挂载(或者使用某些解压软件, 如7zip/bindzip/好压)然后将文件复制到启动盘的合适(随意)位置即可. 5. 制作引导加载器的配置文件 这一步可以说是比较难的一步了, 因为这一步涉及到启动加载器对应的命令、操作系统启动过程等多方面的知识. 不过对于一个封装好的发行版操作系统, 即使不了解这些知识也可以制作配置文件, 以CentOS 5.11 + grub4dos为例: 1. 找到CentOS 5.11的iso镜像文件(下载地址) 2. 打开iso文件, 找到它的引导加载器配置文件 CentOS 5.11 iso文件的引导加载器目录在 /isolinux/isolinux.cfg 它的启动引导加载器是isolinux, 因为我用的是grub4dos, 所以需要一定的"移植" 打开此文件, 关键配置内容如下: label linux kernel vmlinuz append initrd=initrd.img 3 制作适用于grub4dos的配置文件 这一步必须了解grub4dos的常用命令. grub4dos使用 title 指定菜单标题, 使用 kernel 指定内核镜像, 使用 initrd 指定init镜像, 使用 boot 开始引导操作系统, 等等等等. grub4dos的配置文件是menu.lst, 一般将其与grldr放置在同一个目录下. 有menu.lst则修改, 无则新建. 当然在下载的grub4dos压缩包中也有附带的menu.lst模板可以用 参考isolinux.cfg, 可以得出grub4dos的对应代码如下: title install centos 5.11 find --set-root /grldr kernel /path/to/vmlinuz initrd /path/to/initrd.img boot 注意: 一般在使用grub4dos会指定一个根目录(用于绝对路径等), 使用find命令查找grldr文件并使用 --set-root附加选项将第一次找到grldr的目录设置为根目录. 在指定内核镜像和init镜像时, 可以使用相对路径或绝对路径, 但路径必须确保正确. 对于isolinux中append指定的内核参数, 直接以空格分隔的方式附件给kernel即可. 例如: # Some code in isolinux.cfg label ks kernel vmlinuz append ks initrd=initrd.img # In menu.lst title ks find --set-root /grldr kernel /centos/isolinux/vmlinuz ks initrd=/centos/isolinux/initrd.img boot 没错, initrd完全可以以内核附加参数的形式指定, 不过我还是喜欢使用initrd命令指定. 6. 重启计算机并使用启动盘引导 结束 进入CentOS 5.11系统救援模式的方法. 1. 在menu.lst文件中添加救援模式菜单项 title centos 5.11 rescue find --set-root /grldr kernel /path/to/vmlinuz linux rescue initrd /path/to/initrd.img boot 其实就是给内核传参数"linux rescue" 2. 将CentOS 5.11的iso镜像拷贝到U盘中 如果不这样做的话, 进入CentOS的救援模式之后, 它会提示如下错误: Device/dev/sdb4 does not appear to contain centos CDROM image 解决方法就是将iso镜像文件放置到启动盘中, 在提示指定镜像目录时指定iso文件路径即可.
﻿17年的圣诞节, 网站的服务器出现了一起事故, 时恰逢考试, 不得已直到今日才对此事故有所眉目. 运行环境 服务器: Dell PowerEdge 操作系统: CentOS 5.11 后端框架: php-cmsv9 事故表现 ssh登陆时提示root无法登陆 tty登陆时提示root密码错误 按下 ctrl + alt + delete 后INIT进程报错: shutdown[7326]: shutting down for system reboot INIT: cannot execute "/etc/rc.d/rc" INIT: no more processes left in this runlevel 开机后INIT依然报错.登陆依然失败, 同时主机名显示为"(none)" INIT: cannot execute "/etc/rc.d/rc" 刻录的Ubuntu 16.04启动盘和CentOS 6.8启动盘均无法引导并启动服务器, 但随身携带的使用工具制作的Windows PE盘可以引导并启动 进入 救援模式 后使用 chroot /mnt/sysimage/ 报错 chroot: /bin/sh can not be executable 日志分析 日志文件: secure 发现关键信息: sshd[5181]: User root not allowed because shell /bin/bash is not executable 日志文件: message shutdown[7326]: shutting down for system reboot init: cannot execute "/etc/rc.d/rc" init: no more processes left in this runlevel shutdown[7329]: shutting down for system reboot shutdown[7331]: shutting down for system reboot 信息检索 于Google发现一条重要信息: Locked out after installing a bash without executable bit 问题分析 测试的两个启动盘无法引导机器 考虑到机器比较老旧, 而新系统(Ubuntu 16.04和CentOS 6.8 均使用基于UEFI引导的Grub 2启动管理器, 而使用工具制作的Windows PE则一般使用grub4dos启动管理器, 所以决定使用基于mbr方式引导的grub4dos启动管理器引导u盘上的CentOS 5.11, 再进入救援模式解决问题. rc文件不能执行 rc文件的解释器就是/bin/bash , 如果bash不能执行, 那么rc脚本也就不能执行, 因此bash的执行权限是关键. 解决方案 进入救援模式 修改bash可执行权限 chmod +x /mnt/sysimage/bin/bash mbr引导的启动盘制作方法
﻿因为微信小程序的原因, 我开始学习vue框架. vue的响应式模板语法真的很让我惊喜(虽然确实是一种已经很久的模式了). vue的中文文档在这里 1. 简单地引用vue.js 使用vue框架最简单的方式就是写一个HTML页面然后引用vue.js啦. 使用 标签就可以将vue.js导入并且使用它来构建vue app了. 这种方法是官方建议的, 像我这种新手当然也是使用这种方案的啦. 记录一些vue的模板语法 相关链接 {{}} 双大括号绑定内容(类似于innerHtml ) v-bind 绑定属性 (el: v-bind:style="variable") v-on 绑定事件 (el: v-on:click="onClick") v-if 条件渲染 (el: v-if="bool") (el: {{ index }} - {{ item.message }} v-model 输入数据绑定 (el: Message is: {{ model }} 创建vue-app实例 如果要使用vue的"插值语法"和vue的种种api, 则必须在HTML的js代码中建立vue实例. 模板如下: var app = new Vue({ el: '#app', //vue实例的承载元素 data: {}, //数据 method: {}, //方法 computed: {}, //计算属性. 当插值时使用的数据需要过于繁琐的计算时, 使用计算属性. /* 生命周期钩子, 详见vue的文档 */ }); 生命周期函数钩子 2.使用vue-cli构建 vue-cli是个node的模块, 所以想要使用vue-cli, 首先需要配置node运行环境, 然后再使用npm安装vue-cli. 1. vue-cli构建vue-app的流程 使用内置的模板构建vue-app的项目 vue init webpack project-name 按需修改项目的详细信息 使用npm安装依赖 npm install --sava 项目开发码代码 测试 vue run dev 使用webpack打包项目 webpack 2. vue-app项目目录简要分析 index.html ---------项目主页入口, vue-app实例的承载元素就在这里定义 src/ ------------------项目的源码文件目录, 为项目写的所有的组件/js等代码都在这里 src/main.js -------app的入口文件, 它将App.vue作为模板, 以index.html中的承载元素初始化Vue-app实例. src/APP.vue ------app实例的主模板文件, 是整个vue-app最外层的总框架 src/components---模板目录, 原则上应该将所有的component都放在这里 src/assets ------------不需要编译的资源放在这里 src/router ---------------路由目录. 如果初始化app时选择了route, 则会有此目录 src/router/index.js ---路由配置文件. 在这里指定单页面应用的页面跳转 build/ ---------------webpack的配置文件就在这里, 记录了app的构建规则 webpack入门 3. vue模板 1. 模板的模板 //Javascript代码 //CSS代码, 使用scoped属性能将这段style代码限制在此组件内部而不会影响外部 ##### 2. 组件的构造方法 在node中, 一个js文件就是一个模块, 使用 ```import``` 导入模块而使用 ```export``` 导出模块. 在vue中, 一个vue文件即包含了这个组件的view和controller, 而对于javascript来说, 这个vue文件就是一个js模块. 因此, 应该使用``` export``` 导出这个组件的对象实例, 这样才能在外部导入这个组件. 构造一个对象的实例和构造一个vue实例是类似的, 都 ~~需要指定html中的"承载元素"和~~ data等等属性. export default { el:'#component', data: function(){ return somedData; //注意, 一个组件的data应该是一个函数对象并且使用return返回data对象 } method: function(){} //somefunction } ##### 3. 组件间的数据传递 1. 父组件->子组件 父组件传数据给子组件需要两步操作 1. 在子组件中声明需要的数据并完成view和model的绑定; 2. 父组件中将数据传给子组件 //子组件: {{someText}} This font-color should be setted by parent export default { data(){ return { someText: "text" } } props: { colorCode: String //使用props声明子组件需要的数据(属性), msg是属性的"name", String用来指定msg值的类型 } } //父组件: export default { data: ()=>{}, component:{ child: require('componenets/child.vue') } } 2. 子组件->父组件 子组件传递数据给父组件可以有多种操作. - 子组件使用将数据封装到组件实例并使用 ```export``` 导出 - 子组件使用"事件发射器(emit)"以"事件"的方式传给父组件 ##### 4. 组件间的事件传递 >1. 子组件捕获事件, 子组件处理 >2. 父组件捕获事件, 父组件处理 >3. 子组件捕获事件, 父组件处理 >4. 父组件捕获事件, 子组件处理 前两种的事件处理直接在script里将事件"消费"掉即可; 而后两种则需要使用不同的方式分别处理. - **子组件到父组件** 使用"事件发射器(emit)", 子组件捕获事件并将其"发射"给父组件, 由父组件处理 - **父组件到子组件** 在 vue 1 中, 有 ```dispatch()``` 和 ```broadcast()``` 将父组件的事件分发给子组件, 而在 vue 2 中, 上述两个方法已经被弃用, 取而代之的是状态管理层Vuex. [详见](https://cn.vuejs.org/v2/guide/migration.html#dispatch-%E5%92%8C-broadcast-%E6%9B%BF%E6%8D%A2) //子组件 export default{ data(){ return { msg: '请输入值' } }, methods: { onInput: function () { if (this.msg.trim()) { this.$emit('customedEvent', this.msg); //第一个参数是"发射"给父组件的事件名称, 第二个参数是事件的附加参数. } } } } //父组件 export default{ components: { child: require('components/child.vue'), }, methods: { recieveMessage: function (text) { alert(text); } } } #### 注意事项 **1. 每一个组件的最外层只能有一个根元素(template不是一个元素)**