11年底告别租房,搬到了新家。当时智能电视还刚起步,买的55寸的三星电视,只支持简单的应用和DLNA。所以想法很简单,就是想在电脑上下载的视频可以直接在电视上播放。巧的是那时正好西数发布了Mybooklive这个网络NAS,特点是便宜,3T版才1千多点,也就是个硬盘的钱,当即购入,谁知果然便宜没好货!用了三年多,后来手贱,想在Mybooklive上搭个git服务器,然后Mybooklive就变砖了!我搜集了三年的1T多的数据,就这么没了!!!重装系统也无果,硬盘挂了,西数绿盘质量真不咋的~

本来想就算了,就安心把数据都放云盘吧!反正我用的50M的电信网络,下载速度还可以!谁知祸不单行,网盘又开始接二连三的关闭了!虽然我主力用的百度网盘,官方言论是不会关闭,但是谁能保证呢?毕竟官方打脸是分分钟的事!还是搞个私有云比较安心!

  • NAS全称Network Attached Storage:网络附属存储
  • DLNA全称是DIGITAL LIVING NETWORK ALLIANCE:数字生活网络联盟。旨在解决个人PC,消费电器,移动设备在内的无线网络和有线网络的互联互通

需求

目前对私有云的需求不是很复杂。

  • 所有手机、电视、pad都能很容易的访问NAS上的资源
  • 个人的一些资料能备份到NAS上
  • 没有公网访问需求,公网访问需求通过百度网盘来分享

这些需求原来的Mybooklive即可以满足需求。现在我个人不推荐买Mybooklive,因为目前的私有云解决方案很多(不过我没用过其它的,所以也不具体推荐!),Mybooklive的体验并不好。不过我已经折腾了三年了,一是熟悉了,二是有“沉没成本”的投入,最重要的一点是木有钱

所以在双11入手了一块东芝1T的盘!我大概估算了一下,我原来1T的数据,其实大部分都是我当初舍不得删或者懒得删的数据,真正的数据并没有那么多,1T应该差不多了!

  • 沉没成本:已经付出且不可收回的成本。

对于沉没成本最近接触比较多,有些感想,后面总结!

重装系统

Mybooklive其实就是一个简单的电脑,运行的是debian系统!支持ssh,ftp,可以安装一些应用,实现例如离线bt,git服务等功能!

具体流程参考这里

买的硬盘连接线,直接通过USB接口,把硬盘接到电脑上,我用的是Linux Mint系统,如果是windows系统,需要用虚拟机安装debian系的Linux!

1
2
3
sudo apt-get install fuseext2 parted
sudo parted -l //找到磁盘标识,如/dev/sdb
sudo fuseext2 -o allow_other -o ro -o sync_read /dev/sdb4 /mnt/ #这个命令我死活执行不成功,不过算了,不影响,因为我不需要备份
  • 下载apnc-023205-046-20120910.deb这个版本固件,我只有这个版本安装成功了!
  • 从固件中提取rootfs.img
  • 把下面的执行脚本拷贝下来,保存成debrick.sh
  • 运行脚本
1
sudo ./debrick.sh /dev/sdb rootfs.img destroy

升级系统

目前最新的版本是apnc-024310-048-20150507.deb,直接从Mybooklive官网下载即可。

但是使用上面的方法重装系统后,无法使用管理界面里的离线升级!在线升级一直0%,没有进度,所以只能手动升级。

把下载的最新版固件上传到public目录下,执行如下命令!

1
./updateFirmwareFromFile.sh /shares/Public/文件名

管理界面自动进入升级界面!

升级DNLA服务

默认Mybooklive的DNLA服务是twonkymedia,支持的视频格式很有限。后来Mybooklive提供了自己的DLNA服务,从Mybooklive固件帮助页面下载后,和前面的升级系统一样进行操作即可!

