旅かえるのアルバムをお手軽にバックアップする方法(ある程度パソコンに詳しい人向け・ルート化不要)

旅かえる癒されますよね。
かえる達の写真を見るとほっこりします。

アプリを起動しなくてもほっこりできるようにPCにも保存しているのですが、これが結構面倒。
旅好きなかえるから、結構な枚数の写真が送られてくるので、スマホの機能で共有するのも楽ではありません。
そこでお手軽にバックアップする方法を考えました。
なお、本方法はAndroid版 ver.1.2.1を想定しています。


1. Androidに適当なFile Managerを入れる。 (スマホ側の操作)
最近のAndroid機には、元からFileManagerが入っていることも多いです。
"Android"フォルダが見えるのであればそれでも可です。
私はX-ploreというアプリを使いました。

2. /Android/data/jp.co.hit_point.tabikaeruフォルダをPCにコピーする。(スマホ側の操作)
私はX-ploreの機能を使ってzipに圧縮した後、Dropboxにアップロードして共有しました。

3. jp.co.hit_point.tabikaeruフォルダのfiles/Pictureに入っているalbum_*.savファイルをすべて取り出します。
今のバージョンだとalbum_(日時).savみたいな名前になっています。

4. 取り出したすべてのファイルの先頭4バイトを削除し、拡張子をす.savから.pngに変更します
私の場合、WSLを使っていたのでBash上で

ls *.sav | xargs -I% dd if=% of=%.png bs=1 skip=4

とかやりました。


これで今日からスマホがなくともかえるを愛でることができますね!

PowerShell で一時的にスクリプトの実行を許可する方法

PowershellのExecution-Policyを恒久的に変更してスクリプトの実行を許可してしまうと、

  • 実行許可の取り消し忘れによるセキュリティの問題
  • そもそも変更にアドミン権限が必要で面倒

などの問題があります。

それを解決する方法として、スコープを使うことで実行中のターミナルのみ、Execution-Policyを変更できます。

Set-ExecutionPolicy RemoteSigned -Scope Process

以上です。

ちなみに個人的には、RemoteSignedぐらいが、開発中のマシンで使うセキュリティレベルとしてはちょうどいいかなと思っています。
必要に応じてもっと緩く設定してください。

Windows Subsystem for Linuxで、Windows側のSSHキーと設定を使う方法

目的

WindowsでWin32-OpenSSHがまともに使えるようになってきて、Windows側とWSLの両方でSSHを使うよって人もいるかもしれません。
とりあえず、ここに一人います。

SSH鍵のセットアップって、結構面倒(主に、リモート先で鍵を追加して回るのが面倒)なので共有できたら楽ですよね。
別マシンで秘密鍵を流用するのはセキュリティ的によくないことですが、WSLなら物理一台なのでいいじゃん。と先に言い訳しておきます。

方法

まず、WSLのディレクトリマウントのオプションを設定します。

vim /etc/wsl.conf

下記を追記してください。

[automount]
enabled = true
options = "metadata"


続いて下記の操作を行います。

sudo umount /mnt/c
sudo mount -t drvfs C: /mnt/c -o metadata
ln -s /mnt/c/Users/[Username]/.ssh/ ~/.ssh
cd ~/.ssh
chown [Username] *
chmod 600 *

具体的に何をしているのかというと、

  1. 一旦Windows側のファイルシステムをアンマウントして、
  2. wsl.confで設定したのと同様の設定でマウントしなおし、
  3. パーミッションを正しく設定しなおしてる

って感じです。

これで、再起動を行っても問題なく、WSLからWindows側の設定でSSHが使い続けられるようになります。

High SierraでJohn The Ripperをコンパイルする方法。

OS X (High Sierra) 上でJtRを使おうとして色々と罠があったのでメモ。

GCCとOpenSSLのインストール

まず、GCCとOpenSSLをインストールします。その後、OpenSSLにパスを通します。

$ brew update && brew upgrade
$ brew install gcc openssl


続いてOpenSSLにパスを通します。

