2012年12月19日 星期三

利用 libudev 實作 USB 熱拔插偵測功能

udev 是 Linux kernel 的裝置管理服務,我們可以用它提供的 libudev 撰寫裝置熱拔插相關的程式。以下是一個實際範例程式。它每隔一小段時間就會檢查是否有收到 USB 熱拔插事件,並且將收到事件內容顯示到螢幕上。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libudev.h>

#define PROBE_INTERVAL (500)

int main(int argc, char** argv)
{
	struct udev* udev = NULL;
	struct udev_monitor* udev_monitor = NULL;
	struct udev_device* dev = NULL;
	int udev_fd = -1;
	fd_set fds;
	struct timeval tv;
	int ret;
	char node_string[64] = {};
	char serial_string[10] = {};
	const char* tmp = NULL;

	udev = udev_new();
	udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
	udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", NULL);
	udev_monitor_enable_receiving(udev_monitor);
	udev_fd = udev_monitor_get_fd(udev_monitor);

	while(1)
	{
		FD_ZERO(&fds);
		FD_SET(udev_fd, &fds);
		tv.tv_sec = 0;
		tv.tv_usec = 0;

		ret = select(udev_fd + 1, &fds, NULL, NULL, &tv);

		if(ret > 0 && FD_ISSET(udev_fd, &fds))
		{
			dev = udev_monitor_receive_device(udev_monitor);

			tmp = udev_device_get_devtype(dev);

			if(dev && tmp && !strcmp(tmp, "usb_device"))
			{
				if(!strcmp(udev_device_get_action(dev), "add"))
				{
					serial_string[0] = 0;
					strcat(serial_string, udev_device_get_sysattr_value(dev,"idVendor"));
					strcat(serial_string, udev_device_get_sysattr_value(dev,"idProduct"));
					fprintf(stderr, "USB Device [%s] added\n", serial_string);
					fprintf(stderr, "Node \"%s\" created\n", udev_device_get_devnode(dev));

				}else if(!strcmp(udev_device_get_action(dev), "remove"))
				{
					fprintf(stderr, "USB Device removed\n", serial_string);
					fprintf(stderr, "Node \"%s\" deleted\n", udev_device_get_devnode(dev));
				}

				udev_device_unref(dev);
			}
		}

		usleep(1000 * PROBE_INTERVAL);
	}

	udev_monitor_unref(udev_monitor);
	udev_unref(udev);
	udev = NULL;
	udev_monitor = NULL;

	return EXIT_SUCCESS;
}

2012年11月19日 星期一

隱藏 gvfs 中的硬碟分割區圖示

目前有許多檔案管理程式包括 Nautilus、Thunar、PCManFM,使用 gvfs 來存取檔案系統。在預設的情況下,它會把硬碟中的各個分割當成可卸除式磁碟一樣在桌面上或檔案管理視窗中顯示圖示,如果不希望它們被當成隨身碟一樣掛載到 /media/,可以在 /etc/udev/rules.d/ 新增一項規則:

KERNEL=="sda1", ENV{UDISKS_PRESENTATION_HIDE}="1"

這樣就可以把 sda1 的圖示隱藏,其他的分割區依此類推把 sda1 替換掉。規則可以寫到 /etc/udev/rules.d/10-local.rules。

2012年11月2日 星期五

Linux 下的 DVD shrink 替代方案

一般商業 DVD 通常因為區碼和加密而需要像 DVD shrink 這樣的軟體才能做備份,Linux 下除了用 wine 跑 DVD shrink 以外,其實還有 dvdbackup 這個套件可以用。

要做整片 DVD 備份,只需要以下的指令:

$ dvdbackup -M

這樣就可以將整張 DVD 備份到目前的工作目錄。另外記得要裝 libdvdcss2 來支援解密,Debian users 可以從 Debian multimedia 下載這個套件。

2012年10月10日 星期三

PSP NetParty 正體中文版

PSP NetParty 是一個類似 XLink、MHP tunnel 的 PSP 連線軟體。PSP連線可以使用 TCP 或UDP 且客戶端不需要開放通訊埠。


原作者網站(日本語)
 

安裝方式:
  1. 請先下載網路安裝程式,安裝最新的 PspNetParty 日文版。
  2. 下載中文版檔案,用壓縮檔內的檔案替換掉 PspNetParty 裡 jar 資料夾內的檔案。
  3. 執行 PlayClient.exe (Windows) 或 java -jar jar/PlayClient.jar (Linux) 啟動程式。

