taskfs fix up, minor refactoring eme/taskfs
authorLunaixsky <lunaixsky@qq.com>
Fri, 31 Jan 2025 05:36:46 +0000 (05:36 +0000)
committerLunaixsky <lunaixsky@qq.com>
Fri, 31 Jan 2025 05:36:46 +0000 (05:36 +0000)
* fix task listing
* make twimap a separated instance for each inode
* refactor the interface for registering attribute mapping
* replace children atrribute to mm region enumeration
* fix strncpy behaviour, remove the auto null-terminator appendence as
  it may cause out of bound access.
* some minor refactoring

lunaix-os/includes/lunaix/fs.h
lunaix-os/includes/lunaix/fs/api.h
lunaix-os/includes/lunaix/fs/taskfs.h
lunaix-os/includes/lunaix/fs/twimap.h
lunaix-os/kernel/fs/twimap.c
lunaix-os/kernel/fs/vfs.c
lunaix-os/kernel/process/sched.c
lunaix-os/kernel/process/task_attr.c
lunaix-os/kernel/process/taskfs.c
lunaix-os/libs/klibc/string/strcpy.c

index 6feb2aa0447769b7f5d68fda278936774036d8a8..6a5a92d4e03752c84b7ed766f0d59ae381c44a50 100644 (file)
@@ -358,6 +358,12 @@ fsm_itend(struct fs_iter* iterator)
     iterator->fs = NULL;
 }
 
+static inline bool
+fsm_check_pseudo_fs(struct filesystem* fs)
+{
+    return !!(fs->types & FSTYPE_PSEUDO);
+}
+
 void
 vfs_init();
 
index d00277415115f4044fc28f96f07894eabdb3f8c5..9e8ce2f4123ee4dfa1ecbf59f1d3c35f657febc3 100644 (file)
@@ -298,4 +298,16 @@ fsapi_fs_finalise(struct filesystem* fs)
     fsm_register(fs);
 }
 
+static inline bool
+fsapi_check_readdir_pos_pseduo(struct v_file* file)
+{
+    return file->f_pos < 2;
+}
+
+static inline bool
+fsapi_readdir_pos_entries_at(struct v_file* file, unsigned int pos)
+{
+    return file->f_pos == pos + 2;
+}
+
 #endif /* __LUNAIX_FSAPI_H */
index b96e0e5c5f33f15c685cdeab118702f66c92cdd2..f0ef85f4853eb4f3c86edd74a6c1ba1c537c9d7f 100644 (file)
@@ -3,21 +3,39 @@
 
 #include <lunaix/fs/api.h>
 #include <lunaix/fs/twimap.h>
+#include <lunaix/ds/list.h>
 
 struct task_attribute
 {
-    struct llist_header siblings;
+    struct list_node siblings;
     struct hlist_node attrs;
     struct hstr key;
-    struct twimap* map_file;
-    char key_val[32];
+    struct twimap_ops ops;
 };
 
+#define taskfs_export_attr(name)                            \
+    ({                                                      \
+        taskfs_export_attr_mapping(stringify(name),         \
+        (struct twimap_ops) {                               \
+            __task_read_##name,                             \
+            __twimap_default_gonext, __twimap_default_reset \
+        });                                                 \
+    })
+
+#define taskfs_export_list_attr(name)                       \
+    ({                                                      \
+        taskfs_export_attr_mapping(stringify(name),         \
+        (struct twimap_ops) {                               \
+            __task_read_##name,                             \
+            __task_gonext_##name, __task_reset_##name       \
+        });                                                 \
+    })
+
 void
 taskfs_init();
 
 void
-taskfs_export_attr(const char* key, struct twimap* attr_map_file);
+taskfs_export_attr_mapping(const char* key, struct twimap_ops ops);
 
 struct task_attribute*
 taskfs_get_attr(struct hstr* key);
index c9d56a2aaa6a1de1dcd8a8a29cdf74ed88b43808..465c99fc021a69424fdb8ca9d11fe6d1edead20b 100644 (file)
@@ -8,17 +8,37 @@
 
 extern struct v_file_ops twimap_file_ops;
 
