macOS 2 種安裝 OpenSSL 的方法

本篇紀錄 macOS 下 2 種安裝 OpenSSL 的方法,第一種為使用 homebrew 安裝,第二種為下載 OpenSSL 原始碼編譯安裝。

我的使用環境為 macOS 10.13.4,Xcode 9.1。

  • 使用 homebrew 安裝 OpenSSL
  • 下載 OpenSSL 3 原始碼編譯與安裝 OpenSSL
  • OpenSSL 3 原始碼編譯失敗解決方法
  • 下載 OpenSSL 1.1.1 原始碼編譯與安裝 OpenSSL

使用 homebrew 安裝 OpenSSL

以下為 macOS homebrew 安裝 OpenSSL 的指令,

1
brew install openssl

或者指定 OpenSSL 安裝的版本,例如:指定安裝 OpenSSL 1.1.1,

1
brew install openssl@1.1.1o

或者指定安裝 OpenSSL 3,

1
brew install openssl@3

brew 安裝 OpenSSL 3 會編譯失敗的可以參考這篇,在 openssl@3.rb 的 configure_args 函式裡的 args 新增 no-asm 選項,然後再次安裝 brew install openssl@3

/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/openssl@3.rb
1
2
3
4
5
6
7
8
9
10
def configure_args
args = %W[
--prefix=#{prefix}
--openssldir=#{openssldir}
--libdir=#{lib}
no-ssl3
no-ssl3-method
no-zlib
no-asm
]

或者改裝 OpenSSL 1.1.1 的版本。

下載 OpenSSL 3 原始碼編譯與安裝 OpenSSL

這邊介紹 OpenSSL 3 的編譯安裝方式,使用下列指令下載 OpenSSL 3.0.3 原始碼並且解壓縮,

1
2
wget https://www.openssl.org/source/openssl-3.0.3.tar.gz
tar xvf openssl-3.0.3.tar.gz

接下來進行編譯與安裝 OpenSSL,zlib 選項非必要,無壓縮需求可以不加,預設安裝在 /usr/local/ssl 目錄下,也可自行指定 --prefix 選項帶入目錄,如果不用 shared 的方式則 ./config no-shared 即可,

1
2
3
4
5
6
cd openssl-3.0.3
./config shared
#./config --prefix=/usr/local/ssl --openssldir=/usr/local/ssl shared zlib # 指定路徑
make -j4
make test
make install

OpenSSL 3 原始碼編譯失敗解決方法

我的 macOS 10.13.4 會出現這樣的編譯錯誤訊息,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
crypto/bn/rsaz-3k-avx512.s:1283:12: error: register %ymm20 is only available with AVX512
vmovdqu64 %ymm20,320(%rdi)
^~~~~~
crypto/bn/rsaz-3k-avx512.s:1284:12: error: register %ymm21 is only available with AVX512
vmovdqu64 %ymm21,352(%rdi)
^~~~~~
crypto/bn/rsaz-3k-avx512.s:1285:12: error: register %ymm22 is only available with AVX512
vmovdqu64 %ymm22,384(%rdi)
^~~~~~
crypto/bn/rsaz-3k-avx512.s:1286:12: error: register %ymm23 is only available with AVX512
vmovdqu64 %ymm23,416(%rdi)
^~~~~~
crypto/bn/rsaz-3k-avx512.s:1287:12: error: register %ymm24 is only available with AVX512
vmovdqu64 %ymm24,448(%rdi)
^~~~~~
crypto/bn/rsaz-3k-avx512.s:1288:12: error: register %ymm25 is only available with AVX512
vmovdqu64 %ymm25,480(%rdi)
^~~~~~

檢查 Xcode 版本,我的是 Xcode 9.1,

1
2
3
$ xcodebuild -version
Xcode 9.1
Build version 9B55

這篇下面的網友提供了一個解決方法 workaround,
就是在 configure 時加入 no-asm 的選項,這樣就可以編譯過了,但是似乎這個方法就沒法得到好的效能,

1
2
./config shared no-asm
make -j4

使用 make test 進行測試,

1
make test

make install 安裝到系統之前,使用 openssl version 指令測試執行 openssl 是否成功,出現找不到 libssl.3.dylib 動態函式庫的錯誤訊息

1
2
3
4
5
$ ./apps/openssl version
dyld: Library not loaded: /usr/local/lib/libssl.3.dylib
Referenced from: /Users/sheng/Desktop/github/openssl/./apps/openssl
Reason: image not found
Abort trap: 6

設定 DYLD_LIBRARY_PATH 要載入動態函式庫的路徑,因為 libssl.3.dylib 在這個編譯的目錄下,所以就設定一下 libssl.3.dylib 目錄的路徑(相對路徑或絕對路徑都可),這樣就成功執行起來了,macOS 的 DYLD_LIBRARY_PATH 是對應到 linux 的 LD_LIBRARY_PATH,在 macOS 下使用 LD_LIBRARY_PATH 是無效的,

1
2
3
4
$ DYLD_LIBRARY_PATH="./" ./apps/openssl version
# or
$ DYLD_LIBRARY_PATH="/Users/shengyu/openssl-3.0.3" ./apps/openssl version
OpenSSL 3.1.0-dev (Library: OpenSSL 3.1.0-dev )

下載 OpenSSL 1.1.1 原始碼編譯與安裝 OpenSSL

這邊也順便介紹一下的 OpenSSL 1.1.1x 的編譯安裝方式,基本上跟 OpenSSL 3 沒什麼太大差異,使用下列指令下載 OpenSSL 1.1.1o 原始碼並且解壓縮,

1
2
wget https://www.openssl.org/source/openssl-1.1.1o.tar.gz
tar xvf openssl-1.1.1o.tar.gz