$ brew list openssl
/usr/local/Cellar/openssl/1.0.2n/.bottle/etc/ (8 files)
/usr/local/Cellar/openssl/1.0.2n/bin/c_rehash
/usr/local/Cellar/openssl/1.0.2n/bin/openssl
/usr/local/Cellar/openssl/1.0.2n/include/openssl/ (75 files)
/usr/local/Cellar/openssl/1.0.2n/lib/libcrypto.1.0.0.dylib
/usr/local/Cellar/openssl/1.0.2n/lib/libssl.1.0.0.dylib
/usr/local/Cellar/openssl/1.0.2n/lib/engines/ (12 files)
/usr/local/Cellar/openssl/1.0.2n/lib/pkgconfig/ (3 files)
/usr/local/Cellar/openssl/1.0.2n/lib/ (4 other files)
/usr/local/Cellar/openssl/1.0.2n/share/man/ (1680 files)

$ export PATH=/usr/local/Cellar/openssl/1.0.2k/bin:$PATH

$ which openssl
/usr/local/Cellar/openssl/1.0.2k/bin/openssl

JohnTheRipperのコンパイル

公式のリポジトリからソースコードを取得し、コンパイルします。

$ git clone --depth 1 git@github.com:magnumripper/JohnTheRipper.git
$ cd JohnTheRipper/src
$ ./configure CPPFLAGS="-I/usr/local/Cellar/openssl/1.0.2k/include" CFLAGS="-I/usr/local/Cellar/openssl/1.0.2k/include" LDFLAGS="-L/usr/local/Cellar/openssl/1.0.2k/lib" --disable-pkg-config CC="gcc-7"  
$ make -s clean && make -sj4


最後に操作確認をします。

$ cd ../run
$ ./john --test

IntelliJ Ultimate Editionを無料で使う方法。(学生向け)

IntelliJ使ってますか? 私は使っていませんでした。(笑)

所用でJavaを使い始めることとなり、IDEとしてIntelliJを選択することに。。。 最初はCommunity Editionをインストールしようとしたのですが、

「もしかしてEnterprise Editionとかあったりしちゃう???学生だと無料で使えちゃったりしちゃう???」

と悪魔のささやきが。

調べて見ると、なんとあるではないですか!Ultimate Edition!!!

そして学生無料!!!

使うしか無いですね〜

申請方法

www.jetbrains.com

ここで、名前と大学のメールアドレスを使って申請。 すぐに認証メールが届くの、URLをクリックすれば使えるようになります。

注意事項

  • 営利目的には使えない
  • 有効期限は1年間。(必要なら、一年ごとに再申請)

ということでみなさんも是非快適なIntelliJ生活を

F#でargparseぽいことをする方法

F#でコマンドライン引数をうまく使いたかったので。

let ParseArguments options argv = 
    let key = ref "" in
    argv 
    |> Seq.groupBy( fun s -> 
        match Seq.exists(fun t -> String.Compare(t, s) = 0) options with
        | true -> key := s; !key
        | false -> !key
    )
    |> Seq.map(fun (e1, e2) -> 
        let new_e2 = e2 |> Seq.skip 1 |> Seq.toList in
        (e1, new_e2))
    |> dict 

optionsはオプション。argvは与えられたコマンドライン引数。戻り値は辞書型。

使い方

[<EntryPoint>]
let main argv =
    let options = ["-a"; "-b"] in 
    let args = ParseArguments options argv in
    printfn "%A" args.["-a"].[0]

Linux Kernel 4.4 の新機能 "mlock2"

この記事は Linux Advent Calendar 2015 - Qiita の 24日目の記事です。

みなさんUbuntuつかってますか?

次期LTS版である、Ubuntu16.04では、Linux Kernel 4.4を利用することが検討されています。*1

来年から5年間をUbuntu16.04とともに過ごすであろうというあなたのために、今回はLinux Kernel 4.4の新機能のひとつmlock2システムコールについてざっくりとまとめてみたいとおもいます。

