Fork me on GitHub

记一次 Ubuntu 16.04 重装前后

全文概要


前几天实验室PC网络功能出Bug,有线网连不上nju登录站点,而加载内核驱动模块后的无线网卡却妥妥的没有问题,本来懒癌发作打算用一世无线网…可又想到之后虚拟机中的虚拟网卡NAT上网会有坑,且无线网本身速度不够稳定,考虑再三,拉上Quber一起“愉快”地开始了找坑之旅。然而,嗯…虽然折腾的结果并不总是那么令人振奋,但付出总有回报。谨以此文纪念本人各种努(chui)力(si)尝(zheng)试(zha),以及此后愤而重装的心路历程。

重装的前夜


挣扎是徒劳的

遇事儿的第一反应总是想解决问题,只不过每每碰上超出能力范围的…
不!还是要挣扎一下,万一成功了呢!

以下梳理一下Bug出现的前因后果:

硬件配置:
(1)操作系统:Ubuntu 16.04
(2)内核版本:4.13.0-26-generic
(3) 有线网卡:Realtek RTL8111/8168/8411 驱动:r8169
(4)无线网卡:TPLINK RTL8812 驱动:rtl8812

Bug现象:有线网无法连接到校园网登录门户,当然就不能上网了。

可能原因:
(1)硬件故障
① 网线坏了? —毕竟不是一次两次了…
② 网口坏了? —学子莘莘,独坑我一人?
③ 网卡坏了? —可能性比我写程序出Bug大大大多了…
(2)软件故障
① 网卡驱动不匹配? —可为啥之前都是好的…
② 内核中除了网卡驱动之外的网络相关模块故障? —“可为啥之前是好的”二连…我干了啥?
(3)DNS配置错误
① /etc/resolve.conf
② /etc/resolveconf.d/base
③ /etc/resolveconf.d/head

哦对,忘记说了,出事儿之前我正在配置P4环境,编译安装了一堆东西,会不会…嗯,下次还是在虚拟机里试试,这个回头再说…

以上,在我的水平范围内委实只能想到这么多,毕竟…知识总有盲点,宋公常这么安(chao)慰(feng)我们。可很快,它们还是被我一一否决了!

具体我是这么做的:
对于硬件故障,easy,网线坏了换几根好的,网口坏了插几个好的,排除!网卡嘛…暂时咱不折腾了,还得把主机拆开,有点小麻烦,并且可能性微乎其微,讲道理一插上网线就可以ifconfig查到已自动分配好校园网IP或者wireshark抓到DHCP包的话,其实硬件基本就没毛病了。

网站无法连接,很大可能是域名解析出了问题,Ubuntu中两个与DNS相关的配置文件出错,测试发现最重要的一个配置文件——/etc/resolv.conf,“居然”会根据连接的网络的不同而动态变化:

1
$ cat /etc/resolv.conf

呐,连接到无线网OpenWrt的时候,是这样:
image

连接到有线网的时候,又变成介样:
image

网上的建议都是增加新的nameserver,比如全国通用DNS地址114.114.114.114(114.114.115.115备用),还有全球通用的Google的DNS服务器IP:8.8.8.8(8.8.4.4备用),OK,每个都试了下,都在这里不管用,可见问题并不出在这里。在后文总结部分再回来讨论这些配置文件。

至于软件故障,驱动程序首当其冲,google搜索相同系统和网卡,类似不能上网的故障还不少,解决方案也都还完备,一度来了信心,完全把“之前为啥是好的”抛诸脑后,试呗。

根据经验帖,先确定当前以太网卡型号(注意grep命令对大小写敏感,搜关键字ethernet你是真的找不到网卡…):

1
$ sudo lspci | grep Ethernet

网卡型号如下图所示,很普通的以太网卡:
image

进一步查看网卡所用驱动:

1
$ sudo lshw -C network

注意输出中的driver字段:
image

参考他人说法,更换驱动为r8168极有可能解决问题,于是去到官网找对应内核版本的驱动,发现提供Linux内核版本最新至4.7的驱动。
r8168驱动下载