接下來進行編譯與安裝 OpenSSL,zlib 選項非必要,無壓縮需求可以不加,預設安裝在 /usr/local/ssl 目錄下,也可自行指定 --prefix 選項帶入目錄,如果不用 shared 的方式則 ./config no-shared 即可,

1
2
3
4
5
6
cd openssl-1.1.1o
./config shared
#./config --prefix=/usr/local/ssl --openssldir=/usr/local/ssl shared zlib # 指定路徑
make -j4
make test
make install

OpenSSL 1.1.1o 我可以順利編譯過沒有遇到 OpenSSL 3 的 AVX512 的問題。

其他參考
OpenSSL master (and 3.0 branch) won’t build on MacOS 10.11 (El Capitan) · Issue #16670 · openssl/openssl
https://github.com/openssl/openssl/issues/16670

DYLD_LIBRARY_PATH 的相關討論
language agnostic - Is it OK to use DYLD_LIBRARY_PATH on Mac OS X? And, what’s the dynamic library search algorithm with it? - Stack Overflow
https://stackoverflow.com/questions/3146274/is-it-ok-to-use-dyld-library-path-on-mac-os-x-and-whats-the-dynamic-library-s
How do I configure the LD_LIBRARY_PATH on Linux and DYLD_LIBRARY_PATH on MAC OS X to point to MCR?
https://www.mathworks.com/matlabcentral/answers/473971-how-do-i-configure-the-ld_library_path-on-linux-and-dyld_library_path-on-mac-os-x-to-point-to-mcr

其它相關文章推薦
Ubuntu 2 種安裝 OpenSSL 的方法
OpenSSL AES encryption 對稱式加密指令用法與範例
C/C++ OpenSSL AES encryption/decryption 加密解密範例
macOS 查詢 Xcode 版本的 3 種方法
macOS 使用 pip 安裝 opencv

Ubuntu 安裝 Spotify 的方法

本篇紀錄 Ubuntu 下 安裝 Spotify 的方法,

我的使用環境為 Ubuntu 16.04,也適用於 Ubuntu 18.04 跟 Ubuntu 20.04。

Ubuntu 安裝 Spotify

這邊會介紹怎麼使用 apt-get 安裝 Spotify,在使用 apt-get 安裝 Spotify 之前要先設定 Spotify 的 ubuntu/debian 倉儲 (repository)

1
curl -sS https://download.spotify.com/debian/pubkey_0D811D58.gpg | sudo apt-key add -

加入 repository.spotify.com 到 apt sources list,這樣以後 apt-get update 就會去檢查有無更新,

1
echo "deb http://repository.spotify.com stable non-free" | sudo tee /etc/apt/sources.list.d/spotify.list

然後 apt-get update 成功後就可以安裝 spotify-client

1
2
sudo apt-get update
sudo apt-get install spotify-client

安裝 spotify-client 後檢查一下安裝的版本(這步驟非必要),

1
2
$ dpkg -l | grep spotify-client
ii spotify-client 1:1.0.80.480.g51b03ac3-13 amd64 Spotify streaming music client

現在 spotify-client 最新的版本是 1:1.1.84.716.gc5f8b819,但我還沒更新到最新。

也可以參考 Spotify 官方的 linux 安裝教學

錯誤排除

如果已經有安裝 Spotify 的人,後來很久後遇到 apt-get update 時會顯示 repository.spotify.com 站點憑證簽署問題而導致 apt-get update 失敗的話,可以參考這個方法,

apt-get update 失敗的訊息如下,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
sudo apt-get update
...
Hit:10 http://repo.steampowered.com/steam precise InRelease
Err:8 http://repository.spotify.com stable InRelease
The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 5E3C45D7B312C643
Hit:11 http://ppa.launchpad.net/mystic-mirage/pycharm/ubuntu xenial InRelease
Hit:12 http://ppa.launchpad.net/openshot.developers/ppa/ubuntu xenial InRelease
Get:13 https://download.01.org/gfx/ubuntu/16.04/main xenial InRelease [3,651 B]
Hit:14 http://ppa.launchpad.net/peek-developers/stable/ubuntu xenial InRelease
Hit:15 http://ppa.launchpad.net/rvm/smplayer/ubuntu xenial InRelease
Hit:16 http://ppa.launchpad.net/umang/indicator-stickynotes/ubuntu xenial InRelease
Fetched 6,967 B in 3s (2,040 B/s)
Reading package lists... Done
W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: http://repository.spotify.com stable InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 5E3C45D7B312C643
W: https://download.01.org/gfx/ubuntu/16.04/main/dists/xenial/InRelease: Signature by key 09D6EF97BFB38E916EF060E756A3DEF863961D39 uses weak digest algorithm (SHA1)
W: Failed to fetch http://repository.spotify.com/dists/stable/InRelease The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 5E3C45D7B312C643
W: Some index files failed to download. They have been ignored, or old ones used instead.

解決方法,就是把上面的訊息提到的 5E3C45D7B312C643 PUBKEY 加入,

1
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 5E3C45D7B312C643

然後再 apt-get update 就可以成功了

其他參考
Can’t install Spotify under Ubuntu. - The Spotify Community
https://community.spotify.com/t5/Desktop-Linux/Can-t-install-Spotify-under-Ubuntu/td-p/5258438
下方網友 carlgarner 2022-02-22 02:56 PM 回覆目前的 key 是 5E3C45D7B312C643,而我今天 2022-05-31 測試還有效,根據過往經驗可能隔一陣子就會失效。

相關文章
Ubuntu 安裝 protobuf
Ubuntu 安裝 gflags
Ubuntu 安裝 libevent
Ubuntu 編譯安裝 GLFW

Ubuntu 2 種安裝 OpenSSL 的方法

