OSDN Git Service

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