解压后,进入驱动源码目录进行安装:

1
2
$ cd r8168-8.045.08
$ sudo ./autorun.sh

驱动安装完成后重启系统,重复上述命令,或者执行lsmod可以发现r8168驱动已经生效,然而,联网问题依然存在,也许是我与原博主发生的故障原因根本就不一样,自然不能适用。

驱动问题应该是可以排除了,痛定思痛,决定在线升级系统,兴许能解决网络模块故障:

1
2
3
4
$ sudo apt-get update
$ sudo apt-get dist-upgrade
$ sudo reboot # 重启完成上述更新的安装
$ sudo update-manager -d # 打开更新管理器

一连串更新操作之后,应该是这个界面:
image

然后在某人的怂恿下…冒着软件配置在新系统Ubuntu 18(连官网都没有release…)上面各种不兼容报错的风险,我还是干了,其实这时候已经做好重装的准备了。

然后你还问然后?死心了!
一顿操作猛如虎,殊途同归重装苦/(ㄒoㄒ)/~~。

辩证地看问题

重装系统这个事儿吧,熟练了就是很简单的一件事儿,无非就是这么几步:

(1) 找个系统镜像,如Ubuntu
(2) 做个系统启动盘,推荐UltraISO
(3) BIOS设置成从U盘启动懒人教程送上;
(4) U盘启动后根据对应操作系统装机提示按步操作。

以上,操作系统即安装完成,倒不算麻烦,顺利的话20多分钟(Ubuntu)应该能够搞定,日常使用的软件也都提前安装好了或者在应用商店基本都可以找到,基本的工作娱乐需求也基本满足了,但是,有一个问题,装Linux的人会仅仅满足于这些基本的软件功能嘛?——毕竟,以用户友好著称的Windows(仅限于Office…)显然才更应该是大多数人的首选。

(⊙v⊙)嗯…其实我想说的是,对于追求极致效率、捣鼓不倦的Coder们来说,重装系统的工作明明才刚刚开始好伐!

既然无可避免,何不带着享(xiang)受(shi)的心情,重新打造自己的虚拟空间?

重装进行时


俗话说:“年轻不怕重来,生命在于折腾”,那么,开始吧!
(以下系统配置与本人喜好有关,仅供参考)

目录结构

PC里面的文件目录将被设计成和浏览器中的书签一样都是精心整理过的,一是强迫症,二是方便找。
image

主要在用户home目录下新建若干常用目录MineCodeSoftware
安装tree命令

1
$ sudo apt-get install tree

查看目录树型结构如下:
image
image
image
目录配置脚本下载

桌面主题

平时看厌了Ubuntu默认的玫红色桌面和终端,就想换个口味,这里推荐一款Ubuntu的扁平化桌面主题Flatabulous,加上扁平化的icon,显示效果是这样:
image

按下win键触发搜索,界面是这样的:
image

怎么样,喜不喜欢?只需三步你值得拥有:

第一步,安装Unity Tweak Tool

1
$ sudo apt-get install unity-tweak-tool

win键搜索后Unity Tweak Tool打开后是这样,其中themeicon是在第三步要配置的:
image

第二步,配置PPA源安装Flatabulous主题和iFlat Icon图标:

1
2
3
4
5
6
7
8
# theme
$ sudo add-apt-repository ppa:noobslab/themes
$ sudo apt-get update
$ sudo apt-get install flatabulous-theme
# icon
$ sudo add-apt-repository ppa:noobslab/icons
$ sudo apt-get update
$ sudo apt-get install ultra-flat-icons

第三步,使用Unity Tweak Tool配置主题和图标:
打开Unity Tweak Tool,设置themeFlatabulouiconUltra Flat即可。

输入法

Ubuntu上面的中文输入法不是很好用,可以安装搜狗输入法进行替代,配置如下:

1
2
3
4
5
6
$ sudo add-apt-repository ppa:fcitx-team/nightly
$ sudo apt-get update
$ sudo apt-get -y install fcitx
$ sudo apt-get -y install fcitx-config-gtk
$ sudo apt-get -y install fcitx-table-all
$ sudo apt-get -y install im-switch