本篇紀錄 Ubuntu 下 2 種安裝 OpenSSL 的方法,第一種為使用 apt 安裝,第二種為下載 OpenSSL 原始碼編譯安裝。

我的使用環境為 Ubuntu 16.04,也適用於 Ubuntu 18.04 跟 Ubuntu 20.04。

以下 Ubuntu 安裝 OpenSSL 的方法內容大概分為這幾部分,

  • 方法1. 使用 distribution package 安裝 OpenSSL
  • 方法2. 下載 OpenSSL 原始碼編譯與安裝 OpenSSL
  • 備份舊版本 OpenSSL

方法1. 使用 distribution package 安裝 OpenSSL

安裝前記得先 apt-get update 一下,以下為 ubuntu apt-get 安裝 OpenSSL 的指令,

1
2
sudo apt-get update
sudo apt-get install openssl

安裝後可以使用 openssl version 確認一下 openssl 的版本,

1
2
$ openssl version
OpenSSL 1.0.2g 1 Mar 2016

方法2. 下載 OpenSSL 原始碼編譯與安裝 OpenSSL

由於 apt-get 上安裝的 OpenSSL 版本太舊,不符合我的需求,那就只能自己去下載 source code 下來編譯安裝了,使用下列指令下載 OpenSSL 1.1.1o 原始碼並且解壓縮,

1
2
3
cd /usr/local/src/
sudo wget https://www.openssl.org/source/openssl-1.1.1o.tar.gz
sudo tar xvf openssl-1.1.1o.tar.gz

如果你 wget 下載時會出現憑證問題,可以使用 –no-check-certificate 選項不檢查憑證,

1
wget https://www.openssl.org/source/openssl-1.1.1o.tar.gz --no-check-certificate

接下來進行編譯與安裝 OpenSSL,zlib 選項非必要,無壓縮需求可以不加,預設安裝在 /usr/local/ssl 目錄下,也可自行指定 --prefix 選項帶入目錄,如果不用 shared 的方式則 sudo ./config no-shared 即可,

1
2
3
4
5
6
cd openssl-1.1.1o
sudo ./config shared
#sudo ./config --prefix=/usr/local/ssl --openssldir=/usr/local/ssl shared zlib # 指定路徑
sudo make -j4
sudo make test
sudo make install

在 /etc/ld.so.conf.d/ 目錄下新增一個 openssl-1.1.1o.conf 設定檔,

1
sudo vim /etc/ld.so.conf.d/openssl-1.1.1o.conf

開啟 openssl-1.1.1o.conf 後加入這一行

1
/usr/local/ssl/lib

重新載入動態連結,

1
sudo ldconfig -v

測試 openssl 安裝的版本,

1
2
$ openssl version
OpenSSL 1.1.1o 3 May 2022

如果要看更詳細的參數的話可以使用 openssl version -a

備份舊版本 OpenSSL

如果你已經從 apt-get 安裝過 OpenSSL,但又要編譯安裝新版本的 OpenSSL 的話,可以先將舊版本的 OpenSSL 備份起來,
把原本的 /usr/bin/openssl 重新命名成 /usr/bin/openssl-1.0.2g

1
mv /usr/bin/openssl /usr/bin/openssl-1.0.2g

建立軟連結,將 /usr/bin/openssl 指向 /usr/local/bin/openssl (1.1.1),這一步可能不需要,新版本 make install 應該會順便覆蓋 /usr/bin/openssl 的版本,

1
ln -sf /usr/local/bin/openssl /usr/bin/openssl

其它相關文章推薦
macOS 2 種安裝 OpenSSL 的方法
OpenSSL AES encryption 對稱式加密指令用法與範例
C/C++ OpenSSL AES encryption/decryption 加密解密範例
Ubuntu 安裝 protobuf
Ubuntu 安裝 gflags
Ubuntu 安裝 libevent
Ubuntu 編譯安裝 GLFW

Ubuntu 休眠指令

本篇 ShengYu 要介紹在 Ubuntu 下休眠的指令,Ubuntu 裡 Systemd 工具提供了睡眠管理的高階命令,分別有 systemctl suspendsystemctl hibernatesystemctl hybrid-sleep

Suspend 掛起模式

掛起時系統的執行資料仍然儲存在記憶體,所以會以較低的功耗消耗電量。掛起模式喚醒系統恢復非常快速,
Ubuntu 桌面版的選單只有 Suspend 掛起模式,要用其他模式可以用輸入指令的方式。我的主機 suspend 後電源燈會呈現閃爍狀態。

1
systemctl suspend # 需要權限

Suspend 模式使用範例如下,

1
2
3
4
5
6
7
8
9
10
11
$ systemctl suspend
==== AUTHENTICATING FOR org.freedesktop.login1.set-wall-message ===
Authentication is required to set a wall message
Authenticating as: shengyu,,, (shengyu)
Password:
==== AUTHENTICATION COMPLETE ===
==== AUTHENTICATING FOR org.freedesktop.login1.suspend ===
Authentication is required for suspending the system.
Authenticating as: shengyu,,, (shengyu)
Password:
==== AUTHENTICATION COMPLETE ===

Hibernate 休眠模式

Hibernate 模式,字面上的意思是休眠,將記憶體內容寫入硬碟後完全關閉電源,等同 Windows 的休眠模式。完全不耗電,恢復速度比掛起慢。我的主機 hibernate 後電源燈會關閉。

1
systemctl hibernate # 需要權限

Hibernate 模式使用範例如下,

