Diff

Differences From Artifact [e20407f29f]:

To Artifact [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