* Kernel4.4関連の面白い新機能というと、AMDの新しいAPUおよびGPUのサポートやRaspberry Pi KMS ドライバの追加、AVX2を利用したSHA1/SHA256の高速化などなどあるのですが、そのへんはまたそのうち。


目次

1. mlock / mlock2システムコールとは

まずはmlockの解説。

int mlock(const void *addr, size_t len);

mlockでは、仮想アドレスとそこからのサイズを渡すことによって、そのアドレス空間の含まれるページが スワップされなくなります。

そして、その空間を再びスワップするように戻すのにはmunlockというシステムコールが使われます。まあその他関連システムコールとしてmlockallとかmunlockallとかもあります。


さて、今回追加された mlock2は以下のようになっています。

int mlock2(const void *addr, size_t len, int flags);

アドレス空間の指定はmlockと変わらず、それにflagsという変数が追加された形となっています。

このflagsに現在指定可能な定数はMLOCK_LOCKEDとMLOCK_ONFAULTのふたつです。

従来と同じく、MLOCK_LOCKEDを指定した場合、指定したアドレス空間のページは直ちにメモリ上に固定されます。一方、MLOCK_ONFAULTを指定した場合、ページは初回のページフォールト後、メモリに固定されます。

これにより、利用する物理メモリ上の最大メモリが大きい一方、必要とされている固定されたメモリが小さいことが多いといった用途(暗号化など)においては、ページの固定にかかるコストを削減することが可能となります。

2. mlock, mlock2の実装

mlockとmlock2はそれぞれ以下のように実装されています。

linux/mm/mlock.c

mlock

SYSCALL_DEFINE2(mlock, unsigned long, start, size_t, len) 
{ 
return do_mlock(start, len, VM_LOCKED); 
}

mlock2

SYSCALL_DEFINE3(mlock2, unsigned long, start, size_t, len, int, flags) 
{ 
vm_flags_t vm_flags = VM_LOCKED; 


if (flags & ~MLOCK_ONFAULT) 
return -EINVAL; 

if (flags & MLOCK_ONFAULT) 
vm_flags |= VM_LOCKONFAULT; 

return do_mlock(start, len, vm_flags); 
}

どうやら、mlock2では、MLOCK_ONFAULTフラグが立っているときは、do_mlockにVM_LOCKONFAULTというフラグを追加で渡しているようです。

ではdo_mlockはどういった実装になっているのでしょうか?

static int do_mlock(unsigned long start, size_t len, vm_flags_t flags) 
{ 
unsigned long locked; 
unsigned long lock_limit; 
int error = -ENOMEM; 

if (!can_do_mlock()) 
return -EPERM; 

lru_add_drain_all(); /* flush pagevec */ 

len = PAGE_ALIGN(len + (offset_in_page(start))); 
start &= PAGE_MASK; 

lock_limit = rlimit(RLIMIT_MEMLOCK); 
lock_limit >>= PAGE_SHIFT; 
locked = len >> PAGE_SHIFT; 

down_write(&current->mm->mmap_sem); 

locked += current->mm->locked_vm; 

/* check against resource limits */ 
if ((locked <= lock_limit) || capable(CAP_IPC_LOCK)) 
error = apply_vma_lock_flags(start, len, flags); 

up_write(&current->mm->mmap_sem); 
if (error) 
return error; 

error = __mm_populate(start, len, 0); 
if (error) 
return __mlock_posix_error_return(error); 
return 0; 
}

いろいろ調べたり前処理を行い、apply_vma_lock_flagsに処理を渡しています。