1
2
3
4
5
6
7
8
9
10
11
$ systemctl hibernate
==== AUTHENTICATING FOR org.freedesktop.login1.set-wall-message ===
Authentication is required to set a wall message
Authenticating as: shengyu,,, (shengyu)
Password:
==== AUTHENTICATION COMPLETE ===
==== AUTHENTICATING FOR org.freedesktop.login1.hibernate ===
Authentication is required for hibernating the system.
Authenticating as: shengyu,,, (shengyu)
Password:
==== AUTHENTICATION COMPLETE ===

Hybird Sleep 混合睡眠模式

Hybird Sleep 模式,混合睡眠,只供應電源給記憶體,其餘零件全部切斷電源供給,等同 Windows 的睡眠模式。

1
systemctl hybrid-sleep # 需要權限

Hybird Sleep 模式使用範例如下,我是桌機安裝 Ubuntu 桌面版,看起來應該沒有啟用 Hybird Sleep 混合睡眠模式而是會去執行 Hibernate 休眠模式。

1
2
3
4
5
6
7
8
9
10
11
$ systemctl hybrid-sleep
==== AUTHENTICATING FOR org.freedesktop.login1.set-wall-message ===
Authentication is required to set a wall message
Authenticating as: shengyu,,, (shengyu)
Password:
==== AUTHENTICATION COMPLETE ===
==== AUTHENTICATING FOR org.freedesktop.login1.hibernate ===
Authentication is required for hibernating the system.
Authenticating as: shengyu,,, (shengyu)
Password:
==== AUTHENTICATION COMPLETE ===

以上指令會需要輸入兩次密碼,覺得麻煩可以前面加 sudo,但也不會出現任何提示訊息。

其它參考
https://caloskao.org/ubuntu-hibernate-and-sleep-mode/
https://blog.csdn.net/HermitSun/article/details/113791114
https://www.gushiciku.cn/pl/gvWd/zh-tw
https://codertw.com/%E4%BC%BA%E6%9C%8D%E5%99%A8/380170/

其它相關文章推薦
Windows 10 測試搖桿的工具

macOS 查詢 Xcode 版本的 3 種方法

本篇 ShengYu 介紹 macOS 如何查詢 Xcode 版本的 3 種方法,查詢 Xcode 版本資訊的方法分為以下這幾種方法,

  • Xcode Welcome 視窗查看版本
  • Xcode 選單查看版本
  • 用 xcodebuild 指令查看 Xcode 版本

Xcode Welcome 視窗查看版本

啟動 Xcode 後,可以看到 Welcome to Xcode 的視窗,下方就有 Xcode 版本資訊囉!

Xcode 選單查看版本

啟動 Xcode 後,如果已經關閉 Welcome to Xcode 視窗的話,還可以從 Xcode 選單裡查看版本資訊,從選單的 Xcode > About Xcode 就可以看到 Xcode 版本資訊視窗囉!

Xcode 版本資訊視窗

用 xcodebuild 指令查看 Xcode 版本

這邊介紹在命令列下可以使用 xcodebuild 指令查看 Xcode 版本的方法,xcodebuild 指令用法如下,

1
2
3
$ xcodebuild -version
Xcode 9.1
Build version 9B55

以上就是 macOS 查詢 Xcode 版本的 3 種方法介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它相關文章推薦
macOS 安裝 zsh-completions 自動完成指令
mac 雙螢幕延伸模式的 dock 切換方法
macOS Screen Sharing 用指令開啟螢幕分享
macOS 安裝舊版的 Xcode 版本
macOS 版本升級的方法

C/C++ __attribute__((__packed__)) 用法與範例

本篇 ShengYu 介紹 C/C++ __attribute__((__packed__)) 用法與範例。

現代的編譯器幾乎都會進行最佳化,所以有時候某資料結構佔用的 bytes 數可能不是你想像的,原因是因為編譯器會為了運行效能進行最佳化,如下列範例所示,

cpp-attribute-packed.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// g++ cpp-attribute-packed.cpp -o a.out
#include <iostream>
using namespace std;

struct CharChar { char c; char c2; };
struct CharCharInt { char c; char c2; int i; };
struct IntCharChar { int i; char c; char c2; };
struct CharIntChar { char c; int i; char c2; };
struct CharShortChar { char c; short s; char c2; };

int main() {
cout << "sizeof(CharChar) " << sizeof(CharChar) << '\n';
cout << "sizeof(CharCharInt) " << sizeof(CharCharInt) << '\n';
cout << "sizeof(IntCharChar) " << sizeof(IntCharChar) << '\n';
cout << "sizeof(CharIntChar) " << sizeof(CharIntChar) << '\n';
cout << "sizeof(CharShortChar) " << sizeof(CharShortChar) << '\n';

return 0;
}

我的平台輸出如下,值得注意的是 CharCharInt 手算的話應該為 6,但是編譯器進行最佳化時會變成 8,
而 CharIntChar 會因為順序關係而造成最佳化結果不同變成 12,
CharShortChar 手算的話應該為 4,但是編譯器進行最佳化時會變成 6,

1
2
3
4
5
sizeof(CharChar)       2
sizeof(CharCharInt) 8
sizeof(IntCharChar) 8
sizeof(CharIntChar) 12
sizeof(CharShortChar) 6

通常在跨平台或資料結構的網路通訊中會需要資料對齊,
那麼如果要一定讓它強制對齊的話呢?Windows 與 Linux / macOS 作法不同,
在 Windows 下是使用 #pragma pack,這寫法原本只適用於 Visual C++ 編譯器,但後來 GCC 為了相容性也加入了這個語法的支援,詳細用法可看這篇
在 Linux / macOS 下是這樣做,要加上 __attribute__((__packed__)),加在前或後都可以,適用於 GCC 編譯器,

cpp-attribute-packed.cpp
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
// g++ cpp-attribute-packed2.cpp -o a.out
#include <iostream>
using namespace std;

struct __attribute__((__packed__)) CharChar {
char c;
char c2;
};

