OSDN Git Service

libgo: Update to weekly.2011-12-22.
[pf3gnuchains/gcc-fork.git] / libgo / go / os / user / lookup_unix.go
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // +build darwin freebsd linux
6 // +build cgo
7
8 package user
9
10 import (
11         "fmt"
12         "strings"
13         "syscall"
14         "unsafe"
15 )
16
17 /*
18 #include <unistd.h>
19 #include <sys/types.h>
20 #include <pwd.h>
21 #include <stdlib.h>
22
23 static int mygetpwuid_r(int uid, struct passwd *pwd,
24         char *buf, size_t buflen, struct passwd **result) {
25  return getpwuid_r(uid, pwd, buf, buflen, result);
26 }
27 */
28
29 func libc_getpwnam_r(name *byte, pwd *syscall.Passwd, buf *byte, buflen syscall.Size_t, result **syscall.Passwd) int __asm__ ("getpwnam_r")
30 func libc_getpwuid_r(uid syscall.Uid_t, pwd *syscall.Passwd, buf *byte, buflen syscall.Size_t, result **syscall.Passwd) int __asm__ ("getpwuid_r")
31
32 // bytePtrToString takes a NUL-terminated array of bytes and convert
33 // it to a Go string.
34 func bytePtrToString(p *byte) string {
35         a := (*[10000]byte)(unsafe.Pointer(p))
36         i := 0
37         for a[i] != 0 {
38                 i++
39         }
40         return string(a[:i])
41 }
42
43 func init() {
44         implemented = true
45 }
46
47 // Lookup looks up a user by username. If the user cannot be found,
48 // the returned error is of type UnknownUserError.
49 func Lookup(username string) (*User, error) {
50         return lookup(-1, username, true)
51 }
52
53 // LookupId looks up a user by userid. If the user cannot be found,
54 // the returned error is of type UnknownUserIdError.
55 func LookupId(uid int) (*User, error) {
56         return lookup(uid, "", false)
57 }
58
59 func lookup(uid int, username string, lookupByName bool) (*User, error) {
60         var pwd syscall.Passwd
61         var result *syscall.Passwd
62
63         // FIXME: Should let buf grow if necessary.
64         const bufSize = 1024
65         buf := make([]byte, bufSize)
66         if lookupByName {
67                 rv := libc_getpwnam_r(syscall.StringBytePtr(username),
68                         &pwd,
69                         &buf[0],
70                         bufSize,
71                         &result)
72                 if rv != 0 {
73                         return nil, fmt.Errorf("user: lookup username %s: %s", username, syscall.GetErrno())
74                 }
75                 if result == nil {
76                         return nil, UnknownUserError(username)
77                 }
78         } else {
79                 rv := libc_getpwuid_r(syscall.Uid_t(uid),
80                         &pwd,
81                         &buf[0],
82                         bufSize,
83                         &result)
84                 if rv != 0 {
85                         return nil, fmt.Errorf("user: lookup userid %d: %s", uid, syscall.GetErrno())
86                 }
87                 if result == nil {
88                         return nil, UnknownUserIdError(uid)
89                 }
90         }
91         u := &User{
92                 Uid:      int(pwd.Pw_uid),
93                 Gid:      int(pwd.Pw_gid),
94                 Username: bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_name))),
95                 Name:     bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_gecos))),
96                 HomeDir:  bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_dir))),
97         }
98         // The pw_gecos field isn't quite standardized.  Some docs
99         // say: "It is expected to be a comma separated list of
100         // personal data where the first item is the full name of the
101         // user."
102         if i := strings.Index(u.Name, ","); i >= 0 {
103                 u.Name = u.Name[:i]
104         }
105         return u, nil
106 }