ixpc.c (6554B)
1 /* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail> 2 * See LICENSE file for license details. 3 */ 4 #define IXP_NO_P9_ 5 #define IXP_P9_STRUCTS 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <time.h> 10 #include <unistd.h> 11 #include <ixp_local.h> 12 13 /* Temporary */ 14 #define fatal(...) ixp_eprint("ixpc: fatal: " __VA_ARGS__); \ 15 16 static IxpClient *client; 17 18 static void 19 usage(void) { 20 fprintf(stderr, 21 "usage: %1$s [-a <address>] {create | read | ls [-ld] | remove | write | append} <file>\n" 22 " %1$s [-a <address>] xwrite <file> <data>\n" 23 " %1$s -v\n", argv0); 24 exit(1); 25 } 26 27 /* Utility Functions */ 28 static void 29 write_data(IxpCFid *fid, char *name) { 30 void *buf; 31 uint len; 32 33 buf = emalloc(fid->iounit);; 34 do { 35 len = read(0, buf, fid->iounit); 36 if(len >= 0 && ixp_write(fid, buf, len) != len) 37 fatal("cannot write file '%s': %s\n", name, ixp_errbuf()); 38 } while(len > 0); 39 40 free(buf); 41 } 42 43 static int 44 comp_stat(const void *s1, const void *s2) { 45 Stat *st1, *st2; 46 47 st1 = (Stat*)s1; 48 st2 = (Stat*)s2; 49 return strcmp(st1->name, st2->name); 50 } 51 52 static void 53 setrwx(long m, char *s) { 54 static char *modes[] = { 55 "---", "--x", "-w-", 56 "-wx", "r--", "r-x", 57 "rw-", "rwx", 58 }; 59 strncpy(s, modes[m], 3); 60 } 61 62 static char * 63 str_of_mode(uint mode) { 64 static char buf[16]; 65 66 buf[0]='-'; 67 if(mode & P9_DMDIR) 68 buf[0]='d'; 69 buf[1]='-'; 70 setrwx((mode >> 6) & 7, &buf[2]); 71 setrwx((mode >> 3) & 7, &buf[5]); 72 setrwx((mode >> 0) & 7, &buf[8]); 73 buf[11] = 0; 74 return buf; 75 } 76 77 static char * 78 str_of_time(uint val) { 79 static char buf[32]; 80 81 ctime_r((time_t*)&val, buf); 82 buf[strlen(buf) - 1] = '\0'; 83 return buf; 84 } 85 86 static void 87 print_stat(Stat *s, int details) { 88 if(details) 89 fprintf(stdout, "%s %s %s %5llu %s %s\n", str_of_mode(s->mode), 90 s->uid, s->gid, s->length, str_of_time(s->mtime), s->name); 91 else { 92 if((s->mode&P9_DMDIR) && strcmp(s->name, "/")) 93 fprintf(stdout, "%s/\n", s->name); 94 else 95 fprintf(stdout, "%s\n", s->name); 96 } 97 } 98 99 /* Service Functions */ 100 static int 101 xappend(int argc, char *argv[]) { 102 IxpCFid *fid; 103 IxpStat *stat; 104 char *file; 105 106 ARGBEGIN{ 107 default: 108 usage(); 109 }ARGEND; 110 111 file = EARGF(usage()); 112 fid = ixp_open(client, file, P9_OWRITE); 113 if(fid == nil) 114 fatal("Can't open file '%s': %s\n", file, ixp_errbuf()); 115 116 stat = ixp_stat(client, file); 117 fid->offset = stat->length; 118 ixp_freestat(stat); 119 free(stat); 120 write_data(fid, file); 121 return 0; 122 } 123 124 static int 125 xwrite(int argc, char *argv[]) { 126 IxpCFid *fid; 127 char *file; 128 129 ARGBEGIN{ 130 default: 131 usage(); 132 }ARGEND; 133 134 file = EARGF(usage()); 135 fid = ixp_open(client, file, P9_OWRITE); 136 if(fid == nil) 137 fatal("Can't open file '%s': %s\n", file, ixp_errbuf()); 138 139 write_data(fid, file); 140 return 0; 141 } 142 143 static int 144 xawrite(int argc, char *argv[]) { 145 IxpCFid *fid; 146 char *file, *buf, *arg; 147 int nbuf, mbuf, len; 148 149 ARGBEGIN{ 150 default: 151 usage(); 152 }ARGEND; 153 154 file = EARGF(usage()); 155 fid = ixp_open(client, file, P9_OWRITE); 156 if(fid == nil) 157 fatal("Can't open file '%s': %s\n", file, ixp_errbuf()); 158 159 nbuf = 0; 160 mbuf = 128; 161 buf = emalloc(mbuf); 162 while(argc) { 163 arg = ARGF(); 164 len = strlen(arg); 165 if(nbuf + len > mbuf) { 166 mbuf <<= 1; 167 buf = ixp_erealloc(buf, mbuf); 168 } 169 memcpy(buf+nbuf, arg, len); 170 nbuf += len; 171 if(argc) 172 buf[nbuf++] = ' '; 173 } 174 175 if(ixp_write(fid, buf, nbuf) == -1) 176 fatal("cannot write file '%s': %s\n", file, ixp_errbuf()); 177 return 0; 178 } 179 180 static int 181 xcreate(int argc, char *argv[]) { 182 IxpCFid *fid; 183 char *file; 184 185 ARGBEGIN{ 186 default: 187 usage(); 188 }ARGEND; 189 190 file = EARGF(usage()); 191 fid = ixp_create(client, file, 0777, P9_OWRITE); 192 if(fid == nil) 193 fatal("Can't create file '%s': %s\n", file, ixp_errbuf()); 194 195 if((fid->qid.type&P9_DMDIR) == 0) 196 write_data(fid, file); 197 198 return 0; 199 } 200 201 static int 202 xremove(int argc, char *argv[]) { 203 char *file; 204 205 ARGBEGIN{ 206 default: 207 usage(); 208 }ARGEND; 209 210 file = EARGF(usage()); 211 if(ixp_remove(client, file) == 0) 212 fatal("Can't remove file '%s': %s\n", file, ixp_errbuf()); 213 return 0; 214 } 215 216 static int 217 xread(int argc, char *argv[]) { 218 IxpCFid *fid; 219 char *file, *buf; 220 int count; 221 222 ARGBEGIN{ 223 default: 224 usage(); 225 }ARGEND; 226 227 file = EARGF(usage()); 228 fid = ixp_open(client, file, P9_OREAD); 229 if(fid == nil) 230 fatal("Can't open file '%s': %s\n", file, ixp_errbuf()); 231 232 buf = emalloc(fid->iounit); 233 while((count = ixp_read(fid, buf, fid->iounit)) > 0) 234 write(1, buf, count); 235 236 if(count == -1) 237 fatal("cannot read file/directory '%s': %s\n", file, ixp_errbuf()); 238 239 return 0; 240 } 241 242 static int 243 xls(int argc, char *argv[]) { 244 IxpMsg m; 245 Stat *stat; 246 IxpCFid *fid; 247 char *file, *buf; 248 int lflag, dflag, count, nstat, mstat, i; 249 250 lflag = dflag = 0; 251 252 ARGBEGIN{ 253 case 'l': 254 lflag++; 255 break; 256 case 'd': 257 dflag++; 258 break; 259 default: 260 usage(); 261 }ARGEND; 262 263 file = EARGF(usage()); 264 265 stat = ixp_stat(client, file); 266 if(stat == nil) 267 fatal("cannot stat file '%s': %s\n", file, ixp_errbuf()); 268 269 if(dflag || (stat->mode&P9_DMDIR) == 0) { 270 print_stat(stat, lflag); 271 ixp_freestat(stat); 272 return 0; 273 } 274 ixp_freestat(stat); 275 276 fid = ixp_open(client, file, P9_OREAD); 277 if(fid == nil) 278 fatal("Can't open file '%s': %s\n", file, ixp_errbuf()); 279 280 nstat = 0; 281 mstat = 16; 282 stat = emalloc(sizeof(*stat) * mstat); 283 buf = emalloc(fid->iounit); 284 while((count = ixp_read(fid, buf, fid->iounit)) > 0) { 285 m = ixp_message(buf, count, MsgUnpack); 286 while(m.pos < m.end) { 287 if(nstat == mstat) { 288 mstat <<= 1; 289 stat = ixp_erealloc(stat, sizeof(*stat) * mstat); 290 } 291 ixp_pstat(&m, &stat[nstat++]); 292 } 293 } 294 295 qsort(stat, nstat, sizeof(*stat), comp_stat); 296 for(i = 0; i < nstat; i++) { 297 print_stat(&stat[i], lflag); 298 ixp_freestat(&stat[i]); 299 } 300 free(stat); 301 302 if(count == -1) 303 fatal("cannot read directory '%s': %s\n", file, ixp_errbuf()); 304 return 0; 305 } 306 307 typedef struct exectab exectab; 308 struct exectab { 309 char *cmd; 310 int (*fn)(int, char**); 311 } etab[] = { 312 {"append", xappend}, 313 {"write", xwrite}, 314 {"xwrite", xawrite}, 315 {"read", xread}, 316 {"create", xcreate}, 317 {"remove", xremove}, 318 {"ls", xls}, 319 {0, 0} 320 }; 321 322 int 323 main(int argc, char *argv[]) { 324 char *cmd, *address; 325 exectab *tab; 326 int ret; 327 328 address = getenv("IXP_ADDRESS"); 329 330 ARGBEGIN{ 331 case 'v': 332 printf("%s-" VERSION ", ©2007 Kris Maglione\n", argv0); 333 exit(0); 334 case 'a': 335 address = EARGF(usage()); 336 break; 337 default: 338 usage(); 339 }ARGEND; 340 341 cmd = EARGF(usage()); 342 343 if(!address) 344 fatal("$IXP_ADDRESS not set\n"); 345 346 client = ixp_mount(address); 347 if(client == nil) 348 fatal("%s\n", ixp_errbuf()); 349 350 for(tab = etab; tab->cmd; tab++) 351 if(strcmp(cmd, tab->cmd) == 0) break; 352 if(tab->cmd == 0) 353 usage(); 354 355 ret = tab->fn(argc, argv); 356 357 ixp_unmount(client); 358 return ret; 359 }