检查fcitx是否安装完成:win键搜索fcitx,再安装搜狗官网下载linux版本的deb包:

1
$ sudo dpkg -i  文件名.deb

在系统设置里面点击语言支持,将输入法从ibus改为fcitx
image

注销一次,找到fcitx的配置,添加sougou pinyin并设为第一输入法即可:
image

配置完成即可使用,有细心的童鞋还会可能发现一个问题,那就是桌面右上角的任务栏会有两个输入法的图标,一个是搜狗的,另一个是fcitx,并且在打字时还会发现桌面同时出现两个输入框,觉得碍眼的朋友,请这么做,终端执行:

1
$ ps aux | grep fcitx

在输入中找到fcitx-qimpanel那一行,然后将本行的第二个字段(pid,即进程号)对应数字记下,杀掉该进程即可:

1
$ kill -9 进程号

好了,多余的输入框和任务栏图标都没啦~

运行环境

下面是各种开发环境的配置,包括:

  1. git
  2. zsh & oh-my-zsh(fish也蛮不错的)
  3. vim & vimplus
  4. gcc & g++
  5. jdk
  6. python2 & python3 & pip
  7. nodejs & hexo
  8. mysql & workbench
  9. ssh
  10. wireshark
  11. Unix Network Programming

配置详见此篇

工作利器

顺便再安利几款Ubuntu下好用的利器:

  1. IDE
    JetBrains家的几个亲儿子就不用多说啦,选择合适量级的新版本装好:
    (1)Java - Intellij
    (2)C/C++ - Clion(vim大神求放过…个人觉得用IDE来管理工程模块代码还是会方便一些)
    (3)Python - PyCharm
    (4)Java Script - WebStorm
    下载后解压,进入bin目录执行x.sh(x为IDE名称)的脚本即可打开,回头固定到Launcher上就好。
    觉得哪用得上这么多的看过来,Microsoft家的VSCode绝对能满足你,丰富的插件支持多种常见语言开发:C/C++、Java、Python等,文本编辑则有MarkDownLaTex,配置简单,保证够用!
    还嫌(re)弃(ai)麻(zhe)烦(teng)的,您出门右转那儿有个Sublimetext,我就不送了…
    Markdown编辑器的话,比较喜欢Remarkable的风格:
    image
    伸手党据此配置同一效果:View -> Night Mode,Style -> Screen

  2. 虚拟化
    (1)Virtualbox
    (2)VMware
    下载官方.deb包使用命令sudo dpkg -i 文件名.deb安装即可,如有因缺乏依赖导致安装失败时,根据命令行提示,执行:

    1
    $ sudo apt-get -f install 

    一键安装之前缺乏的依赖,再次安装.deb包即可成功。

  3. 阅读器
    推荐Okular,系统自带应用商店Ubuntu Software就有:
    image
    快捷键F6进入文档操作模式,再按数字键4,即可高亮文档,但是有个坑就是它高亮部分的文件状态信息大概是维护在软件内部的,也就是说根本不会对源文件做修改…这导致换个程序换个机器打开文档后都只能看到未经处理的源文档…

  4. 截图
    推荐Shutter,安装命令如下:

    1
    $ sudo apt-get install shutter

    为其配置系统快捷键Ctrl+Alt+A为调用shutter进行区域截图,快捷键Name随意起,Command填入shutter -s
    image

  5. 音乐、翻译
    网易云Ubuntu 16.04版和有道Deepin版,不多说,官网的.deb直接安装

  6. VPN
    使用ShadowSocks在Ubuntu下科学上网,浏览器和终端翻墙都花了不少功夫,详见此篇

重装的收获