+struct twimap;
+struct twimap_ops
+{
+    void (*read)(struct twimap* mapping);
+    int (*go_next)(struct twimap* mapping);
+    void (*reset)(struct twimap* mapping);
+};
+
 struct twimap
 {
     void* index;
     void* buffer;
     void* data;
     size_t size_acc;
-    void (*read)(struct twimap* mapping);
-    int (*go_next)(struct twimap* mapping);
-    void (*reset)(struct twimap* mapping);
+
+    union {
+        struct {
+            void (*read)(struct twimap* mapping);
+            int (*go_next)(struct twimap* mapping);
+            void (*reset)(struct twimap* mapping);
+        };
+        struct twimap_ops ops;
+    };
 };
 
+void
+__twimap_default_reset(struct twimap* map);
+
+int
+__twimap_default_gonext(struct twimap* map);
+
 int
 twimap_read(struct twimap* map, void* buffer, size_t len, size_t fpos);
 
index 62bdaeda41a53b27a520ffdb8f06826cb4ef0e8d..6a6dd0cad05903b0e78ac9cd1c5726cef77ef537 100644 (file)
@@ -68,12 +68,16 @@ twimap_read(struct twimap* map, void* buffer, size_t len, size_t fpos)
     size_t acc_size = MIN(len, map->size_acc - (pos - fpos)), rdlen = acc_size;
     memcpy(buffer, map->buffer + (pos - fpos), acc_size);
 