static int apply_vma_lock_flags(unsigned long start, size_t len,
				vm_flags_t flags)
{
	unsigned long nstart, end, tmp;
	struct vm_area_struct * vma, * prev;
	int error;

	VM_BUG_ON(offset_in_page(start));
	VM_BUG_ON(len != PAGE_ALIGN(len));
	end = start + len;
	if (end < start)
		return -EINVAL;
	if (end == start)
		return 0;
	vma = find_vma(current->mm, start);
	if (!vma || vma->vm_start > start)
		return -ENOMEM;

	prev = vma->vm_prev;
	if (start > vma->vm_start)
		prev = vma;

	for (nstart = start ; ; ) {
		vm_flags_t newflags = vma->vm_flags & VM_LOCKED_CLEAR_MASK;

		newflags |= flags;

		/* Here we know that  vma->vm_start <= nstart < vma->vm_end. */
		tmp = vma->vm_end;
		if (tmp > end)
			tmp = end;
		error = mlock_fixup(vma, &prev, nstart, tmp, newflags);
		if (error)
			break;
		nstart = tmp;
		if (nstart < prev->vm_end)
			nstart = prev->vm_end;
		if (nstart >= end)
			break;

		vma = prev->vm_next;
		if (!vma || vma->vm_start != nstart) {
			error = -ENOMEM;
			break;
		}
	}
	return error;
}

ここでもまたいろいろと作業を行っていますが、本命はmlock_fixupのようです。

static int mlock_fixup(struct vm_area_struct *vma, struct vm_area_struct **prev,
	unsigned long start, unsigned long end, vm_flags_t newflags)
{
	struct mm_struct *mm = vma->vm_mm;
	pgoff_t pgoff;
	int nr_pages;
	int ret = 0;
	int lock = !!(newflags & VM_LOCKED);

	if (newflags == vma->vm_flags || (vma->vm_flags & VM_SPECIAL) ||
	    is_vm_hugetlb_page(vma) || vma == get_gate_vma(current->mm))
		/* don't set VM_LOCKED or VM_LOCKONFAULT and don't count */
		goto out;

	pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
	*prev = vma_merge(mm, *prev, start, end, newflags, vma->anon_vma,
			  vma->vm_file, pgoff, vma_policy(vma),
			  vma->vm_userfaultfd_ctx);
	if (*prev) {
		vma = *prev;
		goto success;
	}

	if (start != vma->vm_start) {
		ret = split_vma(mm, vma, start, 1);
		if (ret)
			goto out;
	}

	if (end != vma->vm_end) {
		ret = split_vma(mm, vma, end, 0);
		if (ret)
			goto out;
	}

success:
	/*
	 * Keep track of amount of locked VM.
	 */
	nr_pages = (end - start) >> PAGE_SHIFT;
	if (!lock)
		nr_pages = -nr_pages;
	mm->locked_vm += nr_pages;

	/*
	 * vm_flags is protected by the mmap_sem held in write mode.
	 * It's okay if try_to_unmap_one unmaps a page just after we
	 * set VM_LOCKED, populate_vma_page_range will bring it back.
	 */

	if (lock)
		vma->vm_flags = newflags;
	else
		munlock_vma_pages_range(vma, start, end);

out:
	*prev = vma;
	return ret;
}

ということで、メモリリージョンにVM_LOCKONFAULTのフラグを設定していることがわかりました。(以前はアンマップ不可を意味するVM_RESERVEDであったものがVM_LOCKONFAULTに名前を変え使われている模様です。)



さて、次に問題となるのはこのVM_LOCKONFAULTがどの場面で使われているのか?ということです。

この答えはpopulate_vma_page_rangeにあります。

linux/mm/gup.c