struct __attribute__((__packed__)) CharCharInt {
char c;
char c2;
int i;
};

struct IntCharChar {
int i;
char c;
char c2;
} __attribute__((__packed__));

struct CharIntChar {
char c;
int i;
char c2;
} __attribute__((__packed__)) charintchar;

typedef struct CharShortChar {
char c;
short s;
char c2;
} __attribute__((__packed__)) CharShortChar_t;

int main() {
charintchar.i = 123;
CharShortChar_t charshortchar;
cout << "sizeof(CharChar) " << sizeof(CharChar) << '\n';
cout << "sizeof(CharCharInt) " << sizeof(CharCharInt) << '\n';
cout << "sizeof(IntCharChar) " << sizeof(IntCharChar) << '\n';
cout << "sizeof(CharIntChar) " << sizeof(CharIntChar) << '\n';
cout << "sizeof(CharShortChar) " << sizeof(CharShortChar) << '\n';

return 0;
}

我的平台輸出如下,

1
2
3
4
5
sizeof(CharChar)       2
sizeof(CharCharInt) 6
sizeof(IntCharChar) 6
sizeof(CharIntChar) 6
sizeof(CharShortChar) 4

以上就是 C/C++ __attribute__((__packed__)) 的用法與範例介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它相關文章推薦
如果你想學習 C/C++ 相關技術,可以參考看看下面的文章,
C/C++ 新手入門教學懶人包
C/C++ pragma pack 用法與範例
C/C++ sizeof 用法與範例
C/C++ typedef 用法與範例
C/C++ define 用法與範例

Android UID 定義

本篇紀錄 Android UID 定義,android 的 user 是定義在程式裡,並不像 linux 一樣可以用 /etc/passwd 來查看。

Android UID 定義在 AOSP/system/core/include/private/android_filesystem_config.h 標頭檔
https://android.googlesource.com/platform/system/core/+/dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0/include/private/android_filesystem_config.h

這是比較早期 Android 的版本,

AOSP/system/core/include/private/android_filesystem_config.h
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
#define AID_ROOT             0  /* traditional unix root user */
#define AID_SYSTEM 1000 /* system server */
#define AID_RADIO 1001 /* telephony subsystem, RIL */
#define AID_BLUETOOTH 1002 /* bluetooth subsystem */
#define AID_GRAPHICS 1003 /* graphics devices */
#define AID_INPUT 1004 /* input devices */
#define AID_AUDIO 1005 /* audio devices */
#define AID_CAMERA 1006 /* camera devices */
#define AID_LOG 1007 /* log devices */
#define AID_COMPASS 1008 /* compass device */
#define AID_MOUNT 1009 /* mountd socket */
#define AID_WIFI 1010 /* wifi subsystem */
#define AID_ADB 1011 /* android debug bridge (adbd) */
#define AID_INSTALL 1012 /* group for installing packages */
#define AID_MEDIA 1013 /* mediaserver process */
#define AID_DHCP 1014 /* dhcp client */
#define AID_SHELL 2000 /* adb and debug shell user */
#define AID_CACHE 2001 /* cache access */
#define AID_DIAG 2002 /* access to diagnostic resources */
/* The 3000 series are intended for use as supplemental group id's only.
* They indicate special Android capabilities that the kernel is aware of. */
#define AID_NET_BT_ADMIN 3001 /* bluetooth: create any socket */
#define AID_NET_BT 3002 /* bluetooth: create sco, rfcomm or l2cap sockets */
#define AID_INET 3003 /* can create AF_INET and AF_INET6 sockets */
#define AID_NET_RAW 3004 /* can create raw INET sockets */
#define AID_MISC 9998 /* access to misc storage */
#define AID_NOBODY 9999
#define AID_APP 10000 /* first app user */

struct android_id_info {
const char *name;
unsigned aid;
};

static struct android_id_info android_ids[] = {
{ "root", AID_ROOT, },
{ "system", AID_SYSTEM, },
{ "radio", AID_RADIO, },
{ "bluetooth", AID_BLUETOOTH, },
{ "graphics", AID_GRAPHICS, },
{ "input", AID_INPUT, },
{ "audio", AID_AUDIO, },
{ "camera", AID_CAMERA, },
{ "log", AID_LOG, },
{ "compass", AID_COMPASS, },
{ "mount", AID_MOUNT, },
{ "wifi", AID_WIFI, },
{ "dhcp", AID_DHCP, },
{ "adb", AID_ADB, },
{ "install", AID_INSTALL, },
{ "media", AID_MEDIA, },
{ "shell", AID_SHELL, },
{ "cache", AID_CACHE, },
{ "diag", AID_DIAG, },
{ "net_bt_admin", AID_NET_BT_ADMIN, },
{ "net_bt", AID_NET_BT, },
{ "inet", AID_INET, },
{ "net_raw", AID_NET_RAW, },
{ "misc", AID_MISC, },
{ "nobody", AID_NOBODY, },
};

#define android_id_count \
(sizeof(android_ids) / sizeof(android_ids[0]))

system/core/include/private/android_filesystem_config.h 軟連結指向 system/core/libcutils/include/private/android_filesystem_config.h,

Android 10 system/core/include/private/android_filesystem_config.h
https://android.googlesource.com/platform/system/core/+/android10-release/include/private/android_filesystem_config.h

Android 10 system/core/libcutils/include/private/android_filesystem_config.h
https://android.googlesource.com/platform/system/core/+/android10-release/libcutils/include/private/android_filesystem_config.h

