此处,我们以Ubuntu 16.04
虚拟机为例讲述搭建方法,为防止环境冲突,请选择使用一台干净的虚拟机,若使用Ubuntu Server 16.04
,可能会出现系统安装失败情况,若出现,请参考底部的参考链接。
另外,此教程中涉及到了部分文件的修改,我也对原项目进行了部分本地化,因此也可以直接获取我fork
修改的项目进行搭建,项目地址:https://github.com/hebtuerror404/libc-database。欢迎Star~
本文中最后生成的配置结束的PVM虚拟机已上传至百度云盘,需要的自取即可,链接: https://pan.baidu.com/s/1mfG_ES4GzBrLyoGRerZDoA 密码: 9vpp
使用命令sudo apt-get update && sudo apt-get upgrade -y
⚠️:可以使用以下命令换源以加速下载
使用命令
使用命令
此处推荐使用以下命令直接获取docker
docker
成功安装后可以去阿里云官网获取镜像加速器,然后按照官网所述直接做如下配置即可。
然后运行sudo pip install docker-compose -i https://mirrors.aliyun.com/pypi/simple/
安装docker-compose
⚠️:此处安装完成后,可能产生以下错误
此时可以使用which docker-compose
来确定核心文件位置,然后建立符号链接即可。
首先运行以下命令获取nodejs
然后安装npm
使用命令git clone https://github.com/niklasb/libc-database.git
获取此项目。
修改libc-database/searchengine/frontend/src/App.js
接下来进入项目文件夹并生成Web
端主项目
⚠️:若npm
安装过慢,可以尝试使用cnpm
,官网对于cnpm
的描述如下:
要使用cnpm
则运行以下命令:
⚠️:若可以在虚拟机内部开启VPN
以加速访问境外网站,请在此步开启。
使用以下命令获取/更新所有libc
文件到本地,此步骤依据网络连接状况需要耗时30 min ~ 2 h
,请耐心等待
./get arch
命令可能极其缓慢,属于正常情况,请耐心等待~
./get rpm
命令可能会因cpio
错误而退出,属于正常情况,直接无视即可~
首先需要修改一系列文件,使之满足启动条件
修改libc-database/searchengine/nginx.conf
修改libc-database/searchengine/config.py
修改libc-database/searchengine/api.py
使用命令sudo docker-compose up -d
启动后可以使用docker ps
检查启动情况
在/libc-database/searchengine
下,执行python3.6 -m index ../db
建立完成后,使用curl -XGET 127.0.0.1:9200/_cat/indices/
来测试索引建立情况
最后,在/libc-database/searchengine
下使用/usr/sbin/nginx -c nginx.conf
启动本地Ngnix
服务
使用命令curl -X POST -H 'Content-Type: application/json' --data '{"symbols": {"strncpy": "db0", "strcat": "0x000000000d800"}}' http://127.0.0.1/api/find
进行测试。
断开虚拟机网络,以验证本地状态下的服务可用性
执行下列命令即可
【原】光盘安装ubuntu出现BusyBox不能继续安装的终极解决方法
sudo cp
/
etc
/
apt
/
sources.
list
/
etc
/
apt
/
sources.
list
.bak
sudo vi
/
etc
/
apt
/
sources.
list
:
%
s
/
us.archive.ubuntu.com
/
mirrors.aliyun.com
/
g
:wq
sudo cp
/
etc
/
apt
/
sources.
list
/
etc
/
apt
/
sources.
list
.bak
sudo vi
/
etc
/
apt
/
sources.
list
:
%
s
/
us.archive.ubuntu.com
/
mirrors.aliyun.com
/
g
:wq
sudo apt
-
get install git vim wget curl python python3 python
-
pip python3
-
pip binutils
file
wget rpm2cpio cpio zstd nginx libffi6 libffi
-
dev software
-
properties
-
common
-
y
sudo add
-
apt
-
repository ppa:deadsnakes
/
ppa
sudo apt
-
get update
sudo apt
-
get install python3.
6
sudo curl https:
/
/
bootstrap.pypa.io
/
get
-
pip.py
-
o
/
get
-
pip.py
sudo python3.
6
/
get
-
pip.py
sudo ln
-
s
/
usr
/
local
/
bin
/
pip
/
usr
/
bin
/
pip
sudo apt
-
get install git vim wget curl python python3 python
-
pip python3
-
pip binutils
file
wget rpm2cpio cpio zstd nginx libffi6 libffi
-
dev software
-
properties
-
common
-
y
sudo add
-
apt
-
repository ppa:deadsnakes
/
ppa
sudo apt
-
get update
sudo apt
-
get install python3.
6
sudo curl https:
/
/
bootstrap.pypa.io
/
get
-
pip.py
-
o
/
get
-
pip.py
sudo python3.
6
/
get
-
pip.py
sudo ln
-
s
/
usr
/
local
/
bin
/
pip
/
usr
/
bin
/
pip
sudo pip install elasticsearch
sudo pip install elasticsearch
curl
-
fsSL https:
/
/
get.docker.com | bash
-
s docker
-
-
mirror Aliyun
curl
-
fsSL https:
/
/
get.docker.com | bash
-
s docker
-
-
mirror Aliyun
sudo mkdir
-
p
/
etc
/
docker
sudo tee
/
etc
/
docker
/
daemon.json <<
-
'EOF'
{
"registry-mirrors"
: [
"https://<镜像加速器ID>.mirror.aliyuncs.com"
]
}
EOF
sudo systemctl daemon
-
reload
sudo systemctl restart docker
sudo mkdir
-
p
/
etc
/
docker
sudo tee
/
etc
/
docker
/
daemon.json <<
-
'EOF'
{
"registry-mirrors"
: [
"https://<镜像加速器ID>.mirror.aliyuncs.com"
]
}
EOF
sudo systemctl daemon
-
reload
sudo systemctl restart docker
curl
-
sL https:
/
/
deb.nodesource.com
/
setup_14.x | sudo
-
E bash
-
sudo apt
-
get install
-
y nodejs
curl
-
sL https:
/
/
deb.nodesource.com
/
setup_14.x | sudo
-
E bash
-
sudo apt
-
get install
-
y nodejs
sudo npm install
-
g n
sudo n latest
sudo npm install
-
g n
sudo n latest
import
React, { useState, useEffect, useCallback, useRef }
from
'react'
;
import
'./App.css'
;
import
'fontsource-roboto'
;
import
Button
from
'@material-ui/core/Button'
;
import
Grid
from
'@material-ui/core/Grid'
;
import
TextField
from
'@material-ui/core/TextField'
;
import
Link
from
'@material-ui/core/Link'
;
import
CircularProgress
from
'@material-ui/core/CircularProgress'
;
import
Table
from
'@material-ui/core/Table'
;
import
TableBody
from
'@material-ui/core/TableBody'
;
import
TableCell
from
'@material-ui/core/TableCell'
;
import
TableRow
from
'@material-ui/core/TableRow'
;
import
{ makeStyles }
from
'@material-ui/core/styles'
;
-
const API_BASE
=
'https://libc.rip/api'
;
+
const API_BASE
=
'http://127.0.0.1/api'
;
const api
=
async (path, data)
=
> {
let resp
=
await fetch(`${API_BASE}${path}`, {
method:
'POST'
,
mode:
'cors'
,
cache:
'no-cache'
,
headers: {
'Content-Type'
:
'application/json'
},
body: JSON.stringify(data),
});
return
await resp.json();
};
const useStyles
=
makeStyles((theme)
=
> ({
root: {
'& .MuiTextField-root'
: {
margin: theme.spacing(
1
),
},
'& .MuiButton-root'
: {
margin: theme.spacing(
1
),
},
'& .remove'
: {
marginTop:
'1.2rem'
,
height:
'2rem'
,
},
'& .findbutton'
: {
marginTop:
'1.2rem'
,
},
},
table: {
marginTop:
'1rem'
,
marginBottom:
'1rem'
,
}
}));
function SearchRow({ onChange
=
()
=
> {}, onRemove
=
()
=
> {} }) {
const [symbol, setSymbol]
=
useState("");
const [address, setAddress]
=
useState("");
const [addressValid, setAddressValid]
=
useState(true);
const onSymbolChange
=
useCallback((evt)
=
> {
setSymbol(evt.target.value);
}, []);
const onAddressChange
=
useCallback((evt)
=
> {
setAddress(evt.target.value);
}, []);
useEffect(()
=
> {
const valid
=
!!address.match(
/
^(
0x
)?[
0
-
9a
-
fA
-
F]
*
$
/
);
setAddressValid(valid);
onChange({valid, symbol, address});
}, [address, symbol, onChange]);
return
(
<div>
<TextField label
=
"Symbol name"
value
=
{symbol} onChange
=
{onSymbolChange}
/
>
<TextField label
=
"Address"
error
=
{!addressValid} value
=
{address} onChange
=
{onAddressChange}
/
>
<Button className
=
"remove"
variant
=
"contained"
color
=
"secondary"
onClick
=
{onRemove}>
Remove
<
/
Button>
<
/
div>
);
}
function SearchForm({ onSearch
=
()
=
> {} }) {
const classes
=
useStyles();
const [nextId, setNextId]
=
useState(
0
);
const [rows, setRows]
=
useState([]);
const [states, setStates]
=
useState({});
const onRemoveRef
=
useRef();
const onChangeRef
=
useRef();
const makeRow
=
(
id
)
=
> {
return
(
<SearchRow key
=
{
id
}
onRemove
=
{()
=
> onRemoveRef.current(
id
)}
onChange
=
{(obj)
=
> onChangeRef.current(
id
, obj)}
/
>);
};
const isEmpty
=
useCallback((i)
=
> {
let state
=
states[rows[i].key];
return
!state || (!state.symbol && !state.address);
}, [rows, states]);
/
/
Add new empty rows automatically
useEffect(()
=
> {
let need
=
true;
for
(let i
=
0
; i < rows.length;
+
+
i) {
if
(isEmpty(i)) {
need
=
false;
break
;
}
}
if
(need) {
setRows(rows
=
> rows.concat([makeRow(''
+
nextId)]));
setNextId(
id
=
>
id
+
1
);
}
}, [rows, states, nextId, isEmpty]);
/
/
Remove superfluous rows at the end
useEffect(()
=
> {
let i
=
rows.length
-
1
;
while
(i >
=
1
&& isEmpty(i) && isEmpty(i
-
1
)) {
-
-
i;
}
if
(i < rows.length
-
1
) {
setRows(rows
=
> rows.
slice
(
0
, i
+
1
));
}
}, [rows, states, nextId, isEmpty]);
const onRemove
=
useCallback((
id
)
=
> {
for
(let i
=
0
; i < rows.length;
+
+
i) {
if
(rows[i].key
=
=
=
id
) {
setRows(rows.
slice
(
0
, i).concat(rows.
slice
(i
+
1
)));
return
;
}
}
}, [rows]);
const onChange
=
useCallback((
id
, obj)
=
> {
setStates({...states, [
id
]: obj});
}, [states]);
onChangeRef.current
=
onChange;
onRemoveRef.current
=
onRemove;
const onSubmit
=
useCallback(()
=
> {
let symbols
=
{};
for
(let row of rows) {
let state
=
states[row.key];
if
(state && state.valid && state.address && state.symbol) {
symbols[state.symbol]
=
state.address;
}
}
onSearch({
"symbols"
: symbols});
}, [rows, states, onSearch]);
const isValid
=
useCallback(()
=
> {
let cnt
=
0
;
for
(let row of rows) {
let state
=
states[row.key];
if
(!state)
continue
;
if
(!state.valid)
return
false;
if
(state.address && state.symbol)
cnt
+
+
;
}
return
cnt >
0
;
}, [rows, states]);
return
(
<form className
=
{classes.root}>
{rows}
<div>
<Button
disabled
=
{!isValid()}
variant
=
"contained"
className
=
"findbutton"
color
=
"primary"
onClick
=
{onSubmit}>
Find
<
/
Button>
<
/
div>
<
/
form>
);
}
function Result({
id
, buildid, md5, symbols, download_url }) {
const classes
=
useStyles();
const [
open
, setOpen]
=
useState(false);
const onToggle
=
useCallback((evt)
=
> {
evt.preventDefault();
setOpen(!
open
);
}, [
open
]);
let symbolRows
=
Object
.entries(symbols).
map
(([k, v])
=
> (
<TableRow key
=
{k}>
<TableCell><code>{k}<
/
code><
/
TableCell>
<TableCell><code>{v}<
/
code><
/
TableCell>
<
/
TableRow>
));
return
(
<div>
<Link href
=
'#'
onClick
=
{onToggle}>{
id
}<
/
Link>
{
open
&& (
<Table size
=
"small"
className
=
{classes.table}>
<TableBody>
<TableRow>
<TableCell>Download<
/
TableCell>
<TableCell>
<Link href
=
{download_url} download>Click to download<
/
Link>
<
/
TableCell>
<
/
TableRow>
<TableRow>
<TableCell>BuildID<
/
TableCell>
<TableCell>{buildid}<
/
TableCell>
<
/
TableRow>
<TableRow>
<TableCell>MD5<
/
TableCell>
<TableCell>{md5}<
/
TableCell>
<
/
TableRow>
{symbolRows}
<
/
TableBody>
<
/
Table>
)}
<
/
div>
);
}
function App() {
const [loading, setLoading]
=
useState(false);
const [results, setResults]
=
useState(null);
const onSearch
=
(data)
=
> {
setLoading(true);
(async ()
=
> {
try
{
setResults(await api(
'/find'
, data));
}
finally
{
setLoading(false);
}
})();
};
return
(
<div className
=
"App"
>
<p>Powered by the <Link href
=
"https://github.com/niklasb/libc-database/tree/master/searchengine"
>libc
-
database search API<
/
Link><
/
p>
<Grid container spacing
=
{
2
}>
<Grid item sm
=
{
12
} md
=
{
6
}>
<h3>Search<
/
h3>
<SearchForm onSearch
=
{onSearch}
/
>
<
/
Grid>
<Grid item sm
=
{
12
} md
=
{
6
}>
<h3>Results<
/
h3>
{loading && <CircularProgress
/
>}
{results !
=
=
null && results.
map
(x
=
> <Result {...x}
/
>)}
<
/
Grid>
<
/
Grid>
<
/
div>
);
}
export default App;
import
React, { useState, useEffect, useCallback, useRef }
from
'react'
;
import
'./App.css'
;
import
'fontsource-roboto'
;
import
Button
from
'@material-ui/core/Button'
;
import
Grid
from
'@material-ui/core/Grid'
;
import
TextField
from
'@material-ui/core/TextField'
;
import
Link
from
'@material-ui/core/Link'
;
import
CircularProgress
from
'@material-ui/core/CircularProgress'
;
import
Table
from
'@material-ui/core/Table'
;
import
TableBody
from
'@material-ui/core/TableBody'
;
import
TableCell
from
'@material-ui/core/TableCell'
;
import
TableRow
from
'@material-ui/core/TableRow'
;
import
{ makeStyles }
from
'@material-ui/core/styles'
;
-
const API_BASE
=
'https://libc.rip/api'
;
+
const API_BASE
=
'http://127.0.0.1/api'
;
const api
=
async (path, data)
=
> {
let resp
=
await fetch(`${API_BASE}${path}`, {
method:
'POST'
,
mode:
'cors'
,
cache:
'no-cache'
,
headers: {
'Content-Type'
:
'application/json'
},
body: JSON.stringify(data),
});
return
await resp.json();
};
const useStyles
=
makeStyles((theme)
=
> ({
root: {
'& .MuiTextField-root'
: {
margin: theme.spacing(
1
),
},
'& .MuiButton-root'
: {
margin: theme.spacing(
1
),
},
'& .remove'
: {
marginTop:
'1.2rem'
,
height:
'2rem'
,
},
'& .findbutton'
: {
marginTop:
'1.2rem'
,
},
},
table: {
marginTop:
'1rem'
,
marginBottom:
'1rem'
,
}
}));
function SearchRow({ onChange
=
()
=
> {}, onRemove
=
()
=
> {} }) {
const [symbol, setSymbol]
=
useState("");
const [address, setAddress]
=
useState("");
const [addressValid, setAddressValid]
=
useState(true);
const onSymbolChange
=
useCallback((evt)
=
> {
setSymbol(evt.target.value);
}, []);
const onAddressChange
=
useCallback((evt)
=
> {
setAddress(evt.target.value);
}, []);
useEffect(()
=
> {
const valid
=
!!address.match(
/
^(
0x
)?[
0
-
9a
-
fA
-
F]
*
$
/
);
setAddressValid(valid);
onChange({valid, symbol, address});
}, [address, symbol, onChange]);
return
(
<div>
<TextField label
=
"Symbol name"
value
=
{symbol} onChange
=
{onSymbolChange}
/
>
<TextField label
=
"Address"
error
=
{!addressValid} value
=
{address} onChange
=
{onAddressChange}
/
>
<Button className
=
"remove"
variant
=
"contained"
color
=
"secondary"
onClick
=
{onRemove}>
Remove
<
/
Button>
<
/
div>
);
}
function SearchForm({ onSearch
=
()
=
> {} }) {
const classes
=
useStyles();
const [nextId, setNextId]
=
useState(
0
);
const [rows, setRows]
=
useState([]);
const [states, setStates]
=
useState({});
const onRemoveRef
=
useRef();
const onChangeRef
=
useRef();
const makeRow
=
(
id
)
=
> {
return
(
<SearchRow key
=
{
id
}
onRemove
=
{()
=
> onRemoveRef.current(
id
)}
onChange
=
{(obj)
=
> onChangeRef.current(
id
, obj)}
/
>);
};
const isEmpty
=
useCallback((i)
=
> {
let state
=
states[rows[i].key];
return
!state || (!state.symbol && !state.address);
}, [rows, states]);
/
/
Add new empty rows automatically
useEffect(()
=
> {
let need
=
true;
for
(let i
=
0
; i < rows.length;
+
+
i) {
if
(isEmpty(i)) {
need
=
false;
break
;
}
}
if
(need) {
setRows(rows
=
> rows.concat([makeRow(''
+
nextId)]));
setNextId(
id
=
>
id
+
1
);
}
}, [rows, states, nextId, isEmpty]);
/
/
Remove superfluous rows at the end
useEffect(()
=
> {
let i
=
rows.length
-
1
;
while
(i >
=
1
&& isEmpty(i) && isEmpty(i
-
1
)) {
-
-
i;
}
if
(i < rows.length
-
1
) {
setRows(rows
=
> rows.
slice
(
0
, i
+
1
));
}
}, [rows, states, nextId, isEmpty]);
const onRemove
=
useCallback((
id
)
=
> {
for
(let i
=
0
; i < rows.length;
+
+
i) {
if
(rows[i].key
=
=
=
id
) {
setRows(rows.
slice
(
0
, i).concat(rows.
slice
(i
+
1
)));
return
;
}
}
}, [rows]);
const onChange
=
useCallback((
id
, obj)
=
> {
setStates({...states, [
id
]: obj});
}, [states]);
onChangeRef.current
=
onChange;
onRemoveRef.current
=
onRemove;
const onSubmit
=
useCallback(()
=
> {
let symbols
=
{};
for
(let row of rows) {
let state
=
states[row.key];
if
(state && state.valid && state.address && state.symbol) {
symbols[state.symbol]
=
state.address;
}
}
onSearch({
"symbols"
: symbols});
}, [rows, states, onSearch]);
const isValid
=
useCallback(()
=
> {
let cnt
=
0
;
for
(let row of rows) {
let state
=
states[row.key];
if
(!state)
continue
;
if
(!state.valid)
return
false;
if
(state.address && state.symbol)
cnt
+
+
;
}
return
cnt >
0
;
}, [rows, states]);
return
(
<form className
=
{classes.root}>
{rows}
<div>
<Button
disabled
=
{!isValid()}
variant
=
"contained"
className
=
"findbutton"
color
=
"primary"
onClick
=
{onSubmit}>
Find
<
/
Button>
<
/
div>
<
/
form>
);
}
function Result({
id
, buildid, md5, symbols, download_url }) {
const classes
=
useStyles();
const [
open
, setOpen]
=
useState(false);
const onToggle
=
useCallback((evt)
=
> {
evt.preventDefault();
setOpen(!
open
);
}, [
open
]);
let symbolRows
=
Object
.entries(symbols).
map
(([k, v])
=
> (
<TableRow key
=
{k}>
<TableCell><code>{k}<
/
code><
/
TableCell>
<TableCell><code>{v}<
/
code><
/
TableCell>
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!