OSDN Git Service

ebc8684825db6e5b74a8a10432c264e82ce97f99
[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         "strconv"
13         "strings"
14         "syscall"
15         "unsafe"
16 )
17
18 /*
19 #include <unistd.h>
20 #include <sys/types.h>
21 #include <pwd.h>
22 #include <stdlib.h>
23
24 static int mygetpwuid_r(int uid, struct passwd *pwd,
25         char *buf, size_t buflen, struct passwd **result) {
26  return getpwuid_r(uid, pwd, buf, buflen, result);
27 }
28 */
29
30 //extern getpwnam_r
31 func libc_getpwnam_r(name *byte, pwd *syscall.Passwd, buf *byte, buflen syscall.Size_t, result **syscall.Passwd) int
32
33 //extern getpwuid_r
34 func libc_getpwuid_r(uid syscall.Uid_t, pwd *syscall.Passwd, buf *byte, buflen syscall.Size_t, result **syscall.Passwd) int
35
36 // bytePtrToString takes a NUL-terminated array of bytes and convert
37 // it to a Go string.
38 func bytePtrToString(p *byte) string {
39         a := (*[10000]byte)(unsafe.Pointer(p))
40         i := 0
41         for a[i] != 0 {
42                 i++
43         }
44         return string(a[:i])
45 }
46
47 // Current returns the current user. 
48 func Current() (*User, error) {
49         return lookup(syscall.Getuid(), "", false)
50 }
51
52 // Lookup looks up a user by username. If the user cannot be found,
53 // the returned error is of type UnknownUserError.
54 func Lookup(username string) (*User, error) {
55         return lookup(-1, username, true)
56 }
57
58 // LookupId looks up a user by userid. If the user cannot be found,
59 // the returned error is of type UnknownUserIdError.
60 func LookupId(uid string) (*User, error) {
61         i, e := strconv.Atoi(uid)
62         if e != nil {
63                 return nil, e
64         }
65         return lookup(i, "", false)
66 }
67
68 func lookup(uid int, username string, lookupByName bool) (*User, error) {
69         var pwd syscall.Passwd
70         var result *syscall.Passwd
71
72         // FIXME: Should let buf grow if necessary.
73         const bufSize = 1024
74         buf := make([]byte, bufSize)
75         if lookupByName {
76                 p := syscall.StringBytePtr(username)
77                 syscall.Entersyscall()
78                 rv := libc_getpwnam_r(p,
79                         &pwd,
80                         &buf[0],
81                         bufSize,
82                         &result)
83                 syscall.Exitsyscall()
84                 if rv != 0 {
85                         return nil, fmt.Errorf("user: lookup username %s: %s", username, syscall.GetErrno())
86                 }
87                 if result == nil {
88                         return nil, UnknownUserError(username)
89                 }
90         } else {
91                 syscall.Entersyscall()
92                 rv := libc_getpwuid_r(syscall.Uid_t(uid),
93                         &pwd,
94                         &buf[0],
95                         bufSize,
96                         &result)
97                 syscall.Exitsyscall()
98                 if rv != 0 {
99                         return nil, fmt.Errorf("user: lookup userid %d: %s", uid, syscall.GetErrno())
100                 }
101                 if result == nil {
102                         return nil, UnknownUserIdError(uid)
103                 }
104         }
105         u := &User{
106                 Uid:      strconv.Itoa(int(pwd.Pw_uid)),
107                 Gid:      strconv.Itoa(int(pwd.Pw_gid)),
108                 Username: bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_name))),
109                 Name:     bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_gecos))),
110                 HomeDir:  bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_dir))),
111         }
112         // The pw_gecos field isn't quite standardized.  Some docs
113         // say: "It is expected to be a comma separated list of
114         // personal data where the first item is the full name of the
115         // user."
116         if i := strings.Index(u.Name, ","); i >= 0 {
117                 u.Name = u.Name[:i]
118         }
119         return u, nil
120 }