/* * Instantiate a private user environment for the calling thread. * * Submitted by: fernando.ruiz@ctv.es (correo@fernando-ruiz.com) * * COPYRIGHT (c) 1989-2010. * On-Line Applications Research Corporation (OAR). * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.com/license/LICENSE. * * $Id$ */ #if HAVE_CONFIG_H #include "config.h" #endif #include /* free */ #include #include #include /* cleanup a user environment * NOTE: this must be called with * thread dispatching disabled! */ static void free_user_env(void *venv) { rtems_user_env_t *env = (rtems_user_env_t*) venv ; if (env != &rtems_global_user_env #ifdef HAVE_USERENV_REFCNT && --env->refcnt <= 0 #endif ) { rtems_filesystem_freenode( &env->current_directory); rtems_filesystem_freenode( &env->root_directory); free(env); } } rtems_status_code rtems_libio_set_private_env(void) { rtems_status_code sc = RTEMS_SUCCESSFUL; rtems_id task_id = rtems_task_self(); rtems_filesystem_location_info_t root_loc; rtems_filesystem_location_info_t current_loc; rtems_user_env_t *new_env = NULL; int rv = 0; rv = rtems_filesystem_evaluate_path("/", 1, 0, &root_loc, 0); if (rv != 0) goto error_0; rv = rtems_filesystem_evaluate_path("/", 1, 0, ¤t_loc, 0); if (rv != 0) goto error_1; /* * Malloc is necessary whenever the current task does not * have its own environment in place. This could be: * a) it never had one * OR * b) it shared another task's environment */ /* * Bharath: I'm not sure if the check can be reduced to * if( rtems_current_user_env->task_id != task_id ) { */ if ( rtems_current_user_env == &rtems_global_user_env || rtems_current_user_env->task_id != task_id ) { new_env = malloc(sizeof(rtems_user_env_t)); if (new_env == NULL) goto error_2; #ifdef HAVE_USERENV_REFCNT new_env->refcnt = 1; #endif sc = rtems_task_variable_add( RTEMS_SELF, (void*)&rtems_current_user_env, (void(*)(void *))free_user_env ); if (sc != RTEMS_SUCCESSFUL) goto error_3; rtems_current_user_env = new_env; } /* Inherit the global values */ *rtems_current_user_env = rtems_global_user_env; rtems_current_user_env->task_id = task_id; /* * Clone the pathlocs. In contrast to most other code we must _not_ free the * original locs because what we are trying to do here is forking off clones. * The reason is a pathloc can be allocated by the file system and needs to * be freed when deleting the environment. */ rtems_filesystem_root = root_loc; rtems_filesystem_current = current_loc; return RTEMS_SUCCESSFUL; error_3: free(new_env); error_2: rtems_filesystem_freenode(¤t_loc); error_1: rtems_filesystem_freenode(&root_loc); error_0: return RTEMS_NO_MEMORY; } /* * Share the same private environment between two tasks: * Task_id (remote) and RTEMS_SELF(current). */ /* NOTE: * * THIS CODE HAS NO PROTECTION IMPLEMENTED * * Tasks who wish to share their environments must * * a) assert that no participants are concurrently * executing * libio_share_private_env() and/or libio_set_private_env() * * b) mutex access to rtems_filesystem_current, rtems_filesytem_root * while changing any of those (chdir(), chroot()). */ rtems_status_code rtems_libio_share_private_env(rtems_id task_id) { rtems_status_code sc; rtems_user_env_t * shared_user_env; rtems_id current_task_id; /* * get current task id */ current_task_id = rtems_task_self(); /* * If this was an attempt to share the task with self, * if somebody wanted to do it... Lets tell them, its shared */ if( task_id == current_task_id ) return RTEMS_SUCCESSFUL; /* * Try to get the requested user environment */ sc = rtems_task_variable_get( task_id, (void*)&rtems_current_user_env, (void*)&shared_user_env ); /* * If it was not successful, return the error code */ if (sc != RTEMS_SUCCESSFUL) return sc; /* * If we are here, we have the required environment to be * shared with the current task */ /* * If we have a current environment in place, we need to * free it, since we will be sharing the variable with the * shared_user_env */ if (rtems_current_user_env->task_id==current_task_id) { rtems_user_env_t *tmp = rtems_current_user_env; free_user_env( tmp ); } /* the current_user_env is the same pointer that remote env */ rtems_current_user_env = shared_user_env; /* increase the reference count */ #ifdef HAVE_USERENV_REFCNT rtems_current_user_env->refcnt++; #endif return RTEMS_SUCCESSFUL; }