※ SSID 功能(目前為 Windows only)需要 msvcp100.dll 和 msvcr100.dll 兩個檔案,沒有這兩個檔案的人請到微軟網站安裝 Microsoft VC++ 2010 runtime。


※ 如果無線網路裝置清單沒有出現你的無線網卡,請確認是否已經安裝 winpcap

※ Linux 使用者如果抓不到網卡,請確定你有 root 權限。執行 PlayClient 時記得設定 LD_LIBRARY_PATH=./ 讓PNP抓得到 libjnetpcap.so,否則清單只會顯示尚未選擇。


相關連結:

原作者 github
https://github.com/montehunter/PSP-NetParty

正體中文版 github
https://github.com/ryuanlu/PSP-NetParty

※ 最終版本為 0.8b (commit:c47d4c7)

2012年9月19日 星期三

精簡版 OpenGL 3.x/4.x+ 初始化

以下的程式碼會用 root window 建立一個 legacy render context,然後再呼叫 glXCreateContextAttribsARB 建立指定版本的 render context。
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <GL/glx.h>
#include <GL/gl.h>
#include <GL/glext.h>

GLXContext glXCreateContextAttribsARB(Display*, GLXFBConfig, GLXContext, Bool, const int*);

int main(int argc, char **argv)
{
	int visual_attr[] = {	GLX_RGBA,
				GLX_DOUBLEBUFFER,
				GLX_RED_SIZE, 8,
				GLX_GREEN_SIZE, 8,
				GLX_BLUE_SIZE, 8,
				GLX_DEPTH_SIZE, 16,
				0 };

	int version_attr[] = {	GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
				GLX_CONTEXT_MINOR_VERSION_ARB, 3, 0};
	int nitems;

	Display* display = NULL;
	Window window;
	XVisualInfo* vi = NULL;
	GLXContext rc = 0;
	GLXContext newrc = 0;
	GLXFBConfig* fbconfig = NULL;

	display = XOpenDisplay(NULL);
	window = XRootWindow(display, 0);
	fbconfig = glXChooseFBConfig(display, DefaultScreen(display), 0, &nitems);

	vi = glXChooseVisual(display,DefaultScreen(display),visual_attr);
	rc = glXCreateContext(display, vi, 0, GL_TRUE);
	glXMakeCurrent(display, window, rc);

	newrc = glXCreateContextAttribsARB(display, *fbconfig, 0, 1, version_attr);
	if(newrc)
		glXDestroyContext(display, rc);

	XCloseDisplay(display);

	return EXIT_SUCCESS;
}

2012年7月21日 星期六

Linux 下進行 DVDrip

DVD 影片本身以標題(Title)和章節(Chapter)分割成好幾個部份,所以 rip 的時候先將需要的章節合併成單一個 vob 檔再轉檔會比較方便。

底下是用 mplayer dump 特定章節的範例:

mplayer dvd://1 -chapter 1-5 -dumpstream -dumpfile 01.vob

dvd://1 代表第一個標題,-chapter 1-5 表示從第一到第五個章節,輸出檔案為 01.vob。Dump 出來的 vob 檔會含 CC 字幕,之後再用 mencoder 轉成其他格式。


2012年6月16日 星期六

network manager 安裝

network manager 是 Gnome 桌面的預設網路管理服務,它可以讓使用者很方便地設定系統的網路裝置。在預設的情況下它會忽略 /etc/network/interfaces 裡的裝置,所以如果要讓 network manager 完全掌控系統上的網路裝置的話,請將 /etc/network/interfaces 清空,只留 loopback 那行。

或者修改 /etc/NetworkManager/NetworkManager.conf 設定檔,把 ifupdown 的 managed 改為 true,這樣 network manager 才會接管 /etc/network/interfaces 列出的裝置。

2012年5月12日 星期六

PSP 影片轉檔:使用 FFmpeg

之前的 Mencoder 文章有說明過 PSP 的影片檔限制,這裡要把那些限制選項轉換到 ffmpeg 這邊來。

以下是 ffmpeg 進行 x264 轉檔的範例:

ffmpeg -i input_file -s 480x270 -vcodec libx264 -preset medium -crf 23 -x264opts global_header=yes:b_pyramid=none:8x8dct=no -acodec libfaac -ab 96k -ac 2 -threads 0 output_file.mp4

這個指令會把輸入檔 input_file 縮小成 480x270,然後轉成 H.264 + AAC 96kbps mp4。轉檔時使用 medium preset,位元率控制採用 crf 固定畫質。-threads 0 表示自動偵測要使用的執行緒數量。

參考資料:

2012年5月5日 星期六