system/core/libcutils/include/private/android_filesystem_config.h
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
#define AID_ROOT 0 /* traditional unix root user */
/* The following are for LTP and should only be used for testing */
#define AID_DAEMON 1 /* traditional unix daemon owner */
#define AID_BIN 2 /* traditional unix binaries owner */
#define AID_SYSTEM 1000 /* system server */
#define AID_RADIO 1001 /* telephony subsystem, RIL */
#define AID_BLUETOOTH 1002 /* bluetooth subsystem */
#define AID_GRAPHICS 1003 /* graphics devices */
#define AID_INPUT 1004 /* input devices */
#define AID_AUDIO 1005 /* audio devices */
#define AID_CAMERA 1006 /* camera devices */
#define AID_LOG 1007 /* log devices */
#define AID_COMPASS 1008 /* compass device */
#define AID_MOUNT 1009 /* mountd socket */
#define AID_WIFI 1010 /* wifi subsystem */
#define AID_ADB 1011 /* android debug bridge (adbd) */
#define AID_INSTALL 1012 /* group for installing packages */
#define AID_MEDIA 1013 /* mediaserver process */
#define AID_DHCP 1014 /* dhcp client */
#define AID_SDCARD_RW 1015 /* external storage write access */
#define AID_VPN 1016 /* vpn system */
#define AID_KEYSTORE 1017 /* keystore subsystem */
#define AID_USB 1018 /* USB devices */
#define AID_DRM 1019 /* DRM server */
#define AID_MDNSR 1020 /* MulticastDNSResponder (service discovery) */
#define AID_GPS 1021 /* GPS daemon */
#define AID_UNUSED1 1022 /* deprecated, DO NOT USE */
#define AID_MEDIA_RW 1023 /* internal media storage write access */
#define AID_MTP 1024 /* MTP USB driver access */
#define AID_UNUSED2 1025 /* deprecated, DO NOT USE */
#define AID_DRMRPC 1026 /* group for drm rpc */
#define AID_NFC 1027 /* nfc subsystem */
#define AID_SDCARD_R 1028 /* external storage read access */
#define AID_CLAT 1029 /* clat part of nat464 */
#define AID_LOOP_RADIO 1030 /* loop radio devices */
#define AID_MEDIA_DRM 1031 /* MediaDrm plugins */
#define AID_PACKAGE_INFO 1032 /* access to installed package details */
#define AID_SDCARD_PICS 1033 /* external storage photos access */
#define AID_SDCARD_AV 1034 /* external storage audio/video access */
#define AID_SDCARD_ALL 1035 /* access all users external storage */
#define AID_LOGD 1036 /* log daemon */
#define AID_SHARED_RELRO 1037 /* creator of shared GNU RELRO files */
#define AID_DBUS 1038 /* dbus-daemon IPC broker process */
#define AID_TLSDATE 1039 /* tlsdate unprivileged user */
#define AID_MEDIA_EX 1040 /* mediaextractor process */
#define AID_AUDIOSERVER 1041 /* audioserver process */
#define AID_METRICS_COLL 1042 /* metrics_collector process */
#define AID_METRICSD 1043 /* metricsd process */
#define AID_WEBSERV 1044 /* webservd process */
#define AID_DEBUGGERD 1045 /* debuggerd unprivileged user */
#define AID_MEDIA_CODEC 1046 /* mediacodec process */
#define AID_CAMERASERVER 1047 /* cameraserver process */
#define AID_FIREWALL 1048 /* firewalld process */
#define AID_TRUNKS 1049 /* trunksd process (TPM daemon) */
#define AID_NVRAM 1050 /* Access-controlled NVRAM */
#define AID_DNS 1051 /* DNS resolution daemon (system: netd) */
#define AID_DNS_TETHER 1052 /* DNS resolution daemon (tether: dnsmasq) */
#define AID_WEBVIEW_ZYGOTE 1053 /* WebView zygote process */
#define AID_VEHICLE_NETWORK 1054 /* Vehicle network service */
#define AID_MEDIA_AUDIO 1055 /* GID for audio files on internal media storage */
#define AID_MEDIA_VIDEO 1056 /* GID for video files on internal media storage */
#define AID_MEDIA_IMAGE 1057 /* GID for image files on internal media storage */
#define AID_TOMBSTONED 1058 /* tombstoned user */
#define AID_MEDIA_OBB 1059 /* GID for OBB files on internal media storage */
#define AID_ESE 1060 /* embedded secure element (eSE) subsystem */
#define AID_OTA_UPDATE 1061 /* resource tracking UID for OTA updates */
#define AID_AUTOMOTIVE_EVS 1062 /* Automotive rear and surround view system */
#define AID_LOWPAN 1063 /* LoWPAN subsystem */
#define AID_HSM 1064 /* hardware security module subsystem */
#define AID_RESERVED_DISK 1065 /* GID that has access to reserved disk space */
#define AID_STATSD 1066 /* statsd daemon */
#define AID_INCIDENTD 1067 /* incidentd daemon */
#define AID_SECURE_ELEMENT 1068 /* secure element subsystem */
#define AID_LMKD 1069 /* low memory killer daemon */
#define AID_LLKD 1070 /* live lock daemon */
#define AID_IORAPD 1071 /* input/output readahead and pin daemon */
#define AID_GPU_SERVICE 1072 /* GPU service daemon */
#define AID_NETWORK_STACK 1073 /* network stack service */
#define AID_GSID 1074 /* GSI service daemon */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
#define AID_CACHE 2001 /* cache access */
#define AID_DIAG 2002 /* access to diagnostic resources */
/* The range 2900-2999 is reserved for OEM, and must never be
* used here */
#define AID_OEM_RESERVED_START 2900
#define AID_OEM_RESERVED_END 2999
/* The 3000 series are intended for use as supplemental group id's only.
* They indicate special Android capabilities that the kernel is aware of. */
#define AID_NET_BT_ADMIN 3001 /* bluetooth: create any socket */
#define AID_NET_BT 3002 /* bluetooth: create sco, rfcomm or l2cap sockets */
#define AID_INET 3003 /* can create AF_INET and AF_INET6 sockets */
#define AID_NET_RAW 3004 /* can create raw INET sockets */
#define AID_NET_ADMIN 3005 /* can configure interfaces and routing tables. */
#define AID_NET_BW_STATS 3006 /* read bandwidth statistics */
#define AID_NET_BW_ACCT 3007 /* change bandwidth statistics accounting */
#define AID_READPROC 3009 /* Allow /proc read access */
#define AID_WAKELOCK 3010 /* Allow system wakelock read/write access */
#define AID_UHID 3011 /* Allow read/write to /dev/uhid node */
/* The range 5000-5999 is also reserved for OEM, and must never be used here. */
#define AID_OEM_RESERVED_2_START 5000
#define AID_OEM_RESERVED_2_END 5999
#define AID_EVERYBODY 9997 /* shared between all apps in the same profile */
#define AID_MISC 9998 /* access to misc storage */
#define AID_NOBODY 9999
#define AID_APP 10000 /* TODO: switch users over to AID_APP_START */
#define AID_APP_START 10000 /* first app user */
#define AID_APP_END 19999 /* last app user */
#define AID_CACHE_GID_START 20000 /* start of gids for apps to mark cached data */
#define AID_CACHE_GID_END 29999 /* end of gids for apps to mark cached data */
#define AID_EXT_GID_START 30000 /* start of gids for apps to mark external data */
#define AID_EXT_GID_END 39999 /* end of gids for apps to mark external data */
#define AID_EXT_CACHE_GID_START 40000 /* start of gids for apps to mark external cached data */
#define AID_EXT_CACHE_GID_END 49999 /* end of gids for apps to mark external cached data */
#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
#define AID_SHARED_GID_END 59999 /* end of gids for apps in each user to share */
/*
* This is a magic number in the kernel and not something that was picked
* arbitrarily. This value is returned whenever a uid that has no mapping in the
* user namespace is returned to userspace:
* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/highuid.h?h=v4.4#n40
*/
#define AID_OVERFLOWUID 65534 /* unmapped user in the user namespace */
/* use the ranges below to determine whether a process is isolated */
#define AID_ISOLATED_START 90000 /* start of uids for fully isolated sandboxed processes */
#define AID_ISOLATED_END 99999 /* end of uids for fully isolated sandboxed processes */
#define AID_USER 100000 /* TODO: switch users over to AID_USER_OFFSET */
#define AID_USER_OFFSET 100000 /* offset for uid ranges for each user */