遵循基本规定

  • 编译安装的文件一般安装在/usr/local/filename
    具体命令如下:
    1
    2
    3
    4
    5
    $ cd 源码文件夹
    $ ./autogen.sh # 生成configure脚本
    $ ./configure --prefix=/usr/local/软件名
    $ make -j4 # 多(四)线程编译
    $ sudo make install # 安装
    以上命令会将此软件相关的文件都会”安装“到同一个文件夹/usr/local/软件名下去,这样做的一个显而易见的好处是:如果之后想要删除该文件,或安装更新版本时要求彻底卸载旧版本,只需删除此文件夹即可实现完全删除,再也不用担心由于卸载不干净导致影响新版本安装配置失败的问题。
    然而这样做在方便软件管理的同时也带来了一个额外的操作:每次安装新命令时,需要配置PATH环境变量,将该命令的安装文件夹下的bin文件夹的绝对路径添加到原有PATH变量后方才能使用新安装软件命令:
    1
    2
    3
    $ vim ~/.zshrc # 本人习惯将环境变量定义在此配置文件中 
    # 末尾增加一行 export PATH=$PATH:/usr/local/软件名/bin
    $ source ~/.zshrc # 令新修改的配置文件生效
    再来理解一下软件“安装“的概念:其实就是把软件的编译好的可执行文件依赖库文件放到一个系统能够发现的合适位置。那么放在什么路径下才能让系统自动找到呢?这就是环境变量的作用了,在Linux乃至Windows系统中,PATH无疑是最重要的一个系统环境变量,它是一个由”:“(Linux)或”;“(Windows)分隔的,由多个软件可执行文件所在路径连接所构成的字符串,在未显式指定可执行文件的情况下,在终端中执行命令,都会到由PATH变量中包含的文件路径下面去找该命令对应的可执行文件,如果没有,就会报”Command Not Found“的错误。