將任意檔案轉換成 C header file

要把任意檔案轉換成 C header file,可以使用 vim-common package 提供的 xxd 工具程式來達成。使用語法如下:

xxd -i input_file output_header


xxd 會以檔案名稱命名變數,無效的字元會被轉換成底線,同時也會加入 length 變數表示這個陣列的大小。

2012年4月23日 星期一

gettext 常用指令

參與開放原始碼專案的翻譯常常會用到 gettext 的各種工具。以下記錄幾個常用的命令:


從 POTFILES.in 更新 pot 檔:

在 po 資料夾裡執行 intltool-update -p

從 pot 檔更新 po 檔:

msgmerge [po file] [pot file] -o [output file]

從 po 檔產生 mo 檔:

msgfmt [po file] -o [mo file]

2012年4月1日 星期日

將 /tmp, /var/log, /var/tmp 導到 ramdisk 以後關機變慢

系統碟用 SSD 的人也許會想要把 /tmp, /var/log, /var/tmp 這些暫存區或者系統紀錄導到 ramdisk 去,以減少 SSD 的寫入次數,延長 SSD 的壽命。不過在你改了 /etc/fstab 以後可能會發現重開機時會在 sendsig 時卡很久。這是因為系統有兩個 logsave 的 process 會嘗試寫入 /var/log/fsck,而 ramdisk 每次重開資料都會消失。雖然不知道為啥在 kill logsave 的時候會 hang 住,不過只要在開機的時候幫 ramdisk 建立 /var/log/fsck 資料夾就可以讓 sendsig 正常地殺掉 logsave。

tmpfs /var/log tmpfs defaults,noatime,mode=0755 0 0
tmpfs /tmp tmpfs defaults,noatime,mode=1777 0 0
tmpfs /var/tmp tmpfs defaults,noatime,mode=1777 0 0

2012年3月31日 星期六

利用 setfacl 設定預設的群組 umask

要讓新檔案繼承資料夾的 group id 可以用 chmod g+s 來執行 setgid,但光是這樣還是沒辦法達到群組共享的效果,因為群組成員無法寫入其他人的檔案(umask == 0022)。

為了解決這個問題,我們需要 ACL 功能來針對特定資料夾設定 umask。首先你必須在掛載選項上加上 acl 標籤,例如「discard,noatime,defaults,acl」。要注意的是如果你有一些用 bind 的掛載點,記得最上層的那個掛載點的掛載選項一定要加 acl,只加 bind 掛載點的話沒辦法設定預設值(出現 Operation not supported 錯誤)。

加上選項並重掛載以後,可以用 setfacl 調整資料夾的 default umask:

setfacl -dm u::rwx,g::rwx,o::r-x [your_shared_folder]

2012年3月19日 星期一

ANSI code 控制游標顯示與隱藏

用 Linux framebuffer 做繪圖時可能會用到,不然圖畫到 fb node 以後會被游標破壞掉。
fputs("\e[?25h", stdout); // Show
fputs("\e[?25l", stdout); // Hide
※stdout 可以用其他的 tty node

據說這種方法並不是每個平台都適用,比較保險的做法還是要呼叫 ncurses 的函數。

2012年2月9日 星期四

Debian 系統建立 initrd.img

在 Debian 下編譯 kernel 請使用 update-initramfs,不要直接呼叫 mkinitramfs 產生 initrd.img,否則 kernel 開機時可能會回你找不到 /lib/modules/x.x.x/modules.dep。

update-initramfs 的使用範例:

$ sudo update-initramfs -c -k 3.2.1

這樣系統就會幫你產生 initrd.img-3.2.1 映像檔。另外 /etc/initramfs-tools/initramfs.conf 這個設定檔可以調整 initrd.img 要包多少 module 進去,通常是選 dep 讓系統去猜你的硬體,只包必要的 module。

2012年1月4日 星期三

Linux Kernel Development & Eclipse CDT

用 Eclipse CDT 開發 kernel module 時,會遇到 indexer 找不到某些符號而產生大量的 syntax error,連帶地 code auto-completion 一起失效,就算你已經把 include path 設定好也一樣。是說 ... 自動完成功能不能用的話我還不如開 vim 來寫。

其實 Indexer 本身沒有問題,問題在於 kernel 要在編譯時才會在 Makefile 裡面定義 __KERNEL__ 巨集,沒定義它的話很多宣告會消失,導致 Indexer 抓不到宣告。只要在設定 include path 時一併將 __KERNEL__ 加進去就可以開心地在 CDT 下寫 kernel module 了。