mod_dbd_mysql
/configure \ --prefix=/usr/local/httpd-2.2.11 \ --enable-modules=most \ --enable-mods-shared=most \ --with-mysql=/opt/local/mysql5 \ --with-included-apr \ --enable-dbd=shared
落とし穴
- MySQLクライアントがスレッドセーフ(libmysqlclient_r)である必要がる。
- ./configure --enable-thread-safe-client
- スレッドセーフでない?libmysqlclientだとリンクしてくれないのかな(MPMがworkerでなければリンクするのかもしれない)
mlockall()呼び出して、メモリ空間をロック、ページアウトしないようにする
http://www.linux.or.jp/JM/html/LDP_man-pages/man2/mlock.2.html #!/usr/bin/perl use strict; use warnings; use Inline C => 'DATA'; c_mlockall(); sleep 100; __END__ __C__ #include <sys/mman.h> int c_mlockall() { return mlockall(MCL_CURRENT|MCL_FUTURE); }
バックグラウントで実行して。ページ獲得するのに時間かかるみたいだから少し置いてから ps aux
root 1311 2.2 1.6 8304 8304 pts/0 SL 14:59 0:00 \_ perl test.pl
- VSS == RSS になってる
- SL ( Sleep + ページロック ) のフラグがたってる
todo
あんまり評判よくないのは何なのかを追って見る
sys_chroot
プロセス単位で有効
- current->fs->root, current->fs->rootmntを指定したディレクトリのもので書き変えるだけ
572 573 asmlinkage long sys_chroot(const char __user * filename) 574 { 575 struct nameidata nd; 576 int error; 577 // chrootするディレクトリのnameidataを取得 578 error = __user_walk(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd); 579 if (error) 580 goto out; 581 // パーミッション 582 error = permission(nd.dentry->d_inode,MAY_EXEC,&nd); 583 if (error) 584 goto dput_and_out; 585 // CAP_SYS_CHROOTケーパビリティが必要 586 error = -EPERM; 587 if (!capable(CAP_SYS_CHROOT)) 588 goto dput_and_out; 589 590 // 現在のプロセスのfs(fs_struct)に、chroot先として指定したディレクトリのvfsmount,dentryをセットする 591 set_fs_root(current->fs, nd.mnt, nd.dentry); 592 593 // altrootmnt//altrootをセットする??? => x86アーキテクチャでは常にNULLなので関係ない 594 set_fs_altroot(); 595 error = 0; 596 dput_and_out: 597 path_release(&nd); 598 out: 599 return error; 600 } 1215 /* 1216 * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values. 1217 * It can block. Requires the big lock held. 1218 */ 1219 void set_fs_root(struct fs_struct *fs, struct vfsmount *mnt, 1220 struct dentry *dentry) 1221 { 1222 struct dentry *old_root; 1223 struct vfsmount *old_rootmnt; 1224 1225 // fsは現在のプロセスのfs_struct 1226 write_lock(&fs->lock); 1227 old_root = fs->root; 1228 old_rootmnt = fs->rootmnt; 1229 1230 // 指定したパスのvfsmountを新しいvfsmountにする 1231 // mntgetはmnt_countをインクリする 1232 fs->rootmnt = mntget(mnt); 1233 1234 // 指定したパスのdentryをrootとして設定する 1235 // dgetは d_countをインクリする 1236 fs->root = dget(dentry); 1237 write_unlock(&fs->lock); 1238 if (old_root) { 1239 dput(old_root); 1240 mntput(old_rootmnt); 1241 } 1242 }
dentryの生成と初期化を追う
- どこのレイヤーを処理してるのかを見失わないように
- dentry
- inodeオブジェクト
- super_block
- ext3_*
struct inode_operations ext3_dir_inode_operations = { /* ... */ .lookup = ext3_lookup, /* ... */ }
- lookup ... dentry操作の抽象化
- iget ... inode操作の抽象化 ... ext3層でinode操作
- inode->i_op->lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
- reallookup
- lookup ---> ext3_lookup
- iget .. inodeオブジェクト割当、super_blockのread_inodeでディスクinode情報で初期化
- iget_locked ...
-
- get_new_inode_fast
- alloc_inode
- get_new_inode_fast
- ifind_fast ... スピンロック,ディスクの待ち合わせ?
- find_inode_fast ... inodeオブジェクトテーブルの探索
-
- iget_locked ...
- reallookup
- ext3_read_inode ... ディスクinodeの情報を読み取り、inodeオブジェクトにセットする
- [fs/namei.c] real_lookup
/* * This is called when everything else fails, and we actually have * to go to the low-level filesystem to find out what we should do.. * * We get the directory semaphore, and after getting that we also * make sure that nobody added the entry to the dcache in the meantime.. * SMP-safe */ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, struct nameidata *nd) { struct dentry * result; struct inode *dir = parent->d_inode; // 親dentryのinode .. ディレクトリ // セマフォ down(&dir->i_sem); /* * First re-do the cached lookup just in case it was created * while we waited for the directory semaphore.. * * FIXME! This could use version numbering or similar to * avoid unnecessary cache lookups. * * The "dcache_lock" is purely to protect the RCU list walker * from concurrent renames at this point (we mustn't get false * negatives from the RCU list walk here, unlike the optimistic * fast walk). * * so doing d_lookup() (with seqlock), instead of lockfree __d_lookup */ result = d_lookup(parent, name); if (!result) { // dentryの割当 struct dentry * dentry = d_alloc(parent, name); result = ERR_PTR(-ENOMEM); if (dentry) { //inode探索のコストはファイルシステムに依る // fs/ext3/namei.c result = dir->i_op->lookup(dir, dentry, nd); if (result) dput(dentry); else result = dentry; } up(&dir->i_sem); return result; } /* * Uhhuh! Nasty case: the cache was re-populated while * we waited on the semaphore. Need to revalidate. */ up(&dir->i_sem); if (result->d_op && result->d_op->d_revalidate) { if (!result->d_op->d_revalidate(result, nd) && !d_invalidate(result)) { dput(result); result = ERR_PTR(-ENOENT); } } return result; }
- ext3_lookup
// [fs/namei.c] real_lookup -> inode->i_op->lookup static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { struct inode * inode; struct ext3_dir_entry_2 * de; // ext3のディレクトリエントリ //新しいバージョン? struct buffer_head * bh; // dentry->d_name -> struct qstr ( 長さとハッシュを保持しているので 探索、比較が速い文字列として扱える?) if (dentry->d_name.len > EXT3_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); bh = ext3_find_entry(dentry, &de); // ディレクトリエントリの探索 -> bufferから探索 inode = NULL; if (bh) { unsigned long ino = le32_to_cpu(de->inode); // inode番号 brelse (bh); // ディレクトリエントリのinode番号からinodeの取得 -> 必要であればディスクinodeから読み込む inode = iget(dir->i_sb, ino); if (!inode) return ERR_PTR(-EACCES); } if (inode) //-> d_add -> d_instantiate -> dentry->d_inode = inode する //-> d_rehash -> ハッシュ? return d_splice_alias(inode, dentry); d_add(dentry, inode); return NULL; } // dirは親ディレクトリのinodeオブジェクト // dentryは親ディレクトリのdentry static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { inode = iget(dir->i_sb, ino); } //iget .. inodeオブジェクト割当、super_blockのread_inodeでディスクinode情報で初期化 1389 static inline struct inode *iget(struct super_block *sb, unsigned long ino) 1390 { 1391 struct inode *inode = iget_locked(sb, ino); 1392 1393 if (inode && (inode->i_state & I_NEW)) { // inodeオブジェクトの状態がI_NEW ... inodeオブジェクトが割当済み、ディスクのinodeの情報で初期化されてない 1394 sb->s_op->read_inode(inode); /// ext3_read_inode .. ディスクのinode読み取り、初期化 1395 unlock_new_inode(inode); 1396 } 1397 1398 return inode; 1399 } //// static struct hlist_head *inode_hashtable 932 struct inode *iget_locked(struct super_block *sb, unsigned long ino) 933 { 934 struct hlist_head *head = inode_hashtable + hash(sb, ino); 935 struct inode *inode; 936 937 inode = ifind_fast(sb, head, ino); 938 if (inode) 939 return inode; 940 /* 941 * get_new_inode_fast() will do the right thing, re-trying the search 942 * in case it had to block at any point. 943 */ 944 return get_new_inode_fast(sb, head, ino); 945 } // ifind_fast ... スピンロック,ディスクの待ち合わせ? 805 static inline struct inode *ifind_fast(struct super_block *sb, 806 struct hlist_head *head, unsigned long ino) 807 { 808 struct inode *inode; 809 810 spin_lock(&inode_lock); 811 inode = find_inode_fast(sb, head, ino); 812 if (inode) { 813 __iget(inode); 814 spin_unlock(&inode_lock); 815 wait_on_inode(inode); 816 return inode; 817 } 818 spin_unlock(&inode_lock); 819 return NULL; 820 } 221 /* 222 * inode_lock must be held 223 */ 224 void __iget(struct inode * inode) 225 { 226 if (atomic_read(&inode->i_count)) { 227 atomic_inc(&inode->i_count); 228 return; 229 } 230 atomic_inc(&inode->i_count); 231 if (!(inode->i_state & (I_DIRTY|I_LOCK))) 232 list_move(&inode->i_list, &inode_in_use); 233 inodes_stat.nr_unused--; 234 } // find_inode_fast ... inodeオブジェクトテーブルの探索 524 /* 525 * find_inode_fast is the fast path version of find_inode, see the comment at 526 * iget_locked for details. 527 */ 528 static struct inode * find_inode_fast(struct super_block * sb, struct hlist_head *head, unsigned long ino) 529 { 530 struct hlist_node *node; 531 struct inode * inode = NULL; 532 533 repeat: // リスト探索 534 hlist_for_each (node, head) { 535 inode = hlist_entry(node, struct inode, i_hash); 536 if (inode->i_ino != ino) 537 continue; 538 if (inode->i_sb != sb) 539 continue; 540 if (inode->i_state & (I_FREEING|I_CLEAR)) { 541 __wait_on_freeing_inode(inode); 542 goto repeat; 543 } 544 break; 545 } 546 return node ? inode : NULL; 547 } // caller: iget_locked /* * get_new_inode_fast is the fast path version of get_new_inode, see the * comment at iget_locked for details. */ static struct inode * get_new_inode_fast(struct super_block *sb, struct hlist_head *head, unsigned long ino) { struct inode * inode; // 割当 inode = alloc_inode(sb); if (inode) { struct inode * old; spin_lock(&inode_lock); /* We released the lock, so.. */ old = find_inode_fast(sb, head, ino); if (!old) { inode->i_ino = ino; inodes_stat.nr_inodes++; list_add(&inode->i_list, &inode_in_use); hlist_add_head(&inode->i_hash, head); // I_NEW ... アロケート済み、初期化されてない inode->i_state = I_LOCK|I_NEW; spin_unlock(&inode_lock); /* Return the locked inode with I_NEW set, the * caller is responsible for filling in the contents */ return inode; } /* * Uhhuh, somebody else created the same inode under * us. Use the old inode instead of the one we just * allocated. */ __iget(old); spin_unlock(&inode_lock); destroy_inode(inode); inode = old; wait_on_inode(inode); } return inode; } // inodeオブジェクトの割当 static struct inode *alloc_inode(struct super_block *sb) { static struct address_space_operations empty_aops; static struct inode_operations empty_iops; static struct file_operations empty_fops; struct inode *inode; if (sb->s_op->alloc_inode) inode = sb->s_op->alloc_inode(sb); else inode = (struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL); if (inode) { //inodeの初期化 //ファイルシステムに依存しないパラメータの初期化 struct address_space * const mapping = &inode->i_data; inode->i_sb = sb; inode->i_blkbits = sb->s_blocksize_bits; inode->i_flags = 0; atomic_set(&inode->i_count, 1); inode->i_sock = 0; inode->i_op = &empty_iops; inode->i_fop = &empty_fops; inode->i_nlink = 1; atomic_set(&inode->i_writecount, 0); inode->i_size = 0; inode->i_blocks = 0; inode->i_bytes = 0; inode->i_generation = 0; #ifdef CONFIG_QUOTA memset(&inode->i_dquot, 0, sizeof(inode->i_dquot)); #endif inode->i_pipe = NULL; inode->i_bdev = NULL; inode->i_cdev = NULL; inode->i_rdev = 0; inode->i_security = NULL; inode->dirtied_when = 0; if (security_inode_alloc(inode)) { if (inode->i_sb->s_op->destroy_inode) inode->i_sb->s_op->destroy_inode(inode); else kmem_cache_free(inode_cachep, (inode)); return NULL; } mapping->a_ops = &empty_aops; mapping->host = inode; mapping->flags = 0; mapping_set_gfp_mask(mapping, GFP_HIGHUSER); mapping->assoc_mapping = NULL; mapping->backing_dev_info = &default_backing_dev_info; /* * If the block_device provides a backing_dev_info for client * inodes then use that. Otherwise the inode share the bdev's * backing_dev_info. */ if (sb->s_bdev) { struct backing_dev_info *bdi; bdi = sb->s_bdev->bd_inode_backing_dev_info; if (!bdi) bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info; mapping->backing_dev_info = bdi; } memset(&inode->u, 0, sizeof(inode->u)); inode->i_mapping = mapping; } return inode; }
loadavg_read_proc
ロードアベレージの算出方法
- runqueue
- TASK_RUNNING, TASK_UNINTERRUPTIBLE
- procfs
- タイマ割り込み
- ticks , HZ
63 /* 64 * These are the constant used to fake the fixed-point load-average 65 * counting. Some notes: // faction .. 分数、割合 66 * - 11 bit fractions expand to 22 bits by the multiplies: this gives 67 * a load-average precision of 10 bits integer + 11 bits fractional 68 * - if you want to count load-averages more often, you need more 69 * precision, or rounding will get you. With 2-second counting freq, 70 * the EXP_n values would be 1981, 2034 and 2043 if still using only 71 * 11 bit fractions. 72 */ 73 extern unsigned long avenrun[]; /* Load averages */ 74 75 #define FSHIFT 11 /* nr of bits of precision */ 76 #define FIXED_1 (1<<FSHIFT) /* 1.0 as fixed-point */ 77 #define LOAD_FREQ (5*HZ) /* 5 sec intervals */ 78 #define EXP_1 1884 /* 1/exp(5sec/1min) as fixed-point */ 79 #define EXP_5 2014 /* 1/exp(5sec/5min) */ 80 #define EXP_15 2037 /* 1/exp(5sec/15min) */ 81 82 #define CALC_LOAD(load,exp,n) \ 83 load *= exp; \ 84 load += n*(FIXED_1-exp); \ 85 load >>= FSHIFT; // FSHIFT ... 11? /* #define LOAD_INT(x) ((x) >> FSHIFT) */ /* #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) */ static int loadavg_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { int a, b, c; int len; // avenrun ... kernel/timer.cのグローバル変数 a = avenrun[0] + (FIXED_1/200); b = avenrun[1] + (FIXED_1/200); c = avenrun[2] + (FIXED_1/200); len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n", LOAD_INT(a), LOAD_FRAC(a), LOAD_INT(b), LOAD_FRAC(b), LOAD_INT(c), LOAD_FRAC(c), // TASK_RUNNINGの数 .. kernel/sched.c // スレッドの数 // 最後のプロセスのpid nr_running(), nr_threads, last_pid); return proc_calc_metrics(page, start, off, count, eof, len); } /* * nr_running, nr_uninterruptible and nr_context_switches: * * externally visible scheduler statistics: current number of runnable * threads, current number of uninterruptible-sleeping threads, total * number of context switches performed since bootup. */ // TASK_RUNNING と TASK_UNINTERRUPTIBLE unsigned long nr_running(void) { unsigned long i, sum = 0; // CPUごとのrunqueueを見て、nr_runningを足す for_each_online_cpu(i) sum += cpu_rq(i)->nr_running; // TASK_RUNNING return sum; } unsigned long nr_uninterruptible(void) { unsigned long i, sum = 0; // CPUごとのrunqueue, TASK_UNINTERRUPTIBLEの数を総計する for_each_cpu(i) sum += cpu_rq(i)->nr_uninterruptible; // TASK_UNINTERRUPTIBLE return sum; } /* * Nr of active tasks - counted in fixed-point numbers */ static unsigned long count_active_tasks(void) { // 全てのCPUのTASK_RUNNING + TASK_UNINTERRUPTIBLE return (nr_running() + nr_uninterruptible()) * FIXED_1; } /* * calc_load - given tick count, update the avenrun load estimates. * This is called while holding a write_lock on xtime_lock. */ static inline void calc_load(unsigned long ticks) { unsigned long active_tasks; /* fixed-point */ static int count = LOAD_FREQ; count -= ticks; if (count < 0) { count += LOAD_FREQ; active_tasks = count_active_tasks(); // TASK_RUNNING + TASK_UNINTERRUPTIBLE CALC_LOAD(avenrun[0], EXP_1, active_tasks); CALC_LOAD(avenrun[1], EXP_5, active_tasks); CALC_LOAD(avenrun[2], EXP_15, active_tasks); } } /* * Called by the timer interrupt. xtime_lock must already be taken * by the timer IRQ! */ // タイマ割り込み 1/1000 とか 1/100 秒とかで static inline void update_times(void) { unsigned long ticks; ticks = jiffies - wall_jiffies; if (ticks) { wall_jiffies += ticks; update_wall_time(ticks); } // ここで計算 calc_load(ticks); }
kernel module , seq_file , テンプレ
シェルをテンプレートにするのもナンだけど。
#!/bin/sh MODULE=mymodule AUTHOR=hoge cat <<EOF #include <linux/errno.h> #include <linux/init.h> #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/version.h> static void *${MODULE}_seq_start(struct seq_file *s, loff_t *pos) { if(*pos >= 1) return NULL; return pos; } static void *${MODULE}_seq_next(struct seq_file *s, void *v, loff_t *pos) { return 0; } static void ${MODULE}_seq_stop(struct seq_file *m, void *p) { } static int ${MODULE}_seq_show(struct seq_file *s, void *v) { return 0; } static struct seq_operations ${MODULE}_seq_ops = { .start = ${MODULE}_seq_start, .next = ${MODULE}_seq_next, .stop = ${MODULE}_seq_stop, .show = ${MODULE}_seq_show }; static int ${MODULE}_proc_open(struct inode *inode, struct file *file) { return seq_open(file, &${MODULE}_seq_ops); } static struct file_operations ${MODULE}_proc_ops = { .owner = THIS_MODULE, .open = ${MODULE}_proc_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; static int __init ${MODULE}_init(void) { struct proc_dir_entry *pdentry = create_proc_entry("${MODULE}", 0, NULL); if(pdentry) pdentry->proc_fops = &${MODULE}_proc_ops; return 0; } static void __exit ${MODULE}_exit(void) { remove_proc_entry("${MODULE}", NULL ); } module_init(${MODULE}_init); module_exit(${MODULE}_exit); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("${AUTHOR}"); MODULE_DESCRIPTION(""); MODULE_VERSION("1"); MODULE_ALIAS("${MODULE}"); EOF
#!bin/bash MODULE=mymodule cat <<EOF obj-m := ${MODULE}.o KDIR := /lib/modules/\$(shell uname -r)/build PWD := \$(shell pwd) default: \$(MAKE) -Wall -Wstrict-prototypes -C \$(KDIR) SUBDIRS=\$(PWD) modules install: ${MODULE}.o insmod ${MODULE}.ko uninstall: ${MODULE}.o rmmod ${MODULE}.ko EOF
[linux] proftpd
lsで表示 => ユーザー名扱うところまで
// ログインしてls static int listfile(cmd_rec *cmd, pool *p, const char *name) { /* ... */ if (!opt_n) { /* Format nameline using user/group names. */ snprintf(nameline, sizeof(nameline)-1, "%s %3d %-8s %-8s %s %s %2d %s %s", m, (int) st.st_nlink, MAP_UID(st.st_uid), MAP_GID(st.st_gid), s, months[t->tm_mon], t->tm_mday, timeline, name); } // fakeuser ... 見せかけユーザー #define MAP_UID(x) (fakeuser ? fakeuser : auth_uid_name(cmd->tmp_pool,(x))) // uidからユーザー名を決定する( ディスパッチャに投げて決定 ) const char *auth_uid_name(pool *p, uid_t uid) { cmd_rec *cmd = NULL; modret_t *mr = NULL; static char namebuf[64]; char *res = "(?)"; memset(namebuf, '\0', sizeof(namebuf)); cmd = make_cmd(p, 1, (void *) uid); // uid_name でディスパッチ mr = dispatch_auth(cmd, "uid_name"); if (MODRET_ISHANDLED(mr) && MODRET_HASDATA(mr)) { res = mr->data; sstrncpy(namebuf, res, sizeof(namebuf)); res = namebuf; } if (cmd->tmp_pool) { destroy_pool(cmd->tmp_pool); cmd->tmp_pool = NULL; } return res; } // モジュールにコマンドをディスパッチする static modret_t *dispatch_auth(cmd_rec *cmd, char *match) { authtable *authtab = NULL; modret_t *mr = NULL; // ? authtab = pr_stash_get_symbol(PR_SYM_AUTH, match, NULL, &cmd->stash_index); while (authtab) { pr_log_debug(DEBUG6, "dispatching auth request \"%s\" to module mod_%s", match, authtab->m->name); mr = call_module(authtab->m, authtab->handler, cmd); if (MODRET_ISHANDLED(mr) || MODRET_ISERROR(mr)) break; authtab = pr_stash_get_symbol(PR_SYM_AUTH, match, authtab, &cmd->stash_index); } return mr; } void *pr_stash_get_symbol(pr_stash_type_t sym_type, const char *name, void *prev, int *idx_cache) { int idx; struct stash *sym = NULL; if (idx_cache && *idx_cache != -1) idx = *idx_cache; else { /* XXX Ugly hack to support mixed cases of directives in config files. */ if (sym_type != PR_SYM_CONF) idx = symtab_hash(name); else { register unsigned int i; char buf[1024]; memset(buf, '\0', sizeof(buf)); sstrncpy(buf, name, sizeof(buf)-1); for (i = 0; i < strlen(buf); i++) buf[i] = tolower((int) buf[i]); idx = symtab_hash(buf); } if (idx_cache) *idx_cache = idx; } if (idx >= PR_TUNABLE_HASH_TABLE_SIZE) { if (*idx_cache) *idx_cache = -1; return NULL; } if (prev) curr_sym = sym = stash_lookup_next(sym_type, name, idx, prev); else curr_sym = sym = stash_lookup(sym_type, name, idx); switch (sym_type) { case PR_SYM_CONF: return sym ? sym->ptr.sym_conf : NULL; case PR_SYM_CMD: return sym ? sym->ptr.sym_cmd : NULL; case PR_SYM_AUTH: return sym ? sym->ptr.sym_auth : NULL; case PR_SYM_HOOK: return sym ? sym->ptr.sym_hook : NULL; } /* In case the compiler complains */ return NULL; } // ディスパッチテーブル static authtable auth_unix_authtab[] = { { 0, "setpwent", pw_setpwent }, { 0, "endpwent", pw_endpwent }, { 0, "setgrent", pw_setgrent }, { 0, "endgrent", pw_endgrent }, { 0, "getpwent", pw_getpwent }, { 0, "getgrent", pw_getgrent }, { 0, "getpwnam", pw_getpwnam }, { 0, "getpwuid", pw_getpwuid }, { 0, "getgrnam", pw_getgrnam }, { 0, "getgrgid", pw_getgrgid }, { 0, "auth", pw_auth }, { 0, "check", pw_check }, { 0, "uid_name", pw_uid2name }, { 0, "gid_name", pw_gid2name }, { 0, "name_uid", pw_name2uid }, { 0, "name_gid", pw_name2gid }, { 0, "getgroups", pw_getgroups }, { 0, NULL } }; MODRET pw_uid2name(cmd_rec *cmd) { idmap_t *m; idauth_t id; struct passwd *pw; id.uid = (uid_t) cmd->argv[0]; m = _auth_lookup_id(uid_table, id); if (!m->name) { /* Wasn't cached, so perform a lookup */ if (PERSISTENT_PASSWD) pw = p_getpwuid(id.uid); // ここ else pw = getpwuid(id.uid); // ここ if (pw) { m->name = pstrdup(session.pool ? session.pool : permanent_pool, pw->pw_name); return mod_create_data(cmd, m->name); } return DECLINED(cmd); } return mod_create_data(cmd, m->name); } static struct passwd *p_getpwuid(uid_t uid) { struct passwd *pw = NULL; p_setpwent(); while ((pw = p_getpwent()) != NULL) if (pw->pw_uid == uid) break; return pw; } static void p_setpwent(void) { if (pwdf) rewind(pwdf); else if ((pwdf = fopen(PASSWD,"r")) == NULL) pr_log_pri(PR_LOG_ERR, "Unable to open password file %s for reading: %s", PASSWD, strerror(errno)); }
[c] snippet
- passwd複製
728 static struct passwd *passwd_dup(pool *p, struct passwd *pw) { 729 struct passwd *npw; 730 731 npw = pcalloc(p,sizeof(struct passwd)); 732 733 npw->pw_name = pstrdup(p,pw->pw_name); 734 npw->pw_passwd = pstrdup(p,pw->pw_passwd); 735 npw->pw_uid = pw->pw_uid; 736 npw->pw_gid = pw->pw_gid; 737 npw->pw_gecos = pstrdup(p,pw->pw_gecos); 738 npw->pw_dir = pstrdup(p,pw->pw_dir); 739 npw->pw_shell = pstrdup(p,pw->pw_shell); 740 741 return npw; 742 }