/* Read the environment variable of current process specified by @key. */ int cfs_get_environ(const char *key, char *value, int *val_len) { struct mm_struct *mm; char *buffer; int buf_len = PAGE_CACHE_SIZE; int key_len = strlen(key); unsigned long addr; int rc; bool skip = false; ENTRY; buffer = kmalloc(buf_len, GFP_USER); if (!buffer) RETURN(-ENOMEM); mm = get_task_mm(current); if (!mm) { kfree(buffer); RETURN(-EINVAL); } addr = mm->env_start; while (addr < mm->env_end) { int this_len, retval, scan_len; char *env_start, *env_end; memset(buffer, 0, buf_len); this_len = min_t(int, mm->env_end - addr, buf_len); retval = cfs_access_process_vm(current, mm, addr, buffer, this_len, 0); if (retval < 0) GOTO(out, rc = retval); else if (retval != this_len) break; addr += retval; /* Parse the buffer to find out the specified key/value pair. * The "key=value" entries are separated by '\0'. */ env_start = buffer; scan_len = this_len; while (scan_len) { char *entry; int entry_len; env_end = memscan(env_start, '\0', scan_len); LASSERT(env_end >= env_start && env_end <= env_start + scan_len); /* The last entry of this buffer cross the buffer * boundary, reread it in next cycle. */ if (unlikely(env_end - env_start == scan_len)) { /* Just skip the entry larger than page size, * it can't be jobID env variable. */ if (unlikely(scan_len == this_len)) skip = true; else addr -= scan_len; break; } else if (unlikely(skip)) { skip = false; goto skip; } entry = env_start; entry_len = env_end - env_start; /* Key length + length of '=' */ if (entry_len > key_len + 1 && !memcmp(entry, key, key_len)) { entry += key_len + 1; entry_len -= key_len + 1; /* The 'value' buffer passed in is too small.*/ if (entry_len >= *val_len) GOTO(out, rc = -EOVERFLOW); memcpy(value, entry, entry_len); *val_len = entry_len; GOTO(out, rc = 0); } skip: scan_len -= (env_end - env_start + 1); env_start = env_end + 1; } } GOTO(out, rc = -ENOENT); out: mmput(mm); kfree((void *)buffer); return rc; }
/* Read the environment variable of current process specified by @key. */ int cfs_get_environ(const char *key, char *value, int *val_len) { struct mm_struct *mm; char *buffer; int buf_len = PAGE_CACHE_SIZE; int key_len = strlen(key); unsigned long addr; int rc; ENTRY; buffer = kmalloc(buf_len, GFP_USER); if (!buffer) RETURN(-ENOMEM); mm = get_task_mm(current); if (!mm) { kfree(buffer); RETURN(-EINVAL); } /* Avoid deadlocks on mmap_sem if called from sys_mmap_pgoff(), * which is already holding mmap_sem for writes. If some other * thread gets the write lock in the meantime, this thread will * block, but at least it won't deadlock on itself. LU-1735 */ if (down_read_trylock(&mm->mmap_sem) == 0) { kfree(buffer); return -EDEADLK; } up_read(&mm->mmap_sem); addr = mm->env_start; while (addr < mm->env_end) { int this_len, retval, scan_len; char *env_start, *env_end; memset(buffer, 0, buf_len); this_len = min_t(int, mm->env_end - addr, buf_len); retval = cfs_access_process_vm(current, addr, buffer, this_len, 0); if (retval != this_len) break; addr += retval; /* Parse the buffer to find out the specified key/value pair. * The "key=value" entries are separated by '\0'. */ env_start = buffer; scan_len = this_len; while (scan_len) { char *entry; int entry_len; env_end = memscan(env_start, '\0', scan_len); LASSERT(env_end >= env_start && env_end <= env_start + scan_len); /* The last entry of this buffer cross the buffer * boundary, reread it in next cycle. */ if (unlikely(env_end - env_start == scan_len)) { /* This entry is too large to fit in buffer */ if (unlikely(scan_len == this_len)) { CERROR("Too long env variable.\n"); GOTO(out, rc = -EINVAL); } addr -= scan_len; break; } entry = env_start; entry_len = env_end - env_start; /* Key length + length of '=' */ if (entry_len > key_len + 1 && !memcmp(entry, key, key_len)) { entry += key_len + 1; entry_len -= key_len + 1; /* The 'value' buffer passed in is too small.*/ if (entry_len >= *val_len) GOTO(out, rc = -EOVERFLOW); memcpy(value, entry, entry_len); *val_len = entry_len; GOTO(out, rc = 0); } scan_len -= (env_end - env_start + 1); env_start = env_end + 1; } } GOTO(out, rc = -ENOENT); out: mmput(mm); kfree((void *)buffer); return rc; }