Blob


1 #include <u.h>
2 #define NOPLAN9DEFINES
3 #include <libc.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <dirent.h>
7 #include <pwd.h>
8 #include <grp.h>
10 #if defined(__FreeBSD__)
11 #include <sys/disk.h>
12 #include <sys/disklabel.h>
13 #include <sys/ioctl.h>
14 #endif
16 #if defined(__OpenBSD__)
17 #include <sys/disklabel.h>
18 #include <sys/ioctl.h>
19 #define _HAVEDISKLABEL
20 static int diskdev[] = {
21 151, /* aacd */
22 116, /* ad */
23 157, /* ar */
24 118, /* afd */
25 133, /* amrd */
26 13, /* da */
27 102, /* fla */
28 109, /* idad */
29 95, /* md */
30 131, /* mlxd */
31 168, /* pst */
32 147, /* twed */
33 43, /* vn */
34 3, /* wd */
35 87, /* wfd */
36 4, /* da on FreeBSD 5 */
37 };
38 static int
39 isdisk(struct stat *st)
40 {
41 int i, dev;
43 if(!S_ISCHR(st->st_mode))
44 return 0;
45 dev = major(st->st_rdev);
46 for(i=0; i<nelem(diskdev); i++)
47 if(diskdev[i] == dev)
48 return 1;
49 return 0;
50 }
51 #endif
53 #if defined(__FreeBSD__) /* maybe OpenBSD too? */
54 char *diskdev[] = {
55 "aacd",
56 "ad",
57 "ar",
58 "afd",
59 "amrd",
60 "da",
61 "fla",
62 "idad",
63 "md",
64 "mlxd",
65 "pst",
66 "twed",
67 "vn",
68 "wd",
69 "wfd",
70 "da",
71 };
72 static int
73 isdisk(struct stat *st)
74 {
75 char *name;
76 int i, len;
78 if(!S_ISCHR(st->st_mode))
79 return 0;
80 name = devname(st->st_rdev, S_IFCHR);
81 for(i=0; i<nelem(diskdev); i++){
82 len = strlen(diskdev[i]);
83 if(strncmp(diskdev[i], name, len) == 0 && isdigit((uchar)name[len]))
84 return 1;
85 }
86 return 0;
87 }
88 #endif
91 #if defined(__linux__)
92 #include <linux/hdreg.h>
93 #include <linux/fs.h>
94 #include <sys/ioctl.h>
95 #undef major
96 #define major(dev) ((int)(((dev) >> 8) & 0xff))
97 static vlong
98 disksize(int fd, int dev)
99 {
100 u64int u64;
101 long l;
102 struct hd_geometry geo;
104 memset(&geo, 0, sizeof geo);
105 l = 0;
106 u64 = 0;
107 #ifdef BLKGETSIZE64
108 if(ioctl(fd, BLKGETSIZE64, &u64) >= 0)
109 return u64;
110 #endif
111 if(ioctl(fd, BLKGETSIZE, &l) >= 0)
112 return l*512;
113 if(ioctl(fd, HDIO_GETGEO, &geo) >= 0)
114 return (vlong)geo.heads*geo.sectors*geo.cylinders*512;
115 return 0;
117 #define _HAVEDISKSIZE
118 #endif
120 #if !defined(__linux__) && !defined(__sun__)
121 #define _HAVESTGEN
122 #endif
124 int _p9usepwlibrary = 1;
125 /*
126 * Caching the last group and passwd looked up is
127 * a significant win (stupidly enough) on most systems.
128 * It's not safe for threaded programs, but neither is using
129 * getpwnam in the first place, so I'm not too worried.
130 */
131 int
132 _p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *estr)
134 char *s;
135 char tmp[20];
136 static struct group *g;
137 static struct passwd *p;
138 static int gid, uid;
139 int sz, fd;
141 fd = -1;
142 USED(fd);
143 sz = 0;
144 if(d)
145 memset(d, 0, sizeof *d);
147 /* name */
148 s = strrchr(name, '/');
149 if(s)
150 s++;
151 if(!s || !*s)
152 s = name;
153 if(*s == '/')
154 s++;
155 if(*s == 0)
156 s = "/";
157 if(d){
158 if(*str + strlen(s)+1 > estr)
159 d->name = "oops";
160 else{
161 strcpy(*str, s);
162 d->name = *str;
163 *str += strlen(*str)+1;
166 sz += strlen(s)+1;
168 /* user */
169 if(p && st->st_uid == uid && p->pw_uid == uid)
171 else if(_p9usepwlibrary){
172 p = getpwuid(st->st_uid);
173 uid = st->st_uid;
175 if(p == nil || st->st_uid != uid || p->pw_uid != uid){
176 snprint(tmp, sizeof tmp, "%d", (int)st->st_uid);
177 s = tmp;
178 }else
179 s = p->pw_name;
180 sz += strlen(s)+1;
181 if(d){
182 if(*str+strlen(s)+1 > estr)
183 d->uid = "oops";
184 else{
185 strcpy(*str, s);
186 d->uid = *str;
187 *str += strlen(*str)+1;
191 /* group */
192 if(g && st->st_gid == gid && g->gr_gid == gid)
194 else if(_p9usepwlibrary){
195 g = getgrgid(st->st_gid);
196 gid = st->st_gid;
198 if(g == nil || st->st_gid != gid || g->gr_gid != gid){
199 snprint(tmp, sizeof tmp, "%d", (int)st->st_gid);
200 s = tmp;
201 }else
202 s = g->gr_name;
203 sz += strlen(s)+1;
204 if(d){
205 if(*str + strlen(s)+1 > estr)
206 d->gid = "oops";
207 else{
208 strcpy(*str, s);
209 d->gid = *str;
210 *str += strlen(*str)+1;
214 if(d){
215 d->type = 'M';
217 d->muid = "";
218 d->qid.path = ((uvlong)st->st_dev<<32) | st->st_ino;
219 #ifdef _HAVESTGEN
220 d->qid.vers = st->st_gen;
221 #endif
222 if(d->qid.vers == 0)
223 d->qid.vers = st->st_mtime + st->st_ctime;
224 d->mode = st->st_mode&0777;
225 d->atime = st->st_atime;
226 d->mtime = st->st_mtime;
227 d->length = st->st_size;
229 if(S_ISDIR(st->st_mode)){
230 d->length = 0;
231 d->mode |= DMDIR;
232 d->qid.type = QTDIR;
234 if(S_ISLNK(lst->st_mode)) /* yes, lst not st */
235 d->mode |= DMSYMLINK;
236 if(S_ISFIFO(st->st_mode))
237 d->mode |= DMNAMEDPIPE;
238 if(S_ISSOCK(st->st_mode))
239 d->mode |= DMSOCKET;
240 if(S_ISBLK(st->st_mode)){
241 d->mode |= DMDEVICE;
242 d->qid.path = ('b'<<16)|st->st_rdev;
244 if(S_ISCHR(st->st_mode)){
245 d->mode |= DMDEVICE;
246 d->qid.path = ('c'<<16)|st->st_rdev;
248 /* fetch real size for disks */
249 #ifdef _HAVEDISKSIZE
250 if(S_ISBLK(st->st_mode) && (fd = open(name, O_RDONLY)) >= 0){
251 d->length = disksize(fd, major(st->st_dev));
252 close(fd);
254 #endif
255 #if defined(DIOCGMEDIASIZE)
256 if(isdisk(st)){
257 int fd;
258 off_t mediasize;
260 if((fd = open(name, O_RDONLY)) >= 0){
261 if(ioctl(fd, DIOCGMEDIASIZE, &mediasize) >= 0)
262 d->length = mediasize;
263 close(fd);
266 #elif defined(_HAVEDISKLABEL)
267 if(isdisk(st)){
268 int fd, n;
269 struct disklabel lab;
271 if((fd = open(name, O_RDONLY)) < 0)
272 goto nosize;
273 if(ioctl(fd, DIOCGDINFO, &lab) < 0)
274 goto nosize;
275 n = minor(st->st_rdev)&7;
276 if(n >= lab.d_npartitions)
277 goto nosize;
279 d->length = (vlong)(lab.d_partitions[n].p_size) * lab.d_secsize;
281 nosize:
282 if(fd >= 0)
283 close(fd);
285 #endif
288 return sz;