善用系统命令

  1. sudo apt-get -f install
    正确安装之前由于缺乏依赖而失败的安装过程中全部必要依赖,避免要对照着安装错误日志上面的依赖名称一个个安装。
  2. sudo add-apt-repository ppa:x
    添加PPA软件源,加入-r参数则表示remove即删除某个之前添加的PPA软件源,回车两下后操作生效,对应的PPA源的增删情况可以在两个地方得到验证:
    (1)系统设置(System Settings) -> 软件更新(Software & Update) -> 其它软件(Other Software):列表中会显示/移除对应的PPA源地址,当然也可以在该UI上直接操作;
    (2)/etc/apt/source.list.d:目录下会出现/删除对应PPA源的.list和.list.save文件。

  3. whereis、local和which
    (1)whereis
    whereis命令只能用于程序名的搜索,而且只搜索二进制文件(参数-b)、man说明文件(参数-m)和源代码文件(参数-s)。如果省略参数,则返回所有信息。
    find相比,whereis查找的速度非常快,这是因为linux系统会将 系统内的所有文件都记录在一个数据库文件中,当使用whereis和下面即将介绍的locate时,会从数据库中查找数据,而不是像find命令那样,通过遍历硬盘来查找,效率自然会很高。
    但是该数据库文件并不是实时更新,默认情况下时一星期更新一次,因此,我们在用whereislocate 查找文件时,有时会找到已经被删除的数据,或者刚刚建立文件,却无法查找到,原因就是因为数据库文件没有被更新。
    (2)locate
    locate让使用者可以很快速的搜寻档案系统内是否有指定的档案。其方法是先建立一个包括系统内所有档案名称及路径的数据库,之后当寻找时就只需查询这个数据库,而不必实际深入档案系统之中了。在一般的发行版中,数据库的建立都被放在crontab中自动执行。
    locate命令其实是”find -name“的另一种写法,但要比后者快得多,原因在于它不搜索具体目录,而是搜索一个数据库(Ubuntu下是/var/lib/mlocate/mlocate.db),这个数据库中含有本地所有文件信息。Linux系统自动创建这个数据库,并且每天自动更新一次,所以使用locate命令查不到最新变动过的文件。为了避免这种情况,可以在使用locate之前,先使用updatedb命令,手动更新数据库。
    (3)which
    which命令的作用是,在PATH变量指定的路径中,搜索某个系统命令的位置,并且返回第一个搜索结果。也就是说,使用which命令,就可以看到某个系统命令是否存在,以及执行的到底是哪一个位置的命令。

  4. echo >> 和echo >
    Shell编程过程很多时候会使用echo并输入到日志文件中。写日志的时候有两种情况,一种是一次写入文件空,再写的时候就将之前的内容给覆盖掉,如何实现追加内容呢?
    (1)覆盖写入

    1
    $ echo "日志内容"  > 文件

    (2)追加写入

    1
    $ echo "日志内容"  >> 文件
  5. lspci和lsmod
    (1)lspci
    lspci命令用于显示当前主机的所有PCI总线信息,以及所有已连接的PCI设备信息。
    (2)lsmod
    lsmod命令用于显示已经加载到内核中的模块的状态信息。执行lsmod命令后会列出所有已载入系统的模块。Linux内核具有模块化的特性,应此在编译内核时,务须把全部的功能都放入内核。可以将这些功能编译成一个个单独的模块,待需要时再分别载入。

  6. insmod、rmmod、modprobe、depmod
    (1)insmod
    insmod命令用于将给定的模块加载到内核中。Linux有许多功能是通过模块的方式,在需要时才载入内核执行。如此可使内核较为精简,进而提高效率,以及保有较大的弹性。这类可载入的模块,通常是设备驱动程序
    (2)rmmod
    rmmod命令用于从当前运行的内核中移除指定的内核模块。执行rmmod可删除不需要的模块。
    (3)modprobe
    modprobe命令用于智能地向内核中加载模块或者从内核中移除模块。
    modprobe可载入指定的个别模块,或是载入一组相依的模块。modprobe会根据depmod所产生的相依关系,决定要载入哪些模块。若在载入过程中发生错误,在modprobe会卸载整组的模块。
    (4)depmod
    depmod命令可产生模块依赖的映射文件,在构建嵌入式系统时,需要由这个命令来生成相应的文件,由modprobe使用。

  7. 查看操作系统及内核版本
    (1)系统版本

    1
    $ cat /etc/issue

    直接显示Ubuntu 16.04.3 LTS
    或:

    1
    $ sudo lsb_release -a

    显示系统版本号(Release):Ubuntu 16.04.3 LTS,及代号(Codename):Xenial
    (2)内核版本

    1
    $ uname -r

    显示当前内核版本:4.13.0-26-generic

  8. 查看CPU信息
    (1)按单个逻辑核粒度

    1
    $ cat /proc/cpuinfo

    (2)按总核粒度

    1
    $ lscpu