-    while (acc_size < len && map->go_next(map)) {
+    while (acc_size < len) {
         map->size_acc = 0;
         map->read(map);
         rdlen = MIN(len - acc_size, map->size_acc);
         memcpy(buffer + acc_size, map->buffer, rdlen);
         acc_size += rdlen;
+
+        if (!map->go_next(map)) {
+            break;
+        }
     }
 
     if (acc_size <= len - 1) {
index 1696d6e961ace4b3ac092809db67cd9dddd42183..53c1efa93f822dffe16e4f468f1a3df8970d681e 100644 (file)
@@ -558,6 +558,8 @@ vfs_i_alloc(struct v_superblock* sb)
 void
 vfs_i_free(struct v_inode* inode)
 {
+    assert(inode->link_count == 0);
+    
     if (inode->pg_cache) {
         pcache_release(inode->pg_cache);
         vfree(inode->pg_cache);
@@ -791,8 +793,12 @@ __vfs_readdir_callback(struct dir_context* dctx,
                        const int dtype)
 {
     struct lx_dirent* dent = (struct lx_dirent*)dctx->cb_data;
-    strncpy(dent->d_name, name, MIN(len, DIRENT_NAME_MAX_LEN));
-    dent->d_nlen = len;
+    int len_ = MIN(len, DIRENT_NAME_MAX_LEN - 1);
+
+    strncpy(dent->d_name, name, len_);
+    dent->d_name[len_] = 0;
+
+    dent->d_nlen = len_;
     dent->d_type = dtype;
 }
 
@@ -832,6 +838,17 @@ done:
     return DO_STATUS_OR_RETURN(errno);
 }
 
+static inline bool
+check_pcache_eligibility(struct v_fd* fd_s)
+{
+    struct v_inode* inode;
+
+    inode = fd_s->file->inode;
+    return !check_seqdev_node(inode) \
+        && !fsm_check_pseudo_fs(inode->sb->fs) \
+        && !(fd_s->flags & FO_DIRECT);
+}
+
 __DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count)
 {
     int errno = 0;
@@ -850,7 +867,7 @@ __DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count)
 
     file->inode->atime = clock_unixtime();
 
-    if (check_seqdev_node(file->inode) || (fd_s->flags & FO_DIRECT)) {
+    if (!check_pcache_eligibility(fd_s)) {
         errno = file->ops->read(file->inode, buf, count, file->f_pos);
     } else {
         errno = pcache_read(file->inode, buf, count, file->f_pos);
@@ -896,7 +913,7 @@ __DEFINE_LXSYSCALL3(int, write, int, fd, void*, buf, size_t, count)
         file->f_pos = inode->fsize;
     }
 
-    if (check_seqdev_node(inode) || (fd_s->flags & FO_DIRECT)) {
+    if (!check_pcache_eligibility(fd_s)) {
         errno = file->ops->write(inode, buf, count, file->f_pos);
     } else {
         errno = pcache_write(inode, buf, count, file->f_pos);
@@ -993,6 +1010,8 @@ vfs_get_path(struct v_dnode* dnode, char* buf, size_t size, int depth)
 
     size_t cpy_size = MIN(dnode->name.len, size - len);
     strncpy(buf + len, dnode->name.value, cpy_size);
+    buf[len + cpy_size] = 0;
+
     len += cpy_size;
 
     return len;
@@ -1453,9 +1472,9 @@ vfs_do_chdir(struct proc_info* proc, struct v_dnode* dnode)
     vfs_ref_dnode(dnode);
     proc->cwd = dnode;
 
+done:
     unlock_dnode(dnode);
 
-done:
     return errno;
 }
 
index e9f61b313af2bf466cb71656ccb27dd3cd1dfea1..be02c57f79bd181a9e1156b20410cff581f111ff 100644 (file)
@@ -446,7 +446,7 @@ commit_process(struct proc_info* process)
         assert(!proc_terminated(process->parent));
     }
 
-    if (sched_ctx.proc_list) {
+    if (likely(sched_ctx.proc_list)) {
         llist_append(sched_ctx.proc_list, &process->tasks);
     } else {
         sched_ctx.proc_list = &process->tasks;
index 7c4c83d1be6544930e15e4a4f2b639aa3a5a166a..20d256f0b1e4de147bc45dbed398cecd8874738a 100644 (file)
 #include <lunaix/fs/taskfs.h>
 #include <lunaix/process.h>
 
+#define proc(map)   (twimap_data(map, struct proc_info*))
+
 void
-__read_parent(struct twimap* map)
+__task_read_parent(struct twimap* map)
 {
-    struct proc_info* proc = twimap_data(map, struct proc_info*);
-    twimap_printf(map, "%d", proc->parent->pid);
+    twimap_printf(map, "%d", proc(map)->parent->pid);
 }
 
 void
-__read_ctimestamp(struct twimap* map)
+__task_read_created(struct twimap* map)
 {
-    struct proc_info* proc = twimap_data(map, struct proc_info*);
-    twimap_printf(map, "%d", proc->created);
+    twimap_printf(map, "%d", proc(map)->created);
 }
 
 void
-__read_pgid(struct twimap* map)
+__task_read_pgid(struct twimap* map)
 {
-    struct proc_info* proc = twimap_data(map, struct proc_info*);
-    twimap_printf(map, "%d", proc->pgid);
+    twimap_printf(map, "%d", proc(map)->pgid);
 }
 
 void
-__read_children(struct twimap* map)
+__task_read_cmdline(struct twimap* map)
 {
-    struct llist_header* proc_list = twimap_index(map, struct llist_header*);
-    struct proc_info* proc =
-      container_of(proc_list, struct proc_info, siblings);
-    if (!proc)
-        return;
-    twimap_printf(map, "%d ", proc->pid);
+    twimap_printf(map, "%s", proc(map)->cmd);
+}
+
+static inline void
+__get_protection(struct mm_region* vmr, char* prot_buf)
+{
+    prot_buf[0] = (vmr->attr & REGION_READ) ? 'r' : '-';
+    prot_buf[1] = (vmr->attr & REGION_WRITE) ? 'w' : '-';
+    prot_buf[2] = (vmr->attr & REGION_EXEC) ? 'x' : '-';
+    prot_buf[3] = shared_writable_region(vmr) ? 's' : 'p';
+    prot_buf[4] = 0;
+}
+
+static inline void
+__get_vmr_name(struct mm_region* vmr, char* buf, unsigned int size)
+{
+    int region_type;
+
+    region_type = (vmr->attr >> 16) & 0xf;
+
+    if (region_type == REGION_TYPE_STACK) {
+        strcpy(buf, "[stack]");
+    }
+
+    else if (region_type == REGION_TYPE_HEAP) {
+        strcpy(buf, "[heap]");
+    }
+
+    else if (vmr->mfile) {
+        vfs_get_path(vmr->mfile->dnode, buf, size, 0);
+    }
+    
+    else {
+        buf[0] = 0;
+    }
+}
+
+void
+__task_read_maps(struct twimap* map)
+{
+    struct llist_header* vmr_;
+    struct mm_region* vmr;
+    unsigned int size;
+
+    vmr_ = twimap_index(map, struct llist_header*);
+    vmr = container_of(vmr_, struct mm_region, head);
+    
+    assert(vmr_);
+
+    char prot[5], name[256];
+    
+    __get_protection(vmr, prot);
+    __get_vmr_name(vmr, name, 256);
+
+    size = vmr->end - vmr->start;
+
+    twimap_printf(map, "%012lx-%012lx %x %s    %s\n", 
+                 vmr->start, vmr->end, size, prot, name);
 }
 
 int
-__next_children(struct twimap* map)
+__task_gonext_maps(struct twimap* map)
 {
-    struct llist_header* proc = twimap_index(map, struct llist_header*);
-    struct proc_info* current = twimap_data(map, struct proc_info*);
-    if (!proc)
+    struct proc_mm* mm;
+    struct llist_header* vmr;
+
+    vmr = twimap_index(map, struct llist_header*);
+    mm = vmspace(proc(map));
+
+    if (!vmr)
         return 0;
-    map->index = proc->next;
-    if (map->index == &current->children) {
+        
+    map->index = vmr->next;
+    if (map->index == &mm->regions) {
         return 0;
     }
+    
     return 1;
 }
 
 void
-__reset_children(struct twimap* map)
+__task_reset_maps(struct twimap* map)
 {
-    struct proc_info* proc = twimap_data(map, struct proc_info*);
-    if (llist_empty(&proc->children)) {
+    struct proc_mm* mm;
+
+    mm = vmspace(proc(map));
+    if (llist_empty(&mm->regions)) {
         map->index = 0;
         return;
     }
-    map->index = proc->children.next;
+
+    map->index = mm->regions.next;
 }
 
 void
 export_task_attr()
 {
-    struct twimap* map;
-    
-    // FIXME goes to thread specific location
-    // map = twimap_create(NULL);
-    // map->read = __read_pending_sig;
-    // taskfs_export_attr("sig_pending", map);
-
-    // map = twimap_create(NULL);
-    // map->read = __read_masked_sig;
-    // taskfs_export_attr("sig_masked", map);
-
-    map = twimap_create(NULL);
-    map->read = __read_parent;
-    taskfs_export_attr("parent", map);
-
-    map = twimap_create(NULL);
-    map->read = __read_ctimestamp;
-    taskfs_export_attr("created", map);
-
-    map = twimap_create(NULL);
-    map->read = __read_pgid;
-    taskfs_export_attr("pgid", map);
-
-    map = twimap_create(NULL);
-    map->read = __read_children;
-    map->go_next = __next_children;
-    map->reset = __reset_children;
-    taskfs_export_attr("children", map);
+    taskfs_export_attr(parent);
+    taskfs_export_attr(created);
+    taskfs_export_attr(pgid);
+    taskfs_export_attr(cmdline);
+    taskfs_export_list_attr(maps);
 }
\ No newline at end of file
index 2015aec4ecbee608e0bffda7251078c19849f3ba..b8f0c18f8979c91e54f440231bf90dfe6b58cf40 100644 (file)
 #define COUNTER_MASK ((1 << 16) - 1)
 
 static struct hbucket* attr_export_table;
-static DEFINE_LLIST(attributes);
+static DEFINE_LIST(attributes);
 static volatile int ino_cnt = 1;
 
-int
+extern struct scheduler sched_ctx;
+
+static void
+__destruct_inode(struct v_inode* inode)
+{
+    vfree_safe(inode->data);
+}
+
+static int
 taskfs_next_counter()
 {
     return (ino_cnt = ((ino_cnt + 1) & COUNTER_MASK) + 1);
 }
 
-inode_t
+static inode_t
 taskfs_inode_id(pid_t pid, int sub_counter)
 {
     return ((pid & (MAX_PROCESS - 1)) << 16) | (sub_counter & COUNTER_MASK);
@@ -39,8 +47,10 @@ taskfs_mknod(struct v_dnode* dnode, pid_t pid, int sub_counter, int itype)
         if (!(inode = vfs_i_alloc(vsb))) {
             return ENOMEM;
         }
+
         inode->id = ino;
         inode->itype = itype;
+        inode->destruct = __destruct_inode;
         vfs_i_addhash(inode);
     }
 
@@ -48,6 +58,47 @@ taskfs_mknod(struct v_dnode* dnode, pid_t pid, int sub_counter, int itype)
     return 0;
 }
 
+static inline int
+__report_task_entries(struct v_file* file, struct dir_context* dctx)
+{
+    unsigned int counter = 0;
+    char name[VFS_NAME_MAXLEN];
+    struct proc_info *pos, *n;
+
+    llist_for_each(pos, n, sched_ctx.proc_list, tasks)
+    {
+        if (!fsapi_readdir_pos_entries_at(file, counter)) {
+            counter++;
+            continue;
+        }
+
+        ksnprintf(name, VFS_NAME_MAXLEN, "%d", pos->pid);
+        dctx->read_complete_callback(dctx, name, VFS_NAME_MAXLEN, DT_DIR);
+        return 1;
+    }
+
+    return 0;
+}
+
+static inline int
+__report_task_attributes(struct v_file* file, struct dir_context* dctx)
+{
+    unsigned int counter = 0;
+    struct task_attribute *pos, *n;
+
+    list_for_each(pos, n, attributes.first, siblings)
+    {
+        if (fsapi_readdir_pos_entries_at(file, counter)) {
+            dctx->read_complete_callback(
+                dctx, HSTR_VAL(pos->key), VFS_NAME_MAXLEN, DT_FILE);
+            return 1;
+        }
+        counter++;
+    }
+
+    return 0;
+}
+
 int
 taskfs_readdir(struct v_file* file, struct dir_context* dctx)
 {
@@ -64,35 +115,14 @@ taskfs_readdir(struct v_file* file, struct dir_context* dctx)
     }
 
     if (pid) {
-        struct task_attribute *pos, *n;
-        llist_for_each(pos, n, &attributes, siblings)
-        {
-            if (counter == file->f_pos) {
-                dctx->read_complete_callback(
-                  dctx, pos->key_val, VFS_NAME_MAXLEN, DT_FILE);
-                return 1;
-            }
-            counter++;
-        }
-        return 0;
+        return __report_task_attributes(file, dctx);
     }
 
-    char name[VFS_NAME_MAXLEN];
-    struct proc_info *root = get_process(pid), *pos, *n;
-    llist_for_each(pos, n, &root->tasks, tasks)
-    {
-        if (counter == file->f_pos) {
-            ksnprintf(name, VFS_NAME_MAXLEN, "%d", pos->pid);
-            dctx->read_complete_callback(dctx, name, VFS_NAME_MAXLEN, DT_DIR);
-            return 1;
-        }
-        counter++;
-    }
-    return 0;
+    return __report_task_entries(file, dctx);
 }
 
 // ascii to pid
-pid_t
+static inline pid_t
 taskfs_atop(const char* str)
 {
     pid_t t = 0;
@@ -107,50 +137,76 @@ taskfs_atop(const char* str)
     return t;
 }
 
+static inline int
+__init_task_inode(pid_t pid, struct v_dnode* dnode)
+{
+    struct twimap* map;
+    struct proc_info* proc;
+    struct task_attribute* tattr;
+    
+    tattr = taskfs_get_attr(&dnode->name);
+    if (!tattr || !(proc = get_process(pid)))
+        return ENOENT;
+
+    map = twimap_create(proc);
+    map->ops = tattr->ops;
+
+    dnode->inode->data = map;
+    dnode->inode->default_fops = &twimap_file_ops;
+    
+    return 0;
+}
+
+static int
+__lookup_attribute(pid_t pid, struct v_dnode* dnode)
+{
+    int errno;    
+
+    errno = taskfs_mknod(dnode, pid, taskfs_next_counter(), VFS_IFFILE);
+    if (errno) {
+        return errno;
+    }
+
+    return __init_task_inode(pid, dnode);
+}
+
 int
 taskfs_dirlookup(struct v_inode* this, struct v_dnode* dnode)
 {
     pid_t pid = this->id >> 16;
-    struct proc_info* proc;
 
     if (pid) {
-        struct task_attribute* tattr = taskfs_get_attr(&dnode->name);
-        if (!tattr || !(proc = get_process(pid)))
-            return ENOENT;
-
-        int errno =
-          taskfs_mknod(dnode, pid, taskfs_next_counter(), VFS_IFSEQDEV);
-        if (!errno) {
-            tattr->map_file->data = proc;
-            dnode->inode->data = tattr->map_file;
-            dnode->inode->default_fops = &twimap_file_ops;
-        }
-        return errno;
+        return __lookup_attribute(pid, dnode);
     }
 
     pid = taskfs_atop(dnode->name.value);
 
-    if (pid <= 0 || !(proc = get_process(pid))) {
+    if (pid <= 0) {
         return ENOENT;
     }
 
-    return taskfs_mknod(dnode, pid, 0, F_DIR);
+    return taskfs_mknod(dnode, pid, 0, VFS_IFDIR);
 }
 
-static struct v_file_ops taskfs_file_ops = { .close = default_file_close,
-                                             .read = default_file_read,
-                                             .read_page =
-                                               default_file_read_page,
-                                             .write = default_file_write,
-                                             .write_page =
-                                               default_file_write_page,
-                                             .readdir = taskfs_readdir,
-                                             .seek = default_file_seek };
-static struct v_inode_ops taskfs_inode_ops = { .dir_lookup = taskfs_dirlookup,
-                                               .open = default_inode_open,
-                                               .mkdir = default_inode_mkdir,
-                                               .rmdir = default_inode_rmdir,
-                                               .rename = default_inode_rename };
+static struct v_file_ops taskfs_file_ops = { 
+    .close =        default_file_close,
+    .read =         default_file_read,
+    .read_page =    default_file_read_page,
+    .write =        default_file_write,
+    .write_page =   default_file_write_page,
+    .readdir =      taskfs_readdir,
+    .seek =         default_file_seek 
+};
+
+static struct v_inode_ops taskfs_inode_ops = { 
+    .dir_lookup =   taskfs_dirlookup,
+    .open =         default_inode_open,
+    .mkdir =        default_inode_mkdir,
+    .rmdir =        default_inode_rmdir,
+    .rename =       default_inode_rename 
+};
+
+static volatile struct v_superblock* taskfs_sb;
 
 void
 taskfs_init_inode(struct v_superblock* vsb, struct v_inode* inode)
@@ -159,8 +215,6 @@ taskfs_init_inode(struct v_superblock* vsb, struct v_inode* inode)
     inode->ops = &taskfs_inode_ops;
 }
 
-static volatile struct v_superblock* taskfs_sb;
-
 int
 taskfs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
 {
@@ -180,8 +234,9 @@ void
 taskfs_invalidate(pid_t pid)
 {
     struct v_dnode *pos, *n;
-    struct v_inode* inode = vfs_i_find(taskfs_sb, taskfs_inode_id(pid, 0));
+    struct v_inode* inode;
 
+    inode = vfs_i_find(taskfs_sb, taskfs_inode_id(pid, 0));
     if (!inode)
         return;
 
@@ -192,23 +247,33 @@ taskfs_invalidate(pid_t pid)
         }
         vfs_d_free(pos);
     }
+
+    if (!inode->link_count) {
+        vfs_i_free(inode);
+    }
 }
 
 #define ATTR_TABLE_LEN 16
+#define ATTR_KEY_LEN 32
 
 void
-taskfs_export_attr(const char* key, struct twimap* attr_map_file)
+taskfs_export_attr_mapping(const char* key, struct twimap_ops ops)
 {
-    struct task_attribute* tattr = valloc(sizeof(*tattr));
+    char* key_val;
+    struct hbucket* slot;
+    struct task_attribute* tattr;
+    
+    tattr = valloc(sizeof(*tattr));
+    key_val = valloc(ATTR_KEY_LEN);
 
-    tattr->map_file = attr_map_file;
-    tattr->key = HSTR(tattr->key_val, 0);
-    strncpy(tattr->key_val, key, 32);
+    tattr->ops = ops;
+    tattr->key = HSTR(key_val, 0);
+    strncpy(key_val, key, ATTR_KEY_LEN);
     hstr_rehash(&tattr->key, HSTR_FULL_HASH);
 
-    struct hbucket* slot = &attr_export_table[tattr->key.hash % ATTR_TABLE_LEN];
+    slot = &attr_export_table[tattr->key.hash % ATTR_TABLE_LEN];
     hlist_add(&slot->head, &tattr->attrs);
-    llist_append(&attributes, &tattr->siblings);
+    list_add(&attributes, &tattr->siblings);
 }
 
 struct task_attribute*
index 7a3b430faad8a4cc673073ee752b7de6f099691c..400aeec4ae1c52ade64a890db2a41ab5ebdd5a48 100644 (file)
@@ -27,18 +27,13 @@ strcpy(char* dest, const char* src)
 char* _weak
 strncpy(char* dest, const char* src, unsigned long n)
 {
-    char c;
+    char c = '\0';
     unsigned int i = 0;
-    while (i <= n && (c = src[i]))
+    while (i < n && (c = src[i]))
         dest[i++] = c;
 
-    if (!(n < i && src[i - 1])) {
-        while (i <= n)
-            dest[i++] = 0;
-    }
-    else {
-        dest[i - 1] = 0;
-    }
+    while (i < n)
+        dest[i++] = 0;
     
     return dest;
 }
\ No newline at end of file