执行脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
#!/bin/bash
#
# The purpose of the script is to reinstall the operating system (debrick) on
# a harddrive that has been extracted from the housing of a WD MyBook Live.
#
#help screen
if [ $# = 1 -a "$1" = "--help" ]; then
echo "
standard use of script is:
sudo ./debricker.sh the script will find out what disk to use, it will not
touch the partition tables and therefore perserves data.
it will look what the newest version of the firmware is
via internet and then search for it in current folder or
subfolders. if none is found it will download one.
possible options are:
/dev/sd? path to the disk from mybook live. if not given, the script
will figure it out on its own.
/*/*.img path to the firmware that will be written to the disk. if
not given, the script will search for and then download it.
destroy script will rewrite the partition table of disk,
this will not perserve data, must match /dev/sd?.
example
sudo ./debricker.sh /dev/sda /firmwares/mine.img destroy
"
exit 1
fi
echo
#check that requirements are fullfilled
if [ "$(id -u)" != "0" ]; then
echo -e "this script must be run as root.\n"
exit 1
fi
if ! which mdadm > /dev/null; then
echo -e "this script requires the mdadm package.\n"
exit 1
fi
#making sure the mountpoint is available
rootfsMount=/mnt/md0
if [ -e ${rootfsMount} ]; then
if mountpoint -q ${rootfsMount}; then
echo "${rootfsMount} needs to be unmounted."
exit 1;
fi
fi
test -d "./mnt" || mkdir -p "/mnt"
test -d "$rootfsMount" || mkdir -p "$rootfsMount"
#making sure that there is no raid unit running
rootfsRaid=/dev/md0
if [ -e $rootfsRaid ]; then
echo -e "\n$rootfsRaid already exists! you need to stop and remove it.\n"
exit 1;
fi
#standard choices
disk=notset
image_img=notset
destroy=false
#handles the arguments and sets options
for (( arg=1; arg<=${#}; arg++ ))
do
case ${!arg} in
/dev/sd?) disk=${!arg};;
*.img) image_img=${!arg};;
"destroy") destroy=true;;
*) echo "unknown argument: ${!arg}"
exit 1
esac
done
echo "********************** DISK **********************"
echo
#figure out what disk to use
if [ $disk = "notset" ]; then
for x in {a..z}
do
#avoid a to literal matching in order to avoid incompability.
if [ -e /dev/sd${x} ]; then
diskTest=$(parted --script /dev/sd${x} print)
if [ ! -e /dev/sd${x}0 -a ! -e /dev/sd${x}5 ]; then
if [[ $diskTest = *WD??EARS* ]]; then
if [[ $diskTest = *??00GB* ]]; then
if [[ $diskTest = *3*B*B*5??MB*primary* ]]; then
if [[ $diskTest = *1*B*B*2???MB*ext3*primary*raid* ]]; then
if [[ $diskTest = *2*B*B*2???MB*ext3*primary*raid* ]]; then
if [[ $diskTest = *4*B*B*GB*ext4*primary* ]]; then
if [ $disk != notset ]; then
echo "multiple disk founds, you must enter the path manually:"
echo " sudo ./debricker.sh /dev/sd?"
exit 1;
fi
disk=/dev/sd${x}
fi; fi; fi; fi; fi; fi; fi; fi
done
if [ $disk == notset ]; then
echo "script could not find a matching sd unit connected to system."
exit 1
fi
else
if [ ! -e $disk ]; then
echo "$disk does not exist."
exit 1;
fi
fi
echo -e "script will use the following disk: \n"
parted --script $disk print
read -p "is this REALLY the disk you want? [y] " -n 1
if ! [[ $REPLY =~ ^[Yy]$ ]]; then
echo -e "\nuser did not confirm, nothing was done.\n"
exit 1;
fi
echo
diskRoot1=${disk}1
diskRoot2=${disk}2
diskSwap=${disk}3
diskData=${disk}4
echo
echo "********************** IMAGE **********************"
echo
#the image was not given as parameter
if [ $image_img = notset ]; then
#find out what the latest version of firmware is
if ! which curl > /dev/null; then
echo -e "\nthis script requires the curl package, either install it or specify image file.\n"
exit 1
fi
wdc_homepage="http://websupport.wdc.com/firmware/list.asp"
wdc_latestfirmware=$(curl "${wdc_homepage}?type=AP1NC&fw=01.03.03" 2> /dev/null | awk ' {
if ( match($0, "upgrade file" ) != 0 ) {
split($0, http, "\"");
print http[2];
exit 1;
}
}')
latestversion_simple=$(echo $wdc_latestfirmware | cut -d'-' -f 2)
latestversion_pattern=$(echo $latestversion_simple | sed 's/../&*/g;s/:$//')
if [ "$latestversion_simple" == "" -o "$latestversion_pattern" == "" ]; then
echo -e "\ncould not fetch the latest version!\n"
exit 1;
fi
echo "checking: ${latestversion_simple}"
echo "searching: ./*/*${latestversion_pattern}.img"
image_img=$(find ./ -type f -name "*${latestversion_pattern}.img" -print; 2>/dev/null)
#get the latest firmware either from subdirs or internet
case `echo $image_img | wc -w` in
0) echo "searching: ./*/*${latestversion_pattern}.deb"
test -d "./firmware" || mkdir -p "./firmware"
image_deb=$(find ./ -type f -name "*${latestversion_pattern}.deb" -print; 2>/dev/null)
image_img="./firmware/rootfs_$latestversion_simple.img"
if ! [ `echo $image_deb | wc -w` == 1 ]; then
image_deb="./firmware/rootfs_$latestversion_simple.deb"
echo
echo "downloading: $image_deb"
read -p "confirm [y]: " -n 1
if ! [[ $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
echo
curl $wdc_latestfirmware > $image_deb
if [ $? != 0 ]; then
echo -e "\ndownloading encountered problems.\n"
exit 1;
fi
fi
echo
echo "will extract: $image_deb"
read -p "confirm [y]: " -n 1
echo
if ! [[ $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
echo "extracting: ./firmware/rootfs_${latestversion_simple}.img"
ar p $image_deb data.tar.lzma | unlzma | tar -x -C ./firmware
if [ $? != 0 ]; then
echo -e "\nextraction encountered problems.\n"
exit 1;
fi
mv ./firmware/CacheVolume/upgrade/rootfs.img ./firmware/rootfs_${latestversion_simple}.img
rm -rf ./firmware/CacheVolume;;
1) echo "found: $image_img";;
*) echo -e "\nmultiple image_img files was found."
exit 1
esac
else
if [ ! -e $image_img ]; then
echo "$image_img does not exist."
exit 1;
fi
fi
#construct the swap program
echo "\
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/mount.h>
#define MD_RESERVED_BYTES (64 * 1024)
#define MD_RESERVED_SECTORS (MD_RESERVED_BYTES / 512)
#define MD_NEW_SIZE_SECTORS(x) ((x & ~(MD_RESERVED_SECTORS - 1)) - MD_RESERVED_SECTORS)
main(int argc, char *argv[])
{
int fd, i;
unsigned long size;
unsigned long long offset;
char super[4096];
if (argc != 2) {
fprintf(stderr, \"Usage: swap_super device\\n\");
exit(1);
}
fd = open(argv[1], O_RDWR);
if (fd<0) {
perror(argv[1]);
exit(1);
}
if (ioctl(fd, BLKGETSIZE, &size)) {
perror(\"BLKGETSIZE\");
exit(1);
}
offset = MD_NEW_SIZE_SECTORS(size) * 512LL;
if (lseek64(fd, offset, 0) < 0LL) {
perror(\"lseek64\");
exit(1);
}
if (read(fd, super, 4096) != 4096) {
perror(\"read\");
exit(1);
}
for (i=0; i < 4096 ; i+=4) {
char t = super[i];
super[i] = super[i+3];
super[i+3] = t;
t=super[i+1];
super[i+1]=super[i+2];
super[i+2]=t;
}
/* swap the u64 events counters */
for (i=0; i<4; i++) {
/* events_hi and events_lo */
char t=super[32*4+7*4 +i];
super[32*4+7*4 +i] = super[32*4+8*4 +i];
super[32*4+8*4 +i] = t;
/* cp_events_hi and cp_events_lo */
t=super[32*4+9*4 +i];
super[32*4+9*4 +i] = super[32*4+10*4 +i];
super[32*4+10*4 +i] = t;
}
if (lseek64(fd, offset, 0) < 0LL) {
perror(\"lseek64\");
exit(1);
}
if (write(fd, super, 4096) != 4096) {
perror(\"write\");
exit(1);
}
exit(0);
}" >./swap.c
gcc swap.c -o swap
rm swap.c
echo
echo "********************** IMPLEMENTATION **********************"
echo -e "
everything is now prepared!
device: $disk
image_img: $image_img
destroy: $destroy\n"
read -p "this is the point of no return, continue? [y] " -n 1
echo
if ! [[ $REPLY =~ ^[Yy]$ ]]; then
exit 1;
fi
echo
#rewrite the partition table
if [ $destroy = true ]; then
backgroundPattern="${backgroundPattern:-0}"
dd if=/dev/zero of=$diskRoot1 bs=1M count=32
dd if=/dev/zero of=$diskRoot2 bs=1M count=32
dd if=/dev/zero of=$diskSwap bs=1M count=32
dd if=/dev/zero of=$diskData bs=1M count=32
badblocks -swf -b 1048576 -t ${backgroundPattern} ${disk} 16 0
sync
sleep 2
parted $disk --align optimal <<EOP
mklabel gpt
mkpart primary 528M 2576M
mkpart primary 2576M 4624M
mkpart primary 16M 528M
mkpart primary 4624M -1M
set 1 raid on
set 2 raid on
quit
EOP
sync
sleep 1
#blocksize 65536 is required by the hardware, you won't be able to mount if different.
mkfs.ext4 -b 65536 -m 0 $diskData
echo
read -p "destroying was done, would you like to continue with installation? [y] " -n 1
echo -e
if ! [[ $REPLY =~ ^[Yy]$ ]]; then
exit 1;
fi
fi
#write the image to the raid disk
echo
sync
mdadm --create $rootfsRaid --verbose --metadata=0.9 --raid-devices=2 --level=raid1 --run $diskRoot1 missing
mdadm --wait $rootfsRaid
sync
sleep 2
mkfs.ext3 -c -b 4096 $rootfsRaid
sync
sleep 2
mdadm $rootfsRaid --add --verbose $diskRoot2
echo
echo -n "synchronize raid... "
sleep 2
mdadm --wait $rootfsRaid
sync
echo -e "done\n"
echo "copying image to disk... "
dd if=$image_img of=$rootfsRaid
mount $rootfsRaid $rootfsMount
cp $rootfsMount/usr/local/share/bootmd0.scr $rootfsMount/boot/boot.scr
echo "enabled" > $rootfsMount/etc/nas/service_startup/ssh
sync
sync
sync
umount $rootfsMount
rmdir $rootfsMount
mdadm --stop $rootfsRaid
./swap $diskRoot1
./swap $diskRoot2
rm ./swap
echo
echo "all done! device should be debricked!"
echo

参考资料