认识配置文件

  1. 环境变量配置文件:
    (1)/etc/profile:此文件为系统的每个用户设置环境信息。当用户登录时,该文件被执行一次,并从 /etc/profile.d目录的配置文件中搜集shell的设置。一般用于设置所有用户使用的全局变量
    (2)~/.bashrc:只对单个用户生效,当登录以及每次打开新的bash shell时,该文件被读取;
    (3)~/.zshrc:只对单个用户生效,当登录以及每次打开新的zsh shell时,该文件被读取。
    我的环境变量一般都配置在~/.zshrc中,保存文件后别忘了用source使之立即生效。

  2. sudo配置文件:
    /etc/sudoers:从源码编译安装mininet时,执行安装脚本:sudo ./install.sh,怎么配置也找不到之前安装好的gitvim,我们都知道”Command Not Found”错误的原因就是没配置好对应命令的环境变量,于是我把上面提到的配置文件都加上了GIT_HOMEVIM_HOME,即使切换到root用户,仍然报错,于是猜想sudo命令虽然是让普通用户能够在执行命令时以root权限运行,但是仍不是真正的root,上述对所有用户都生效的环境变量都对sudo不适用,原因应该是sudo自己有特殊的环境变量定义。google到的结果证实了我这一想法,在/etc目录下有一个sudo命令的配置文件sudoers
    image
    sudo执行命令都会从/etc/sudoers这个配置文件中变量secure_path的值作为sudoPATH环境变量,会去这个变量指定的路径下去找命令对应的可执行文件。将GIT_HOMEVIM_HOME的添加到secure_path末尾,命令就能顺利找到执行了。

  3. 内核驱动文件:
    /lib/modules/$(uname -r)/kernel/drivers/:网卡驱动会放在net文件夹中,ethernet表示以太网卡,wireless中放的是无线网卡驱动。

  4. DNS配置文件:
    (1)/etc/resolv.conf
    (2)/etc/resolvconf/resolvconf.d/base
    (3)/etc/resolvconf/resolvconf.d/head
    里面最关键的就是nameserver字段,在其IP所对应的DNS Serversearch当前想要连接的域名,如nju.edu.cnlan等,一般来讲在Ubuntu 16.04系统中,每次更换网络连接后,resolv.conf都会自动重新加载,nameserver一般为127.0.1.1,一个很奇怪的IP地址,我们知道本机的回环地址loIP127.0.0.1。查找资料后才知道,原来Ubuntu下是有一个本地DNS服务,叫做dnsmasq,由NetworkManager控制,通过以下命令能发现此服务进程信息:

    1
    2
    $ ps aux | grep dnsmasq # 以下命令效果同上
    $ ps -ef | grep dnsmasq

    输出如下:
    image
    可以看到它监听的本地地址,–listen-address=127.0.1.1(ubuntu12.04及之前的版本是 127.0.0.1), 这个地址是一个本地回环地址,而你真实的dns服务器地址,是被这个服务管理维护着的。(之后我会写篇文章专门讨论Ubuntu下的DNS配置)
    即,用户进程想要访问某个IP未知、只知道主机名的服务器时,其发起DNS请求的流程如下:

    local process -> local dnsmasq -> router -> ISP DNS

  5. 软件源配置文件:
    (1)/etc/apt/source.list:通常放的是官方镜像源,但是中间偶然一天遇到了官方源挂掉的情况,考虑到教育网的缘故,我就更换成了清华的源
    (2)/etc/apt/source.list.d:通常放的是PPA等第三方镜像源。

掌握实用操作

好奇之人对新知识总是充满着渴望,这次掌握几个小Trick,提(ke)高(xue)效(tou)率(lan)再进一步!
(1)vim中临时提升编辑者权限
在Linux上工作的朋友很可能遇到过这样一种情况,当你用Vim编辑完一个文件时,运行:wq保存退出,突然蹦出一个错误:
image

这表明文件是只读的,按照提示,加上!强制保存::w!,结果又一个错误出现:
image

文件明明存在,为何提示无法打开?查看Vim帮助文档E212错误的解释如下:
image

原来是可能没有权限造成的,此时你才想起,这个文件需要root权限才能编辑,而当前登陆的只是普通用户,在编辑之前你忘了使用sudo来启动Vim,所以才保存失败。于是为了防止修改丢失,你只好先把它保存为另外一个临时文件temp-file-name,然后退出Vim,再运行sudo mv temp-file-name readonly-file-name覆盖原文件。
但这样操作过于繁琐。而且如果只是想暂存此文件,还需要接着修改,则希望保留Vim的工作状态,比如编辑历史,buffer状态等等,该怎么办?能不能在不退出Vim的情况下获得root权限来保存这个文件?
答案是肯定的,执行这样一条命令即可(原理参见这篇):

1
$ :w !sudo tee %

(2)待更…

参考资料


[1]Ubuntu 16.04 RTL8111/8168/8411 不能上网 经常断网解决办法
[2]Ubuntu系统升级
[3]Ubuntu下超好看的主题Flatabulous
[4]Ubuntux新安装后的软件准备—秋波
[5]dpkg安装deb缺少依赖包的解决方法
[6]Ubuntu截图软件shutter
[7]在Ubuntu中添加和删除PPA软件源
[8]Linux的五个查找命令-阮一峰
[9]每天一个Linux命令
[10]echo写入文件
[11]ubuntu dns服务器127.0.1.1的问题

我知道是不会有人点的,但万一有人想不开呢?!