1 /* Copyight ©2007-2010 Kris Maglione <fbsdaemon@gmail.com>
2 * See LICENSE file for license details.
3 */
4 #define EXTERN
5 #define IXP_NO_P9_
6 #define IXP_P9_STRUCTS
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <time.h>
11 #include <unistd.h>
12 #include <ixp.h>
13 #include <util.h>
14 #include <fmt.h>
15
16 static IxpClient *client;
17
18 static void
usage(void)19 usage(void) {
20 fprint(1,
21 "usage: %s [-a <address>] {create | ls [-dlp] | read | remove | write} <file>\n"
22 " %s [-a <address>] xwrite <file> <data>\n"
23 " %s -v\n", argv0, argv0, argv0);
24 exit(1);
25 }
26
27 static int
errfmt(Fmt * f)28 errfmt(Fmt *f) {
29 return fmtstrcpy(f, ixp_errbuf());
30 }
31
32 /* Utility Functions */
33 static void
write_data(IxpCFid * fid,char * name)34 write_data(IxpCFid *fid, char *name) {
35 void *buf;
36 int len;
37
38 buf = emalloc(fid->iounit);;
39 for(;;) {
40 len = read(0, buf, fid->iounit);
41 if(len <= 0)
42 break;
43 if(ixp_write(fid, buf, len) != len)
44 fatal("cannot write file %q\n", name);
45 }
46 free(buf);
47 }
48
49 static int
comp_stat(const void * s1,const void * s2)50 comp_stat(const void *s1, const void *s2) {
51 Stat *st1, *st2;
52
53 st1 = (Stat*)s1;
54 st2 = (Stat*)s2;
55 return strcmp(st1->name, st2->name);
56 }
57
58 static void
setrwx(long m,char * s)59 setrwx(long m, char *s) {
60 static char *modes[] = {
61 "---", "--x", "-w-",
62 "-wx", "r--", "r-x",
63 "rw-", "rwx",
64 };
65 strncpy(s, modes[m], 3);
66 }
67
68 static char *
modestr(uint mode)69 modestr(uint mode) {
70 static char buf[16];
71
72 buf[0]='-';
73 if(mode & P9_DMDIR)
74 buf[0]='d';
75 buf[1]='-';
76 setrwx((mode >> 6) & 7, &buf[2]);
77 setrwx((mode >> 3) & 7, &buf[5]);
78 setrwx((mode >> 0) & 7, &buf[8]);
79 buf[11] = 0;
80 return buf;
81 }
82
83 static char*
timestr(time_t val)84 timestr(time_t val) {
85 static char buf[32];
86
87 strftime(buf, sizeof buf, "%Y-%m-%d %H:%M", localtime(&val));
88 return buf;
89 }
90
91 static void
print_stat(Stat * s,int lflag,char * file,int pflag)92 print_stat(Stat *s, int lflag, char *file, int pflag) {
93 char *slash;
94
95 slash = "";
96 if(pflag)
97 slash = "/";
98 else
99 file = "";
100
101 if(lflag)
102 print("%s %s %s %5llud %s %s%s%s\n",
103 modestr(s->mode), s->uid, s->gid, s->length,
104 timestr(s->mtime), file, slash, s->name);
105 else {
106 if((s->mode&P9_DMDIR) && strcmp(s->name, "/"))
107 print("%s%s%s/\n", file, slash, s->name);
108 else
109 print("%s%s%s\n", file, slash, s->name);
110 }
111 }
112
113 /* Service Functions */
114 static int
xwrite(int argc,char * argv[])115 xwrite(int argc, char *argv[]) {
116 IxpCFid *fid;
117 char *file;
118
119 ARGBEGIN{
120 default:
121 usage();
122 }ARGEND;
123
124 file = EARGF(usage());
125 fid = ixp_open(client, file, P9_OWRITE);
126 if(fid == nil)
127 fatal("Can't open file '%s': %r\n", file);
128
129 write_data(fid, file);
130 ixp_close(fid);
131 return 0;
132 }
133
134 static int
xawrite(int argc,char * argv[])135 xawrite(int argc, char *argv[]) {
136 IxpCFid *fid;
137 char *file, *buf;
138 int nbuf, i;
139
140 ARGBEGIN{
141 default:
142 usage();
143 }ARGEND;
144
145 file = EARGF(usage());
146 fid = ixp_open(client, file, P9_OWRITE);
147 if(fid == nil)
148 fatal("Can't open file '%s': %r\n", file);
149
150 nbuf = 1;
151 for(i=0; i < argc; i++)
152 nbuf += strlen(argv[i]) + (i > 0);
153 buf = emalloc(nbuf);
154 buf[0] = '\0';
155 while(argc) {
156 strcat(buf, ARGF());
157 if(argc)
158 strcat(buf, " ");
159 }
160
161 if(ixp_write(fid, buf, nbuf) == -1)
162 fatal("cannot write file '%s': %r\n", file);
163 ixp_close(fid);
164 free(buf);
165 return 0;
166 }
167
168 static int
xcreate(int argc,char * argv[])169 xcreate(int argc, char *argv[]) {
170 IxpCFid *fid;
171 char *file;
172
173 ARGBEGIN{
174 default:
175 usage();
176 }ARGEND;
177
178 file = EARGF(usage());
179 fid = ixp_create(client, file, 0777, P9_OWRITE);
180 if(fid == nil)
181 fatal("Can't create file '%s': %r\n", file);
182
183 if((fid->qid.type&P9_DMDIR) == 0)
184 write_data(fid, file);
185 ixp_close(fid);
186 return 0;
187 }
188
189 static int
xremove(int argc,char * argv[])190 xremove(int argc, char *argv[]) {
191 char *file;
192
193 ARGBEGIN{
194 default:
195 usage();
196 }ARGEND;
197
198 file = EARGF(usage());
199 do {
200 if(!ixp_remove(client, file))
201 fprint(2, "%s: Can't remove file '%s': %r\n", argv0, file);
202 }while((file = ARGF()));
203 return 0;
204 }
205
206 static int
xread(int argc,char * argv[])207 xread(int argc, char *argv[]) {
208 IxpCFid *fid;
209 char *file, *buf;
210 int count;
211
212 ARGBEGIN{
213 default:
214 usage();
215 }ARGEND;
216
217 if(argc == 0)
218 usage();
219 file = EARGF(usage());
220 do {
221 fid = ixp_open(client, file, P9_OREAD);
222 if(fid == nil)
223 fatal("Can't open file '%s': %r\n", file);
224
225 buf = emalloc(fid->iounit);
226 while((count = ixp_read(fid, buf, fid->iounit)) > 0)
227 write(1, buf, count);
228 ixp_close(fid);
229
230 if(count == -1)
231 fprint(2, "%s: cannot read file '%s': %r\n", argv0, file);
232 } while((file = ARGF()));
233
234 return 0;
235 }
236
237 static int
xls(int argc,char * argv[])238 xls(int argc, char *argv[]) {
239 IxpMsg m;
240 Stat *stat;
241 IxpCFid *fid;
242 char *file;
243 char *buf;
244 int lflag, dflag, pflag;
245 int count, nstat, mstat, i;
246
247 lflag = dflag = pflag = 0;
248
249 ARGBEGIN{
250 case 'l':
251 lflag++;
252 break;
253 case 'd':
254 dflag++;
255 break;
256 case 'p':
257 pflag++;
258 break;
259 default:
260 usage();
261 }ARGEND;
262
263 count = 0;
264 file = EARGF(usage());
265 do {
266 stat = ixp_stat(client, file);
267 if(stat == nil)
268 fatal("cannot stat file '%s': %r\n", file);
269
270 i = strlen(file);
271 if(file[i-1] == '/') {
272 file[i-1] = '\0';
273 if(!(stat->mode&P9_DMDIR))
274 fatal("%s: not a directory", file);
275 }
276 if(dflag || (stat->mode&P9_DMDIR) == 0) {
277 print_stat(stat, lflag, file, pflag);
278 ixp_freestat(stat);
279 continue;
280 }
281 ixp_freestat(stat);
282
283 fid = ixp_open(client, file, P9_OREAD);
284 if(fid == nil)
285 fatal("Can't open file '%s': %r\n", file);
286
287 nstat = 0;
288 mstat = 16;
289 stat = emalloc(mstat * sizeof *stat);
290 buf = emalloc(fid->iounit);
291 while((count = ixp_read(fid, buf, fid->iounit)) > 0) {
292 m = ixp_message(buf, count, MsgUnpack);
293 while(m.pos < m.end) {
294 if(nstat == mstat) {
295 mstat <<= 1;
296 stat = erealloc(stat, mstat * sizeof *stat);
297 }
298 ixp_pstat(&m, &stat[nstat++]);
299 }
300 }
301 ixp_close(fid);
302
303 qsort(stat, nstat, sizeof *stat, comp_stat);
304 for(i = 0; i < nstat; i++) {
305 print_stat(&stat[i], lflag, file, pflag);
306 ixp_freestat(&stat[i]);
307 }
308 free(stat);
309 } while((file = ARGF()));
310
311 if(count == -1)
312 fatal("cannot read directory '%s': %r\n", file);
313 return 0;
314 }
315
316 static int
xnamespace(int argc,char * argv[])317 xnamespace(int argc, char *argv[]) {
318 char *path;
319
320 ARGBEGIN{
321 default:
322 usage();
323 }ARGEND;
324
325 path = ixp_namespace();
326 if(path == nil)
327 fatal("can't find namespace: %r\n");
328 print("%s\n", path);
329 return 0;
330 }
331
332 static int
xsetsid(int argc,char * argv[])333 xsetsid(int argc, char *argv[]) {
334 char *av0;
335
336 av0 = nil;
337 ARGBEGIN{
338 case '0':
339 av0 = EARGF(usage());
340 break;
341 default:
342 usage();
343 }ARGEND;
344 if(av0 == nil)
345 av0 = argv[0];
346 if(av0 == nil)
347 return 1;
348
349 setsid();
350 execvp(av0, argv);
351 fatal("setsid: can't exec: %r");
352 return 1; /* NOTREACHED */
353 }
354
355 typedef struct exectab exectab;
356 struct exectab {
357 char *cmd;
358 int (*fn)(int, char**);
359 } fstab[] = {
360 {"cat", xread},
361 {"create", xcreate},
362 {"ls", xls},
363 {"read", xread},
364 {"remove", xremove},
365 {"rm", xremove},
366 {"write", xwrite},
367 {"xwrite", xawrite},
368 {0, }
369 }, utiltab[] = {
370 {"namespace", xnamespace},
371 {"ns", xnamespace},
372 {"setsid", xsetsid},
373 {0, }
374 };
375
376 int
main(int argc,char * argv[])377 main(int argc, char *argv[]) {
378 char *address;
379 exectab *tab;
380 int ret;
381
382 quotefmtinstall();
383 fmtinstall('r', errfmt);
384
385 address = getenv("WMII_ADDRESS");
386
387 ARGBEGIN{
388 case 'v':
389 print("%s-" VERSION ", " COPYRIGHT "\n", argv0);
390 exit(0);
391 case 'a':
392 address = EARGF(usage());
393 break;
394 default:
395 usage();
396 }ARGEND;
397
398 if(argc < 1)
399 usage();
400
401 for(tab=utiltab; tab->cmd; tab++)
402 if(!strcmp(*argv, tab->cmd))
403 return tab->fn(argc, argv);
404
405 if(address && *address)
406 client = ixp_mount(address);
407 else
408 client = ixp_nsmount("wmii");
409 if(client == nil)
410 fatal("can't mount: %r\n");
411
412 for(tab=fstab; tab->cmd; tab++)
413 if(strcmp(*argv, tab->cmd) == 0) break;
414 if(tab->cmd == 0)
415 usage();
416
417 ret = tab->fn(argc, argv);
418
419 ixp_unmount(client);
420 return ret;
421 }
422
423