抽丝剥茧:理解Android权限机制
https://www.cnblogs.com/0xJDchen/p/6806573.html
Android:进程UID定义
https://blog.csdn.net/annkie/article/details/8111842

Android su 切換使用者指令用法與範例

本篇介紹 Android su 指令用法與範例,su 指令可以用來切換使用者,切換使用者後可以測試該使用者的執行權限。

su 後面接使用者名稱或者接使用者 id 也可以,範例如下,

1
2
3
4
5
6
7
8
9
10
11
12
# 切換成 root
su root # 或 su 0

# 切換成 system
su system # 或 su 1000

# 切換成 shell
su shell

# 切換成 user
su app_0 # 舊版 android, 或 su 10000
su u0_a0 # 新版 android, u0 表示 user 0, 或 su 10000

su 執行檔路徑在哪

su 在 /system/xbin/ 下,可以透過 which su 查詢得知,
如果想要知道目前的使用者是誰的話可以使用 whoami

userdebug build 會有 su 指令,但 user build 不會有 su 指令。

su 原始碼在哪

su 原始碼在 system/extras/su/su.cpp 裡,整體來說還是一個 C 程式。

其它參考
Android UID的分配、查看及相关知识
https://www.jianshu.com/p/b33dd49f2ae6

C/C++ strlen 用法與範例

本篇 ShengYu 介紹 C/C++ strlen 的用法與範例,C/C++ 可以使用 strlen 來計算字串長度,但不包括結束字元 '\0'

C/C++ 要使用 strlen 的話需要引入的標頭檔 <string.h>,如果要使用 C++ 的標頭檔則是引入 <cstring>
strlen 函式原型為

1
size_t strlen(const char * str);

str:欲計算字串長度的字元陣列

C/C++ strlen 計算字串長度的基本用法

這邊介紹 C/C++ strlen 來計算字元陣列裡的字串長度,strlen 計算字串長度是不包含結束字元 '\0'

cpp-strlen.cpp
1
2
3
4
5
6
7
8
9
10
11
// g++ cpp-strlen.cpp -o a.out
#include <stdio.h>
#include <string.h>

int main() {
char arr[] = "hello";

printf("Length of string is: %d\n", (int)strlen(arr));

return 0;
}

結果輸出如下,

1
Length of string is: 5

這邊示範另外一種使用情境,字元陣列分別初始化每個字元,並之後計算該字串長度,

cpp-strlen2.cpp
1
2
3
4
5
6
7
8
9
10
11
// g++ cpp-strlen2.cpp -o a.out
#include <stdio.h>
#include <string.h>

int main() {
char arr[] = {'h', 'e', 'l', 'l', 'o', '\0'};

printf("Length of string is: %d\n", (int)strlen(arr));

return 0;
}

輸出同上。

這邊介紹另外一種使用情境,初始化一個 const 字串,並之後計算該字串長度,

cpp-strlen3.cpp
1
2
3
4
5
6
7
8
9
10
11
// g++ cpp-strlen3.cpp -o a.out
#include <stdio.h>
#include <string.h>

int main() {
const char *arr = "hello";

printf("Length of string is: %d\n", (int)strlen(arr));

return 0;
}

