Overview
Comment: | Added comments |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | tcl-ops |
Files: | files | file ages | folders |
SHA1: | 83dcb7cd523520a4bf51a48d3e3484e81f96577a |
User & Date: | rkeene on 2014-11-07 06:14:42 |
Other Links: | manifest | tags |
Context
2014-11-07
| ||
06:47 | Added start of supplying default options check-in: a7e9dac6ce user: rkeene tags: tcl-ops | |
06:14 | Added comments check-in: 83dcb7cd52 user: rkeene tags: tcl-ops | |
05:42 | Added more functionality to "appfs-cache" control system check-in: 82982300d8 user: rkeene tags: tcl-ops | |
Changes
Modified appfsd.c from [e20407f29f] to [616c3164a5].
9 9 #include <errno.h> 10 10 #include <fcntl.h> 11 11 #include <stdio.h> 12 12 #include <fuse.h> 13 13 #include <pwd.h> 14 14 #include <tcl.h> 15 15 16 -/* From sha1.c */ 17 -int Sha1_Init(Tcl_Interp *interp); 18 - 16 +/* 17 + * Default cache directory 18 + */ 19 19 #ifndef APPFS_CACHEDIR 20 20 #define APPFS_CACHEDIR "/var/cache/appfs" 21 21 #endif 22 22 23 +/* Debugging macros */ 23 24 #ifdef DEBUG 24 25 #define APPFS_DEBUG(x...) { fprintf(stderr, "[debug] %s:%i:%s: ", __FILE__, __LINE__, __func__); fprintf(stderr, x); fprintf(stderr, "\n"); } 25 26 #else 26 27 #define APPFS_DEBUG(x...) /**/ 27 28 #endif 28 29 30 +/* 31 + * SHA1 Tcl Package initializer, from sha1.o 32 + */ 33 +int Sha1_Init(Tcl_Interp *interp); 34 + 35 +/* 36 + * Thread Specific Data (TSD) for Tcl Interpreter for the current thread 37 + */ 29 38 static pthread_key_t interpKey; 30 39 40 +/* 41 + * Data for a given thread (most likely these will become just globable variables soon.) 42 + */ 31 43 struct appfs_thread_data { 32 44 const char *cachedir; 33 45 time_t boottime; 34 46 struct { 35 47 int writable; 36 48 } options; 37 49 }; 38 50 51 +/* The global thread data (likely to go away) */ 39 52 struct appfs_thread_data globalThread; 40 53 54 +/* 55 + * AppFS Path Type: Describes the type of path a given file is 56 + */ 41 57 typedef enum { 42 58 APPFS_PATHTYPE_INVALID, 43 59 APPFS_PATHTYPE_FILE, 44 60 APPFS_PATHTYPE_DIRECTORY, 45 61 APPFS_PATHTYPE_SYMLINK 46 62 } appfs_pathtype_t; 47 63 64 +/* 65 + * AppFS Children Files linked-list 66 + */ 48 67 struct appfs_children { 49 68 struct appfs_children *_next; 50 - int counter; 51 - 52 69 char name[256]; 53 70 }; 54 71 72 +/* 73 + * AppFS Path Information: 74 + * Completely describes a specific path, how it should be returned to 75 + * to the kernel 76 + */ 55 77 struct appfs_pathinfo { 56 78 appfs_pathtype_t type; 57 79 time_t time; 58 80 char hostname[256]; 59 81 int packaged; 60 82 unsigned long long inode; 61 83 union { ................................................................................ 69 91 struct { 70 92 off_t size; 71 93 char source[256]; 72 94 } symlink; 73 95 } typeinfo; 74 96 }; 75 97 98 +/* 99 + * Create a new Tcl interpreter and completely initialize it 100 + */ 76 101 static Tcl_Interp *appfs_create_TclInterp(void) { 77 102 Tcl_Interp *interp; 78 103 const char *cachedir = globalThread.cachedir; 79 104 int tcl_ret; 80 105 81 106 APPFS_DEBUG("Creating new Tcl interpreter for TID = 0x%llx", (unsigned long long) pthread_self()); 82 107 ................................................................................ 113 138 fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp)); 114 139 115 140 Tcl_DeleteInterp(interp); 116 141 117 142 return(NULL); 118 143 } 119 144 145 + /* 146 + * Load the "appfsd.tcl" script, which is "compiled" into a C header 147 + * so that it does not need to exist on the filesystem and can be 148 + * directly evaluated. 149 + */ 120 150 tcl_ret = Tcl_Eval(interp, "" 121 151 #include "appfsd.tcl.h" 122 152 ""); 123 153 if (tcl_ret != TCL_OK) { 124 154 fprintf(stderr, "Unable to initialize Tcl AppFS script. Aborting.\n"); 125 155 fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp)); 126 156 127 157 Tcl_DeleteInterp(interp); 128 158 129 159 return(NULL); 130 160 } 131 161 162 + /* 163 + * Set global variables from C to Tcl 164 + */ 132 165 if (Tcl_SetVar(interp, "::appfs::cachedir", cachedir, TCL_GLOBAL_ONLY) == NULL) { 133 166 fprintf(stderr, "Unable to set cache directory. This should never fail.\n"); 134 167 135 168 Tcl_DeleteInterp(interp); 136 169 137 170 return(NULL); 138 171 } 139 172 173 + /* 174 + * Initialize the "appfsd.tcl" environment, which must be done after 175 + * global variables are set. 176 + */ 140 177 tcl_ret = Tcl_Eval(interp, "::appfs::init"); 141 178 if (tcl_ret != TCL_OK) { 142 179 fprintf(stderr, "Unable to initialize Tcl AppFS script (::appfs::init). Aborting.\n"); 143 180 fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp)); 144 181 145 182 Tcl_DeleteInterp(interp); 146 183 147 184 return(NULL); 148 185 } 149 186 187 + /* 188 + * Hide some Tcl commands that we do not care to use and which may 189 + * slow down run-time operations. 190 + */ 150 191 Tcl_HideCommand(interp, "auto_load_index", "auto_load_index"); 151 192 Tcl_HideCommand(interp, "unknown", "unknown"); 152 193 194 + /* 195 + * Return the completely initialized interpreter 196 + */ 153 197 return(interp); 154 198 } 155 199 200 +/* 201 + * Return the thread-specific Tcl interpreter, creating it if needed 202 + */ 156 203 static Tcl_Interp *appfs_TclInterp(void) { 157 204 Tcl_Interp *interp; 205 + int pthread_ret; 158 206 159 207 interp = pthread_getspecific(interpKey); 160 208 if (interp == NULL) { 161 209 interp = appfs_create_TclInterp(); 162 210 163 211 if (interp == NULL) { 164 212 return(NULL); 165 213 } 166 214 167 - pthread_setspecific(interpKey, interp); 215 + pthread_ret = pthread_setspecific(interpKey, interp); 216 + if (pthread_ret != 0) { 217 + Tcl_DeleteInterp(interp); 218 + 219 + return(NULL); 220 + } 168 221 } 169 222 170 223 return(interp); 171 224 } 172 225 226 +/* 227 + * Evaluate a Tcl script constructed by concatenating a bunch of C strings 228 + * together. 229 + */ 173 230 static int appfs_Tcl_Eval(Tcl_Interp *interp, int objc, const char *cmd, ...) { 174 231 Tcl_Obj **objv; 175 232 const char *arg; 176 233 va_list argp; 177 234 int retval; 178 235 int i; 179 236 ................................................................................ 204 261 if (retval != TCL_OK) { 205 262 APPFS_DEBUG("Tcl command failed, ::errorInfo contains: %s\n", Tcl_GetVar(interp, "::errorInfo", 0)); 206 263 } 207 264 208 265 return(retval); 209 266 } 210 267 268 +/* 269 + * AppFS: Request that a host's package index be updated locally 270 + */ 211 271 static void appfs_update_index(const char *hostname) { 212 272 Tcl_Interp *interp; 213 273 int tcl_ret; 214 274 215 275 APPFS_DEBUG("Enter: hostname = %s", hostname); 216 276 217 277 interp = appfs_TclInterp(); ................................................................................ 225 285 226 286 return; 227 287 } 228 288 229 289 return; 230 290 } 231 291 292 +/* 293 + * AppFS: Get a SHA1 from a host 294 + * Returns a local file name, or NULL if it cannot be fetched 295 + */ 232 296 static const char *appfs_getfile(const char *hostname, const char *sha1) { 233 297 Tcl_Interp *interp; 234 298 char *retval; 235 299 int tcl_ret; 236 300 237 301 interp = appfs_TclInterp(); 238 302 if (interp == NULL) { ................................................................................ 247 311 } 248 312 249 313 retval = strdup(Tcl_GetStringResult(interp)); 250 314 251 315 return(retval); 252 316 } 253 317 318 +/* 319 + * AppFS: Update the manifest for a specific package (by the package SHA1) on 320 + * a given host 321 + */ 254 322 static void appfs_update_manifest(const char *hostname, const char *sha1) { 255 323 Tcl_Interp *interp; 256 324 int tcl_ret; 257 325 258 326 interp = appfs_TclInterp(); 259 327 if (interp == NULL) { 260 328 return; ................................................................................ 266 334 267 335 return; 268 336 } 269 337 270 338 return; 271 339 } 272 340 341 +/* 342 + * Determine the UID for the user making the current FUSE filesystem request. 343 + * This will be used to lookup the user's home directory so we can search for 344 + * locally modified files. 345 + */ 273 346 static uid_t appfs_get_fsuid(void) { 274 347 struct fuse_context *ctx; 275 348 276 349 ctx = fuse_get_context(); 277 350 if (ctx == NULL) { 278 351 /* Unable to lookup user for some reason */ 279 352 /* Return an unprivileged user ID */ 280 353 return(1); 281 354 } 282 355 283 356 return(ctx->uid); 284 357 } 285 358 359 +/* 360 + * Look up the home directory for a given UID 361 + * Returns a C string containing the user's home directory or NULL if 362 + * the user's home directory does not exist or is not correctly 363 + * configured 364 + */ 286 365 static char *appfs_get_homedir(uid_t fsuid) { 287 366 struct passwd entry, *result; 288 367 struct stat stbuf; 289 368 char buf[1024], *retval; 290 369 int gpu_ret, stat_ret; 291 370 292 371 gpu_ret = getpwuid_r(fsuid, &entry, buf, sizeof(buf), &result); ................................................................................ 326 405 } 327 406 328 407 retval = strdup(result->pw_dir); 329 408 330 409 return(retval); 331 410 } 332 411 412 +/* 413 + * Tcl interface to get the home directory for the user making the "current" 414 + * FUSE I/O request 415 + */ 333 416 static int tcl_appfs_get_homedir(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { 334 417 char *homedir; 335 418 336 419 if (objc != 1) { 337 420 Tcl_WrongNumArgs(interp, 1, objv, NULL); 338 421 return(TCL_ERROR); 339 422 } ................................................................................ 347 430 Tcl_SetObjResult(interp, Tcl_NewStringObj(homedir, -1)); 348 431 349 432 free(homedir); 350 433 351 434 return(TCL_OK); 352 435 } 353 436 354 -/* Generate an inode for a given path */ 437 +/* 438 + * Generate an inode for a given path. The inode should be computed in such 439 + * a way that it is unlikely to be duplicated and remains the same for a given 440 + * file 441 + */ 355 442 static long long appfs_get_path_inode(const char *path) { 356 443 long long retval; 357 444 const char *p; 358 445 359 446 retval = 10; 360 447 361 448 for (p = path; *p; p++) { ................................................................................ 543 630 } 544 631 545 632 read_ret = read(fi->fh, buf, size); 546 633 547 634 return(read_ret); 548 635 } 549 636 637 +/* 638 + * SQLite3 mode: Execute raw SQL and return success or failure 639 + */ 550 640 static int appfs_sqlite3(const char *sql) { 551 641 Tcl_Interp *interp; 552 642 const char *sql_ret; 553 643 int tcl_ret; 554 644 555 645 interp = appfs_create_TclInterp(); 556 646 if (interp == NULL) { ................................................................................ 571 661 if (sql_ret && sql_ret[0] != '\0') { 572 662 printf("%s\n", sql_ret); 573 663 } 574 664 575 665 return(0); 576 666 } 577 667 668 +/* 669 + * Tcl mode: Execute raw Tcl and return success or failure 670 + */ 578 671 static int appfs_tcl(const char *tcl) { 579 672 Tcl_Interp *interp; 580 673 const char *tcl_result; 581 674 int tcl_ret; 582 675 583 676 interp = appfs_create_TclInterp(); 584 677 if (interp == NULL) { ................................................................................ 599 692 if (tcl_result && tcl_result[0] != '\0') { 600 693 printf("%s\n", tcl_result); 601 694 } 602 695 603 696 return(0); 604 697 } 605 698 699 +/* 700 + * AppFSd Package for Tcl: 701 + * Bridge for I/O operations to request information about the current 702 + * transaction 703 + */ 606 704 static int Appfsd_Init(Tcl_Interp *interp) { 607 705 #ifdef USE_TCL_STUBS 608 706 if (Tcl_InitStubs(interp, TCL_VERSION, 0) == 0L) { 609 707 return(TCL_ERROR); 610 708 } 611 709 #endif 612 710 ................................................................................ 613 711 Tcl_CreateObjCommand(interp, "appfsd::get_homedir", tcl_appfs_get_homedir, NULL, NULL); 614 712 615 713 Tcl_PkgProvide(interp, "appfsd", "1.0"); 616 714 617 715 return(TCL_OK); 618 716 } 619 717 718 +/* 719 + * FUSE operations structure 720 + */ 620 721 static struct fuse_operations appfs_oper = { 621 722 .getattr = appfs_fuse_getattr, 622 723 .readdir = appfs_fuse_readdir, 623 724 .readlink = appfs_fuse_readlink, 624 725 .open = appfs_fuse_open, 625 726 .release = appfs_fuse_close, 626 727 .read = appfs_fuse_read 627 728 }; 628 729 730 +/* 731 + * Entry point into this program. 732 + */ 629 733 int main(int argc, char **argv) { 630 734 const char *cachedir = APPFS_CACHEDIR; 631 735 int pthread_ret; 632 736 737 + /* 738 + * Set global variables, these should be configuration options. 739 + */ 633 740 globalThread.cachedir = cachedir; 634 - globalThread.boottime = time(NULL); 635 741 globalThread.options.writable = 1; 636 742 743 + /* 744 + * Set global variable for "boot time" to set a time on directories 745 + * that we fake. 746 + */ 747 + globalThread.boottime = time(NULL); 748 + 749 + /* 750 + * Register "sha1" and "appfsd" package with libtcl so that any new 751 + * interpreters created (which are done dynamically by FUSE) can have 752 + * the appropriate configuration done automatically. 753 + */ 637 754 Tcl_StaticPackage(NULL, "sha1", Sha1_Init, NULL); 638 755 Tcl_StaticPackage(NULL, "appfsd", Appfsd_Init, NULL); 639 756 757 + /* 758 + * Create a thread-specific-data (TSD) key for each thread to refer 759 + * to its own Tcl interpreter. Tcl interpreters must be unique per 760 + * thread and new threads are dynamically created by FUSE. 761 + */ 640 762 pthread_ret = pthread_key_create(&interpKey, NULL); 641 763 if (pthread_ret != 0) { 642 764 fprintf(stderr, "Unable to create TSD key for Tcl. Aborting.\n"); 643 765 644 766 return(1); 645 767 } 646 768 769 + /* 770 + * SQLite3 mode, for running raw SQL against the cache database 771 + */ 647 772 if (argc == 3 && strcmp(argv[1], "-sqlite3") == 0) { 648 773 return(appfs_sqlite3(argv[2])); 649 774 } 650 775 776 + /* 777 + * Tcl mode, for running raw Tcl in the same environment AppFSd would 778 + * run code. 779 + */ 651 780 if (argc == 3 && strcmp(argv[1], "-tcl") == 0) { 652 781 return(appfs_tcl(argv[2])); 653 782 } 654 783 784 + /* 785 + * Enter the FUSE main loop -- this will process any arguments 786 + * and start servicing requests. 787 + */ 655 788 return(fuse_main(argc, argv, &appfs_oper, NULL)); 656 789 } 657 790