long populate_vma_page_range(struct vm_area_struct *vma,
		unsigned long start, unsigned long end, int *nonblocking)
{
	struct mm_struct *mm = vma->vm_mm;
	unsigned long nr_pages = (end - start) / PAGE_SIZE;
	int gup_flags;

	VM_BUG_ON(start & ~PAGE_MASK);
	VM_BUG_ON(end   & ~PAGE_MASK);
	VM_BUG_ON_VMA(start < vma->vm_start, vma);
	VM_BUG_ON_VMA(end   > vma->vm_end, vma);
	VM_BUG_ON_MM(!rwsem_is_locked(&mm->mmap_sem), mm);

	gup_flags = FOLL_TOUCH | FOLL_POPULATE | FOLL_MLOCK;
	if (vma->vm_flags & VM_LOCKONFAULT)
		gup_flags &= ~FOLL_POPULATE;

	/*
	 * We want to touch writable mappings with a write fault in order
	 * to break COW, except for shared mappings because these don't COW
	 * and we would not want to dirty them for nothing.
	 */
	if ((vma->vm_flags & (VM_WRITE | VM_SHARED)) == VM_WRITE)
		gup_flags |= FOLL_WRITE;

	/*
	 * We want mlock to succeed for regions that have any permissions
	 * other than PROT_NONE.
	 */
	if (vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC))
		gup_flags |= FOLL_FORCE;

	/*
	 * We made sure addr is within a VMA, so the following will
	 * not result in a stack expansion that recurses back here.
	 */
	return __get_user_pages(current, mm, start, nr_pages, gup_flags,
				NULL, NULL, nonblocking);
}

上記のようにメモリの配置の際、確保するユーザーページのFOLL_POPULATEフラグを削除します。


すると、ユーザーページが不足していた際に、呼ばれることとなる以下のfaultin_pageの処理がスキップされるようになります。

static int faultin_page(struct task_struct *tsk, struct vm_area_struct *vma,
		unsigned long address, unsigned int *flags, int *nonblocking)
{
	struct mm_struct *mm = vma->vm_mm;
	unsigned int fault_flags = 0;
	int ret;

	/* mlock all present pages, but do not fault in new pages */
	if ((*flags & (FOLL_POPULATE | FOLL_MLOCK)) == FOLL_MLOCK)
		return -ENOENT;
	/* For mm_populate(), just skip the stack guard page. */
	if ((*flags & FOLL_POPULATE) &&
			(stack_guard_page_start(vma, address) ||
			 stack_guard_page_end(vma, address + PAGE_SIZE)))
		return -ENOENT;
	if (*flags & FOLL_WRITE)
		fault_flags |= FAULT_FLAG_WRITE;
	if (nonblocking)
		fault_flags |= FAULT_FLAG_ALLOW_RETRY;
	if (*flags & FOLL_NOWAIT)
		fault_flags |= FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_RETRY_NOWAIT;
	if (*flags & FOLL_TRIED) {
		VM_WARN_ON_ONCE(fault_flags & FAULT_FLAG_ALLOW_RETRY);
		fault_flags |= FAULT_FLAG_TRIED;
	}

	ret = handle_mm_fault(mm, vma, address, fault_flags);
	if (ret & VM_FAULT_ERROR) {
		if (ret & VM_FAULT_OOM)
			return -ENOMEM;
		if (ret & (VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE))
			return *flags & FOLL_HWPOISON ? -EHWPOISON : -EFAULT;
		if (ret & (VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV))
			return -EFAULT;
		BUG();
	}

	if (tsk) {
		if (ret & VM_FAULT_MAJOR)
			tsk->maj_flt++;
		else
			tsk->min_flt++;
	}

	if (ret & VM_FAULT_RETRY) {
		if (nonblocking)
			*nonblocking = 0;
		return -EBUSY;
	}

	/*
	 * The VM_FAULT_WRITE bit tells us that do_wp_page has broken COW when
	 * necessary, even if maybe_mkwrite decided not to set pte_write. We
	 * can thus safely do subsequent page lookups as if they were reads.
	 * But only do so when looping for pte_write is futile: in some cases
	 * userspace may also be wanting to write to the gotten user page,
	 * which a read fault here might prevent (a readonly page might get
	 * reCOWed by userspace write).
	 */
	if ((ret & VM_FAULT_WRITE) && !(vma->vm_flags & VM_WRITE))
		*flags &= ~FOLL_WRITE;
	return 0;
}


以上の処理によってmlock2は実装されています。

3. 備考

mlock2関連の関数・変数の名称は開発中に一度変更がなされているようです。
またそのうち変更が加わるかもしれません。

4. まとめ

暗号系のソフトを開発している人はこのシステムコールを使ってみてはいかがでしょうか?