輸出同上。

這邊介紹另外一種使用情境,使用 malloc 配置一塊指向字元陣列指標,並用 strcpy 複製字串,之後計算該字串長度,

cpp-strlen4.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// g++ cpp-strlen4.cpp -o a.out
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
char *arr = NULL;
arr = (char *)malloc(sizeof(char) * 64);
strcpy(arr, "hello");

printf("Length of string is: %d\n", (int)strlen(arr));
free(arr);
return 0;
}

輸出同上。

這邊介紹另外一種使用情境,取得使用者輸入的字串,並計算該字串長度,使用 gets 取得輸入是不安全的,因為給 gets 一個緩衝區但是卻沒有告訴它這個緩衝區到底有多大,也不知道輸入的字串到底有多大,輸入的字串可能超出緩衝區,而引起程式崩潰,解決方法是使用 fgets 替代,fgets 取得標準輸入時會將換行字元讀取進來,而 strlen 計算字串長度是會包含換行字元的,所以在這邊會將換行字元取代成結束字元。

cpp-strlen5.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// g++ cpp-strlen5.cpp -o a.out
#include <stdio.h>
#include <string.h>

int main() {
char arr[128] = {0};
// gets(arr); // unsafe
fgets(arr, 128, stdin);
int len = (int)strlen(arr);
if (arr[len-1] == '\n') // remove '\n'
arr[len-1] = '\0';

printf("Input: %s\n", arr);
printf("Length of string is: %d\n", (int)strlen(arr));
return 0;
}

gets 在某些平台下執行程式時會顯示警告訊息,例如在 macOS 平台下會顯示 warning: this program uses gets(), which is unsafe.

以上就是 C/C++ strlen 的用法與範例介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它參考
strlen - C++ Reference
https://www.cplusplus.com/reference/cstring/strlen/

其它相關文章推薦
如果你想學習 C++ 相關技術,可以參考看看下面的文章,
C/C++ 新手入門教學懶人包
C/C++ fgets 用法與範例
C/C++ malloc 用法與範例
C/C++ strcmp 用法與範例

C/C++ snprintf 用法與範例

本篇 ShengYu 介紹 C/C++ snprintf 的用法與範例,C/C++ 可以使用 snprintf 格式化輸出到 buffer 裡,除此之外還可以指定輸出的字元數。

C/C++ 要使用 snprintf 的話需要引入的標頭檔 <stdio.h>,如果要使用 C++ 的標頭檔則是引入 <cstdio>
snprintf 函式原型為

1
int snprintf(char * buffer, size_t n, const char * format, ...);

buffer:指向一塊字元陣列的指標,格式化輸出的結果字串輸出到這裡,該 buffer 需要足夠的空間存放結果。
n:指定輸出的最大字元數。
format:format 是格式控制字串,format 可被隨後的附加參數中指定的值替換,並按需求進行格式化,跟 printf 的 format 用法一樣。
…:可變引數 argument,依序替換 format 中的格式化種類。

C/C++ snprintf 格式化輸出基本用法

這邊介紹 C/C++ snprintf 格式化輸出的基本用法,snprintf 函式會在中將格式化輸出的一連串字元存到 buffer 裡。隨後的每個引數 argument 是根據 format 中的對應格式進行轉換和輸出。

使用 sprintf 的話沒有方法可以限制寫入的字元數,這表示使用 sprintf 撰寫出的程式碼很容易發生緩衝區溢位。跟 sprintf 相比 snprintf 可以指定要寫入 buffer 的字元數。

這邊介紹 C/C++ snprintf 格式化輸出,例如將數字格式化輸出成字串到 buffer 裡、將浮點數格式化輸出成字串到 buffer 裡,

cpp-snprintf.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// g++ cpp-snprintf.cpp -o a.out
#include <stdio.h>

int main() {
char buf[128] = {0};
const char str[] = "hello world";
char c = 'a';
int num = 123;
float f = 5.4321f;

snprintf(buf, 128, "string: %s\n", str);
printf("%s", buf);

snprintf(buf, 128, "character: %c\n", c);
printf("%s", buf);

snprintf(buf, 128, "integer: %d\n", num);
printf("%s", buf);

snprintf(buf, 128, "float: %f\n", f);
printf("%s", buf);

return 0;
}

結果輸出如下,

1
2
3
4
string: hello world
character: a
integer: 123
float: 5.432100

這邊再介紹一個範例,有時需要將一些資料格式化輸出並且連接在一起,這時可以使用 snprintf 搭配 strcat,snprintf 將資料格式化輸出到 tmp 後,再使用 strcat 連接 tmp 到 buf 裡,最後再用 printf 輸出結果,詳見下列範例,

cpp-snprintf2.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// g++ cpp-snprintf2.cpp -o a.out
#include <stdio.h>
#include <string.h>

int main() {
char hex[] = {0x01, 0x02, 0x03, 0x1a, 0x2b, 0x3c};
char tmp[128] = {0};
char buf[128] = {0};

for (int i = 0; i < sizeof(hex); i++) {
snprintf(tmp, sizeof(tmp), "0x%02x, ", hex[i]);
strcat(buf, tmp);
}
printf("hex : %s\n", buf);

return 0;
}

輸出結果如下,

1
hex : 0x01, 0x02, 0x03, 0x1a, 0x2b, 0x3c,

以上就是 C/C++ snprintf 的用法與範例介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它參考
snprintf - C++ Reference
https://www.cplusplus.com/reference/cstdio/snprintf/

其它相關文章推薦
如果你想學習 C++ 相關技術,可以參考看看下面的文章,
C/C++ 新手入門教學懶人包
C/C++ sprintf 用法與範例
C/C++ strcat 用法與範例