feat: fstat now handle symbolic link
authorMinep <lunaixsky@qq.com>
Thu, 7 Sep 2023 19:55:56 +0000 (20:55 +0100)
committerMinep <lunaixsky@qq.com>
Thu, 7 Sep 2023 19:55:56 +0000 (20:55 +0100)
refactor: file type mask rework
fix: device definition should be reflected on the abstract device struct

46 files changed:
lunaix-os/arch/i386/syscall.S
lunaix-os/hal/ahci/ahci.c
lunaix-os/hal/char/devnull.c
lunaix-os/hal/char/devzero.c
lunaix-os/hal/char/ps2kbd.c
lunaix-os/hal/char/serial.c
lunaix-os/hal/char/uart/16550_pmio.c
lunaix-os/hal/pci.c
lunaix-os/hal/rng/rngx86.c
lunaix-os/hal/rtc/hwrtc.c
lunaix-os/hal/rtc/mc146818a.c
lunaix-os/hal/timer/apic_timer.c
lunaix-os/hal/timer/hwtimer.c
lunaix-os/includes/hal/hwrtc.h
lunaix-os/includes/hal/hwtimer.h
lunaix-os/includes/hal/serial.h
lunaix-os/includes/lunaix/block.h
lunaix-os/includes/lunaix/device.h
lunaix-os/includes/lunaix/device_num.h
lunaix-os/includes/lunaix/fs.h
lunaix-os/includes/lunaix/input.h
lunaix-os/includes/usr/lunaix/fcntl_defs.h
lunaix-os/includes/usr/lunaix/fstypes.h [new file with mode: 0644]
lunaix-os/includes/usr/lunaix/syscallid.h
lunaix-os/includes/usr/lunaix/types.h
lunaix-os/kernel/block/block.c
lunaix-os/kernel/device/devdb.c
lunaix-os/kernel/device/devfs.c
lunaix-os/kernel/device/device.c
lunaix-os/kernel/device/input.c
lunaix-os/kernel/fs/iso9660/directory.c
lunaix-os/kernel/fs/iso9660/inode.c
lunaix-os/kernel/fs/iso9660/mount.c
lunaix-os/kernel/fs/mount.c
lunaix-os/kernel/fs/path_walk.c
lunaix-os/kernel/fs/probe_boot.c
lunaix-os/kernel/fs/ramfs/ramfs.c
lunaix-os/kernel/fs/twifs/twifs.c
lunaix-os/kernel/fs/vfs.c
lunaix-os/kernel/process/taskfs.c
lunaix-os/kernel/tty/lxconsole.c
lunaix-os/usr/libc/arch/i386/fcntl.c
lunaix-os/usr/libc/includes/fcntl.h
lunaix-os/usr/makefile
lunaix-os/usr/stat/main.c [new file with mode: 0644]
lunaix-os/usr/stat/makefile [new file with mode: 0644]

index ac3fe80d4a75afb9a7d93e643324309f62345d58..5a6f6a08db67b9c081e361d25e33dc9678b36362 100644 (file)
@@ -62,6 +62,7 @@
         .long __lxsys_sys_mmap
         .long __lxsys_munmap
         .long __lxsys_execve
+        .long __lxsys_fstat         /* 55 */
         2:
         .rept __SYSCALL_MAX - (2b - 1b)/4
             .long 0
index 2b1176e4742dad14458240faf06b762afe2c2856..220038ac6d112602ceb17831117ac638f7f0ce3a 100644 (file)
@@ -31,6 +31,7 @@
 #define HBA_CLB_SIZE 1024
 
 #define HBA_MY_IE (HBA_PxINTR_DHR | HBA_PxINTR_TFE | HBA_PxINTR_OF)
+#define AHCI_DEVCLASS DEVCLASS(DEVIF_PCI, DEVFN_STORAGE, DEV_SATA, 0)
 
 // #define DO_HBA_FULL_RESET
 
@@ -43,6 +44,8 @@ static char sata_ifs[][20] = { "Not detected",
                                "SATA II (3.0Gbps)",
                                "SATA III (6.0Gbps)" };
 
+static struct devclass ahci_class = AHCI_DEVCLASS;
+
 extern void
 ahci_fsexport(struct block_dev* bdev, void* fs_node);
 
@@ -209,6 +212,7 @@ ahci_register_device(struct hba_device* hbadev)
 
     bdev->end_lba = hbadev->max_lba;
     bdev->blk_size = hbadev->block_size;
+    bdev->class = &ahci_class;
 
     block_mount(bdev, ahci_fsexport);
 }
index 0bdf99c25e4faf36fa5cbea0cc0423cd7edbe3f6..5d0aef5e6f72639dea3f8db0237ce686a2c5b85d 100644 (file)
@@ -30,9 +30,9 @@ __null_rd(struct device* dev, void* buf, size_t offset, size_t len)
 }
 
 static int
-pdev_nulldev_init(struct device_def*)
+pdev_nulldev_init(struct device_def* def)
 {
-    struct device* devnull = device_addseq(NULL, NULL, "null");
+    struct device* devnull = device_addseq(NULL, &def->class, NULL, "null");
     devnull->ops.write_page = __null_wr_pg;
     devnull->ops.write = __null_wr;
     devnull->ops.read_page = __null_rd_pg;
index d5f13c69f9268bb1d2426c96791fd3f7de46c387..cd4a6ebd817a7d4024b6535e757d4c698c3e0b1f 100644 (file)
@@ -18,9 +18,9 @@ __zero_rd(struct device* dev, void* buf, size_t offset, size_t len)
 }
 
 static int
-pdev_zerodev_init(struct device_def*)
+pdev_zerodev_init(struct device_def* def)
 {
-    struct device* devzero = device_addseq(NULL, NULL, "zero");
+    struct device* devzero = device_addseq(NULL, &def->class, NULL, "zero");
     devzero->ops.read_page = __zero_rd_pg;
     devzero->ops.read = __zero_rd;
 
index d2be85dbe8b0dae0d4ec75c74dd5130efbb2d68c..77568918fefa81669cec947f222dccae8b70ae2a 100644 (file)
@@ -224,7 +224,7 @@ ps2_kbd_init(struct device_def* devdef)
     kbd_state.translation_table = scancode_set2;
     kbd_state.state = KBD_STATE_KWAIT;
 
-    kbd_idev = input_add_device("i8042-kbd");
+    kbd_idev = input_add_device(&devdef->class, devdef->name);
 
     /* FIXME This require systematical rework! */
     // acpi_context* acpi_ctx = acpi_get_context();
index 8997c57ed594871ff49f147c47ce1d1dab784400..9297136a5b02a580862de8ef4c46effce27c7a07 100644 (file)
@@ -158,10 +158,11 @@ __serial_exec_command(struct device* dev, u32_t req, va_list args)
 #define RXBUF_SIZE 512
 
 struct serial_dev*
-serial_create()
+serial_create(struct devclass* class)
 {
     struct serial_dev* sdev = valloc(sizeof(struct serial_dev));
-    struct device* dev = device_addseq(NULL, sdev, "ttyS%d", serial_idx++);
+    struct device* dev =
+      device_addseq(NULL, class, sdev, "ttyS%d", serial_idx++);
     dev->ops.read = __serial_read;
     dev->ops.read_page = __serial_read_page;
     dev->ops.write = __serial_write;
index 1415174f432c96593f554344dc60a7df3a8ca68d..ed3a6186504b2210f6dcb7059145d218a143add2 100644 (file)
@@ -77,7 +77,7 @@ upiom_init(struct device_def* def)
         uart_enable_fifo(uart, UART_FIFO8);
         llist_append(&com_ports, &uart->local_ports);
 
-        struct serial_dev* sdev = serial_create();
+        struct serial_dev* sdev = serial_create(&def->class);
         sdev->backend = uart;
         sdev->write = uart_general_tx;
         sdev->exec_cmd = uart_general_exec_cmd;
index 9ac45d5ca680a266d429dc3203a188035acea78a..3859e0c368e073449860319e834b22b61715d18f 100644 (file)
@@ -63,7 +63,7 @@ found:
     device->cspace_base = pci_base;
     device->intr_info = intr;
 
-    device_prepare(&device->dev);
+    device_prepare(&device->dev, &pos->devdef.class);
 
     pci_probe_msi_info(device);
     pci_probe_bar_info(device);
index af11802a43378de27c63f40ee62cb911e6ca4629..f398c662a0cb87c13666ec29ae872d34cf058098 100644 (file)
@@ -31,7 +31,7 @@ __rand_rd(struct device* dev, void* buf, size_t offset, size_t len)
 int
 pdev_randdev_init(struct device_def* devdef)
 {
-    struct device* devrand = device_addseq(NULL, NULL, "rand");
+    struct device* devrand = device_addseq(NULL, &devdef->class, NULL, "rand");
     devrand->ops.read = __rand_rd;
     devrand->ops.read_page = __rand_rd_pg;
 
index 5a53664214da108e4435a917fa8598b3640a620b..82f98eb9fbf2f132abe443b2783fe5f4fe789c16 100644 (file)
@@ -69,7 +69,7 @@ hwrtc_read(struct device* dev, void* buf, size_t offset, size_t len)
 }
 
 struct hwrtc*
-hwrtc_alloc_new(char* name)
+hwrtc_alloc_new(struct device_def* def, char* name)
 {
     struct hwrtc* rtc_instance = valloc(sizeof(struct hwrtc));
 
@@ -85,7 +85,7 @@ hwrtc_alloc_new(char* name)
 
     rtc_instance->name = name;
     struct device* rtcdev =
-      device_addsys(NULL, rtc_instance, "rtc%d", rtc_count);
+      device_addsys(NULL, &def->class, rtc_instance, "rtc%d", rtc_count);
 
     rtcdev->ops.exec_cmd = hwrtc_ioctl;
     rtcdev->ops.read = hwrtc_read;
index c36412a8d293aa2a2f55ab08db05db66a4cfee73..dce0a5179ad8386212d9552d1f417259c50a5a2e 100644 (file)
@@ -195,7 +195,7 @@ rtc_init(struct device_def* devdef)
     // Make sure the rtc timer is disabled by default
     rtc_disable_timer();
 
-    struct hwrtc* rtc = hwrtc_alloc_new("mc146818");
+    struct hwrtc* rtc = hwrtc_alloc_new(devdef, "mc146818");
     struct mc146818* state = valloc(sizeof(struct mc146818));
 
     state->rtc_context = rtc;
index 15b3e827ef2f14ad064f7432ac49224527ebde22..c52cebe5d03210d0cbde466b213c7b6fee97db55 100644 (file)
@@ -151,6 +151,8 @@ struct hwtimer*
 apic_hwtimer_context()
 {
     static struct hwtimer apic_hwt = { .name = "apic_timer",
+                                       .class = DEVCLASS(
+                                         DEVIF_SOC, DEVFN_TIME, DEV_TIMER, 0),
                                        .init = apic_timer_init,
                                        .supported = apic_timer_check,
                                        .systicks = apic_get_systicks };
index 1a994f7d3d163dcce4abaec3c9d5d530f3875bf1..4da156895fb3de77384edb9e0ac5dc5a75f058e5 100644 (file)
@@ -58,7 +58,8 @@ hwtimer_init(u32_t hertz, void* tick_callback)
 
     current_timer = hwt_ctx;
 
-    struct device* timerdev = device_addsys(NULL, hwt_ctx, hwt_ctx->name);
+    struct device* timerdev =
+      device_addsys(NULL, &hwt_ctx->class, hwt_ctx, hwt_ctx->name);
 
     timerdev->ops.exec_cmd = __hwtimer_ioctl;
 }
\ No newline at end of file
index fcd4d48a5f2ddccc6599fc51463b1e4304e5f898..a5ebb9c21e0587c3f9de6df0d2ee895fb0983aef 100644 (file)
@@ -35,7 +35,7 @@ void
 hwrtc_init();
 
 struct hwrtc*
-hwrtc_alloc_new(char* driver_id);
+hwrtc_alloc_new(struct device_def* def, char* name);
 
 void
 hwrtc_walltime(datetime_t* dt);
index 83ff92c8bc9c3bc75162edb913009071db437ebf..22fdaacc37b71168bf624a2db00e43d95bf55d33 100644 (file)
@@ -12,6 +12,7 @@ struct hwtimer
     char* name;
     void* data;
 
+    struct devclass class;
     struct device* timer_dev;
 
     int (*supported)(struct hwtimer*);
index b2fdf5ebc2ff6906a2d6f9570562fc11c99c63a4..8346fd0422dd5ba22008b1f1dcc44aad3515f09b 100644 (file)
@@ -43,7 +43,7 @@ struct serial_dev
 };
 
 struct serial_dev*
-serial_create();
+serial_create(struct devclass* class);
 
 void
 serial_readone(struct serial_dev* sdev, u8_t* val);
index 0ddd00058cb585a22fdf6b17095d26582c85b00c..0eb777542aaef8415ed3d29a6f9b0781b9f629c4 100644 (file)
@@ -31,6 +31,7 @@ struct block_dev
     u64_t end_lba;
     u32_t blk_size;
     struct block_dev_ops ops;
+    struct devclass* class;
 };
 
 // Lunaix Partition Table
index cb2c2947a5b52264d33bcaed959faf18b7f4f3c8..af21cb35d0062f1dbbe12f674c05819a14b4e9e3 100644 (file)
@@ -65,8 +65,6 @@
 #define DEV_IFCAT 0x2 // a device category (as device groupping)
 #define DEV_IFSYS 0x3 // a system device
 
-typedef unsigned int dev_t;
-
 struct devclass
 {
     u32_t meta;
@@ -84,8 +82,8 @@ struct device
     // TODO investigate event polling
 
     struct hstr name;
-    struct devclass class;
-    dev_t dev_id;
+    struct devclass* class;
+    u32_t dev_uid;
     int dev_type;
     char name_val[DEVICE_NAME_SIZE];
     void* underlay;
@@ -123,11 +121,17 @@ static inline u32_t devclass_hash(struct devclass class)
            ~class.meta;
 }
 
+static inline u32_t
+device_id_from_class(struct devclass* class)
+{
+    return ((class->device & 0xffff) << 16) | ((class->variant & 0xffff));
+}
+
 void
 device_register_all();
 
 void
-device_prepare(struct device* dev);
+device_prepare(struct device* dev, struct devclass* class);
 
 void
 device_setname(struct device* dev, char* fmt, ...);
@@ -140,23 +144,37 @@ device_add_vargs(struct device* parent,
                  void* underlay,
                  char* name_fmt,
                  u32_t type,
+                 struct devclass* class,
                  va_list args);
 
 struct device*
 device_add(struct device* parent,
+           struct devclass* class,
            void* underlay,
            u32_t type,
            char* name_fmt,
            ...);
 
 struct device*
-device_addsys(struct device* parent, void* underlay, char* name_fmt, ...);
+device_addsys(struct device* parent,
+              struct devclass* class,
+              void* underlay,
+              char* name_fmt,
+              ...);
 
 struct device*
-device_addseq(struct device* parent, void* underlay, char* name_fmt, ...);
+device_addseq(struct device* parent,
+              struct devclass* class,
+              void* underlay,
+              char* name_fmt,
+              ...);
 
 struct device*
-device_addvol(struct device* parent, void* underlay, char* name_fmt, ...);
+device_addvol(struct device* parent,
+              struct devclass* class,
+              void* underlay,
+              char* name_fmt,
+              ...);
 
 struct device*
 device_addcat(struct device* parent, char* name_fmt, ...);
@@ -165,7 +183,7 @@ void
 device_remove(struct device* dev);
 
 struct device*
-device_getbyid(struct llist_header* devlist, dev_t id);
+device_getbyid(struct llist_header* devlist, u32_t id);
 
 struct device*
 device_getbyhname(struct device* root_dev, struct hstr* name);
index 704c39bc3a33dfa83060351e099352aab3c90f81..d6052cdb0c09160e09e84828d32a342c3fa17113 100644 (file)
@@ -76,5 +76,6 @@
 #define DEV_NVME 0x5
 #define DEV_BUS 0x6
 #define DEV_SERIAL 0x7
+#define DEV_TIMER 0x8
 
 #endif /* __LUNAIX_DEVICE_NUM_H */
index d90a773294099a40ef39ea90df2314aaabcc2c7d..d5990235253f2b06485b7f10d23d63ac2b5f84cd 100644 (file)
 #include <lunaix/ds/lru.h>
 #include <lunaix/ds/mutex.h>
 #include <lunaix/status.h>
+
 #include <stdatomic.h>
 
+#include <usr/lunaix/fstypes.h>
+
 #define VFS_NAME_MAXLEN 128
 #define VFS_MAX_FD 32
 
-#define VFS_IFDIR 0x1
-#define VFS_IFFILE 0x2
-#define VFS_IFSEQDEV 0x4
-#define VFS_IFVOLDEV 0x8
-#define VFS_IFSYMLINK 0x10
+#define VFS_IFDIR F_DIR
+#define VFS_IFFILE F_FILE
+#define VFS_IFDEV (F_DEV | F_FILE)
+#define VFS_IFSEQDEV (F_SEQDEV | F_FILE)
+#define VFS_IFVOLDEV (F_VOLDEV | F_FILE)
+#define VFS_IFSYMLINK (F_SYMLINK | F_FILE)
+
+#define VFS_DEVFILE(type) ((type) & F_DEV)
+#define VFS_DEVTYPE(type) ((type) & ((F_SEQDEV | F_VOLDEV) ^ F_DEV))
 
 // Walk, mkdir if component encountered is non-exists.
 #define VFS_WALK_MKPARENT 0x1
@@ -48,7 +55,7 @@
 
 #define TEST_FD(fd) (fd >= 0 && fd < VFS_MAX_FD)
 
-#define EXPORT_FILE_SYSTEM(fs_id, init_fn)                                        \
+#define EXPORT_FILE_SYSTEM(fs_id, init_fn)                                     \
     export_ldga_el(fs, fs_id, ptr_t, init_fn)
 
 #define VFS_VALID_CHAR(chr)                                                    \
@@ -107,6 +114,7 @@ struct v_superblock
     struct filesystem* fs;
     struct hbucket* i_cache;
     void* data;
+    size_t blksize;
     struct
     {
         u32_t (*read_capacity)(struct v_superblock* vsb);
index 9f7008f450247a5050e866bf2ff459248f1e2219..28c89626e0ca794f632dcc52440c0138afc3ebdf 100644 (file)
@@ -56,6 +56,6 @@ void
 input_add_listener(input_evt_cb listener);
 
 struct input_device*
-input_add_device(char* name_fmt, ...);
+input_add_device(struct devclass* class, char* name_fmt, ...);
 
 #endif /* __LUNAIX_INPUT_H */
index c6cbe4f645e98574386bd5d308e1ce0e07e96791..7659a3200c9c879e5f6c1fd68f52e1b5e2d2ac3c 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef __LUNAIX_SYS_FCNTL_DEFS_H
 #define __LUNAIX_SYS_FCNTL_DEFS_H
 
+#include "fstypes.h"
+#include "types.h"
+
 #define FO_CREATE 0x1
 #define FO_APPEND 0x2
 #define FO_DIRECT 0x4
@@ -8,6 +11,8 @@
 #define FO_RDONLY 0x10
 #define FO_RDWR 0x20
 
+#define FO_NOFOLLOW 0x10000
+
 #define FSEEK_SET 0x1
 #define FSEEK_CUR 0x2
 #define FSEEK_END 0x3
 
 #define MNT_RO 0x1
 
+struct file_stat
+{
+    dev_t st_dev;
+    ino_t st_ino;
+    unsigned int mode;
+    dev_t st_rdev;
+    off_t st_size;
+    size_t st_blksize;
+    size_t st_ioblksize;
+    size_t st_blocks;
+};
+
 #endif /* __LUNAIX_FNCTL_DEFS_H */
diff --git a/lunaix-os/includes/usr/lunaix/fstypes.h b/lunaix-os/includes/usr/lunaix/fstypes.h
new file mode 100644 (file)
index 0000000..957ede0
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __LUNAIX_FSTYPES_H
+#define __LUNAIX_FSTYPES_H
+
+#define F_DIR 0x0
+#define F_FILE 0x1
+#define F_DEV 0x2
+#define F_SEQDEV 0x6
+#define F_VOLDEV 0xa
+#define F_SYMLINK 0x10
+
+#define F_MFILE 0b00001
+#define F_MDEV 0b01110
+#define F_MSLNK 0b10000
+
+#endif /* __LUNAIX_FSTYPES_H */
index d388e1250e4fe1956f36217b2bbb71b1515207e9..aa1180d4a16c17b895abe91e19939a22b7858a3d 100644 (file)
@@ -63,6 +63,8 @@
 
 #define __SYSCALL_execve 54
 
+#define __SYSCALL_fstat 55
+
 #define __SYSCALL_MAX 0x100
 
 #endif /* __LUNAIX_SYSCALLID_H */
index 4c197f5ab12fdc37f8b85bc1df37245dbf034c22..9650b47a86badfaae05066800376829d7085f212 100644 (file)
@@ -28,4 +28,13 @@ typedef unsigned long size_t;
 
 typedef unsigned long off_t;
 
+typedef unsigned int ino_t;
+
+typedef struct dev_t
+{
+    unsigned int meta;
+    unsigned int devident;
+    unsigned int dev_uid;
+} dev_t;
+
 #endif /* __LUNAIX_TYPES_H */
index 460e94bf3c4690394b4bf2240113ace6ae5a5397..76ef7787f36d3864b162a96f3df7c4916d57bf1c 100644 (file)
@@ -319,7 +319,7 @@ __block_register(struct block_dev* bdev)
     }
 
     struct device* dev =
-      device_addvol(blk_parent_dev, bdev, "sd%c", 'a' + free_slot);
+      device_addvol(blk_parent_dev, bdev->class, bdev, "sd%c", 'a' + free_slot);
     dev->ops.write = __block_write;
     dev->ops.write_page = __block_write_page;
     dev->ops.read = __block_read;
@@ -341,8 +341,8 @@ blk_mount_part(struct block_dev* bdev,
     struct block_dev* pbdev = cake_grab(lbd_pile);
     memcpy(pbdev, bdev, sizeof(*bdev));
 
-    struct device* dev =
-      device_addvol(NULL, pbdev, "%sp%d", bdev->bdev_id, index + 1);
+    struct device* dev = device_addvol(
+      NULL, pbdev->class, pbdev, "%sp%d", bdev->bdev_id, index + 1);
     dev->ops.write = __block_write;
     dev->ops.write_page = __block_write_page;
     dev->ops.read = __block_read;
index db45ed933b636cb6b4fa49ffbc67a356a1237344..f77afec56a02d4f4b9ffc164fd9a53e5191b1348 100644 (file)
@@ -85,7 +85,7 @@ device_create_byclass(struct devclass* class,
         return NULL;
     }
 
-    struct device* dev = device_add(adhoc_devcat, NULL, type, NULL);
+    struct device* dev = device_add(adhoc_devcat, class, NULL, type, NULL);
 
     errno = devdef->init_for(devdef, dev);
     if (err_code && !errno) {
@@ -100,7 +100,7 @@ device_create_byclass(struct devclass* class,
                    class->meta,
                    class->device,
                    class->device,
-                   dev->dev_id);
+                   dev->dev_uid);
 
     return dev;
 }
index fb55d2403b10dfdd70ea152d92ffdbd8e6d85123..1a49b0519ebdca9882b67baae30cf661ec6a4762 100644 (file)
@@ -73,8 +73,10 @@ devfs_get_itype(struct device* dev)
         itype = VFS_IFDIR;
     } else if (dev_if == DEV_IFVOL) {
         itype |= VFS_IFVOLDEV;
-    } else {
+    } else if (dev_if == DEV_IFSEQ) {
         itype |= VFS_IFSEQDEV;
+    } else {
+        itype |= VFS_IFDEV;
     }
     return itype;
 }
@@ -96,10 +98,10 @@ devfs_mknod(struct v_dnode* dnode, struct device* dev)
 {
     assert(dev);
 
-    struct v_inode* devnod = vfs_i_find(dnode->super_block, dev->dev_id);
+    struct v_inode* devnod = vfs_i_find(dnode->super_block, dev->dev_uid);
     if (!devnod) {
         if ((devnod = vfs_i_alloc(dnode->super_block))) {
-            devnod->id = dev->dev_id;
+            devnod->id = dev->dev_uid;
             devnod->data = dev;
             devnod->itype = devfs_get_itype(dev);
 
index ae855ef52dcf51e80ed5f88d12c9e907b5622a6f..d26808a4646dbe453ff276e6f2836b6e1e203f6d 100644 (file)
 
 static DEFINE_LLIST(root_list);
 
-static volatile dev_t devid = 0;
+static volatile u32_t devid = 0;
+
+struct devclass default_devclass = {};
 
 void
-device_prepare(struct device* dev)
+device_prepare(struct device* dev, struct devclass* class)
 {
     dev->magic = DEV_STRUCT_MAGIC;
-    dev->dev_id = devid++;
+    dev->dev_uid = devid++;
+    dev->class = class ? class : &default_devclass;
 
     llist_init_head(&dev->children);
 }
@@ -53,11 +56,12 @@ device_add_vargs(struct device* parent,
                  void* underlay,
                  char* name_fmt,
                  u32_t type,
+                 struct devclass* class,
                  va_list args)
 {
     struct device* dev = vzalloc(sizeof(struct device));
 
-    device_prepare(dev);
+    device_prepare(dev, class);
 
     if (parent) {
         assert((parent->dev_type & DEV_MSKIF) == DEV_IFCAT);
@@ -79,6 +83,7 @@ device_add_vargs(struct device* parent,
 
 struct device*
 device_add(struct device* parent,
+           struct devclass* class,
            void* underlay,
            u32_t type,
            char* name_fmt,
@@ -88,46 +93,58 @@ device_add(struct device* parent,
     va_start(args, name_fmt);
 
     struct device* dev =
-      device_add_vargs(parent, underlay, name_fmt, type, args);
+      device_add_vargs(parent, underlay, name_fmt, type, class, args);
 
     va_end(args);
     return dev;
 }
 
 struct device*
-device_addsys(struct device* parent, void* underlay, char* name_fmt, ...)
+device_addsys(struct device* parent,
+              struct devclass* class,
+              void* underlay,
+              char* name_fmt,
+              ...)
 {
     va_list args;
     va_start(args, name_fmt);
 
     struct device* dev =
-      device_add_vargs(parent, underlay, name_fmt, DEV_IFSEQ, args);
+      device_add_vargs(parent, underlay, name_fmt, DEV_IFSYS, class, args);
 
     va_end(args);
     return dev;
 }
 
 struct device*
-device_addseq(struct device* parent, void* underlay, char* name_fmt, ...)
+device_addseq(struct device* parent,
+              struct devclass* class,
+              void* underlay,
+              char* name_fmt,
+              ...)
 {
     va_list args;
     va_start(args, name_fmt);
 
     struct device* dev =
-      device_add_vargs(parent, underlay, name_fmt, DEV_IFSEQ, args);
+      device_add_vargs(parent, underlay, name_fmt, DEV_IFSEQ, class, args);
 
     va_end(args);
     return dev;
 }
 
 struct device*
-device_addvol(struct device* parent, void* underlay, char* name_fmt, ...)
+device_addvol(struct device* parent,
+              struct devclass* class,
+              void* underlay,
+              char* name_fmt,
+              ...)
 {
     va_list args;
     va_start(args, name_fmt);
 
     struct device* dev =
-      device_add_vargs(parent, underlay, name_fmt, DEV_IFVOL, args);
+      device_add_vargs(parent, underlay, name_fmt, DEV_IFVOL, class, args);
 
     va_end(args);
     return dev;
@@ -140,20 +157,20 @@ device_addcat(struct device* parent, char* name_fmt, ...)
     va_start(args, name_fmt);
 
     struct device* dev =
-      device_add_vargs(parent, NULL, name_fmt, DEV_IFCAT, args);
+      device_add_vargs(parent, NULL, name_fmt, DEV_IFCAT, NULL, args);
 
     va_end(args);
     return dev;
 }
 
 struct device*
-device_getbyid(struct llist_header* devlist, dev_t id)
+device_getbyid(struct llist_header* devlist, u32_t id)
 {
     devlist = devlist ? devlist : &root_list;
     struct device *pos, *n;
     llist_for_each(pos, n, devlist, siblings)
     {
-        if (pos->dev_id == id) {
+        if (pos->dev_uid == id) {
             return pos;
         }
     }
@@ -210,15 +227,15 @@ device_getbyoffset(struct device* root_dev, int offset)
 static inline void
 device_populate_info(struct device* dev, struct dev_info* devinfo)
 {
-    devinfo->dev_id.meta = dev->class.meta;
-    devinfo->dev_id.device = dev->class.device;
-    devinfo->dev_id.variant = dev->class.variant;
+    devinfo->dev_id.meta = dev->class->meta;
+    devinfo->dev_id.device = dev->class->device;
+    devinfo->dev_id.variant = dev->class->variant;
 
     if (!devinfo->dev_name.buf) {
         return;
     }
 
-    struct device_def* def = devdef_byclass(&dev->class);
+    struct device_def* def = devdef_byclass(dev->class);
     size_t buflen = devinfo->dev_name.buf_len;
 
     strncpy(devinfo->dev_name.buf, def->name, buflen);
index 52c8820400f31f8c06c28b1308eba0b21d5cfbbf..252993f934d56bef8041e0c0af57e3ca92ebc05c 100644 (file)
@@ -70,7 +70,7 @@ __input_dev_read_pg(struct device* dev, void* buf, size_t offset)
 }
 
 struct input_device*
-input_add_device(char* name_fmt, ...)
+input_add_device(struct devclass* class, char* name_fmt, ...)
 {
     assert(input_devcat);
 
@@ -81,7 +81,7 @@ input_add_device(char* name_fmt, ...)
     va_start(args, name_fmt);
 
     struct device* dev =
-      device_add_vargs(input_devcat, idev, name_fmt, DEV_IFSEQ, args);
+      device_add_vargs(input_devcat, idev, name_fmt, DEV_IFSEQ, class, args);
 
     idev->dev_if = dev;
     dev->ops.read = __input_dev_read;
index 770cd50c078c93b73bb063243fb8dc51a3bbeff8..9f4d988f8c39606fd7f7e1160ecbff0bbfe433f5 100644 (file)
@@ -66,7 +66,7 @@ done:
 int
 iso9660_setup_dnode(struct v_dnode* dnode, struct v_inode* inode)
 {
-    if (!(inode->itype & VFS_IFDIR)) {
+    if ((inode->itype & F_FILE)) {
         vfs_assign_inode(dnode, inode);
         return 0;
     }
index 3b53b5c31dd49c2961c8e84a6919a72fa2c451a7..ac151b32d10759697d05b06bdadcf0afc4c1dd5b 100644 (file)
@@ -61,6 +61,7 @@ iso9660_fill_inode(struct v_inode* inode, struct iso_drecache* dir, int ino)
 
     inode->id = ino;
     inode->lb_addr = dir->extent_addr;
+    inode->lb_usage = ICEIL(dir->data_size, fu_len);
     inode->ops = &iso_inode_ops;
     inode->default_fops = &iso_file_ops;
 
index 3849add82eb53117c60ae75655614b53cf60b6fa..25150e5efe990aa73807f0f885c7bda9bc8d822c 100644 (file)
@@ -55,6 +55,7 @@ iso9660_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
     vsb->data = isovsb;
     vsb->ops.init_inode = iso9660_init_inode;
     vsb->ops.read_capacity = iso9660_rd_capacity;
+    vsb->blksize = ISO9660_BLKSZ;
 
     struct v_inode* rootino = vfs_i_alloc(vsb);
     struct iso_var_mdu* mdu = (struct iso_var_mdu*)vprim->root_record;
index 12e1d4b94c273acc87df26203f8ea96c2b611711..629a480f615d2d034c1a1aae2e0fe3c3abe5292e 100644 (file)
@@ -137,7 +137,7 @@ vfs_mount_at(const char* fs_name,
         return ENOTBLK;
     }
 
-    if (mnt_point->inode && !(mnt_point->inode->itype & VFS_IFDIR)) {
+    if (mnt_point->inode && (mnt_point->inode->itype & F_MFILE)) {
         return ENOTDIR;
     }
 
index 07edfc70675065cf5959fb0d36123ddf3f700446..d376c798b778660328f07951257c6acfd9c537cd 100644 (file)
@@ -119,7 +119,7 @@ __vfs_walk(struct v_dnode* start,
         current_level = dnode;
         current_inode = current_level->inode;
 
-        if ((current_inode->itype & VFS_IFSYMLINK) &&
+        if ((current_inode->itype & F_MSLNK) &&
             !(walk_options & VFS_WALK_NOFOLLOW)) {
             const char* link;
 
index 4f38c6ac90cc2d93c250c7171db3e708de5e8e19..a935fc44181b8c7ce9fd1fabbe3dafbcca1642a8 100644 (file)
@@ -23,10 +23,11 @@ probe_boot_medium()
         int errno =
           pos->ops.read(pos, (void*)volp, ISO9660_READ_OFF, ISO9660_BLKSZ);
         if (errno < 0) {
-            kprintf(KWARN "can not probe %x:%s (%d)\n",
-                    pos->dev_id,
-                    pos->name.value,
-                    errno);
+            kprintf(KINFO "failed %x:%d:%d, /dev/%s\n",
+                    pos->class->meta,
+                    pos->class->device,
+                    pos->class->variant,
+                    pos->name.value);
             pos = NULL;
             goto done;
         }
@@ -36,8 +37,10 @@ probe_boot_medium()
         }
 
         if (*(u32_t*)volp->sys_id == LUNAIX_ID) {
-            kprintf(KINFO "[%x:%s] %s\n",
-                    pos->dev_id,
+            kprintf(KINFO "%x:%d:%d, /dev/%s, %s\n",
+                    pos->class->meta,
+                    pos->class->device,
+                    pos->class->variant,
                     pos->name.value,
                     (char*)volp->vol_id);
             break;
index e2d1263607c2c8a79a596e7d2f40f00f0cb32938..e7ac05c7b93c991a5bceb39cb145aa040aa81255 100644 (file)
@@ -65,9 +65,7 @@ __ramfs_mknod(struct v_dnode* dnode, struct v_inode** nod_out, u32_t flags)
     rinode->flags = flags;
     inode->data = rinode;
 
-    if ((flags & RAMF_DIR)) {
-        inode->itype = VFS_IFDIR;
-    } else {
+    if (!(flags & RAMF_DIR)) {
         inode->itype = VFS_IFFILE;
     }
 
index 4d987ae8c25115f1653de0332c2e3e6e3a6d3634..c243fcc073ed6607bd0488c0451551ade9430832 100644 (file)
@@ -118,7 +118,7 @@ __twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode)
 {
     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
 
-    if (!(twi_node->itype & VFS_IFDIR)) {
+    if ((twi_node->itype & F_FILE)) {
         return ENOTDIR;
     }
 
@@ -180,7 +180,7 @@ __twifs_openfile(struct v_inode* inode, struct v_file* file)
 int
 twifs_rm_node(struct twifs_node* node)
 {
-    if ((node->itype & VFS_IFDIR) && !llist_empty(&node->children)) {
+    if (!(node->itype & F_FILE) && !llist_empty(&node->children)) {
         return ENOTEMPTY;
     }
     llist_delete(&node->siblings);
index 3197a5b05a4476e39066ec1c24bdf5f6b9d13cd2..cf376d23f132ad5e3dd56d368da195e54e317f2d 100644 (file)
@@ -40,7 +40,7 @@
                     we can do similar thing in Lunaix? A block device emulation
                     above the regular file when we mount it on.
  10. (device) device number (dev_t) allocation
-            [good idea] <class>:<subclass>:<uniq_id> composition
+            [good idea] <class>:<subclass>:<uniq_id> composition (CHECKED)
 */
 
 #include <klibc/string.h>
@@ -201,7 +201,7 @@ vfs_open(struct v_dnode* dnode, struct v_file** file)
     vfile->ref_count = ATOMIC_VAR_INIT(1);
     vfile->ops = inode->default_fops;
 
-    if ((inode->itype & VFS_IFFILE) && !inode->pg_cache) {
+    if ((inode->itype & F_MFILE) && !inode->pg_cache) {
         struct pcache* pcache = vzalloc(sizeof(struct pcache));
         pcache_init(pcache);
         pcache->master = inode;
@@ -515,6 +515,7 @@ vfs_i_free(struct v_inode* inode)
 
 #define FLOCATE_CREATE_EMPTY 1
 #define FLOCATE_CREATE_ONLY 2
+#define FLOCATE_NOFOLLOW 4
 
 int
 vfs_getfd(int fd, struct v_fd** fd_s)
@@ -533,14 +534,18 @@ __vfs_try_locate_file(const char* path,
 {
     char name_str[VFS_NAME_MAXLEN];
     struct hstr name = HSTR(name_str, 0);
-    int errno;
+    int errno, woption = 0;
+
+    if ((options & FLOCATE_NOFOLLOW)) {
+        woption |= VFS_WALK_NOFOLLOW;
+    }
 
     name_str[0] = 0;
-    if ((errno = vfs_walk_proc(path, fdir, &name, VFS_WALK_PARENT))) {
+    if ((errno = vfs_walk_proc(path, fdir, &name, woption | VFS_WALK_PARENT))) {
         return errno;
     }
 
-    errno = vfs_walk(*fdir, name.value, file, NULL, 0);
+    errno = vfs_walk(*fdir, name.value, file, NULL, woption);
 
     if (errno != ENOENT && (options & FLOCATE_CREATE_ONLY)) {
         return EEXIST;
@@ -575,12 +580,17 @@ __vfs_try_locate_file(const char* path,
 int
 vfs_do_open(const char* path, int options)
 {
-    int errno, fd;
+    int errno, fd, loptions = 0;
     struct v_dnode *dentry, *file;
     struct v_file* ofile = NULL;
 
-    errno = __vfs_try_locate_file(
-      path, &dentry, &file, (options & FO_CREATE) ? FLOCATE_CREATE_EMPTY : 0);
+    if ((options & FO_CREATE)) {
+        loptions |= FLOCATE_CREATE_EMPTY;
+    } else if ((options & FO_NOFOLLOW)) {
+        loptions |= FLOCATE_NOFOLLOW;
+    }
+
+    errno = __vfs_try_locate_file(path, &dentry, &file, loptions);
 
     if (!errno && !(errno = vfs_alloc_fdslot(&fd))) {
 
@@ -651,7 +661,7 @@ __DEFINE_LXSYSCALL2(int, sys_readdir, int, fd, struct lx_dirent*, dent)
 
     lock_inode(inode);
 
-    if (!(inode->itype & VFS_IFDIR)) {
+    if ((inode->itype & F_FILE)) {
         errno = ENOTDIR;
     } else {
         struct dir_context dctx =
@@ -689,7 +699,7 @@ __DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count)
     }
 
     struct v_file* file = fd_s->file;
-    if ((file->inode->itype & VFS_IFDIR)) {
+    if (!(file->inode->itype & F_FILE)) {
         errno = EISDIR;
         goto done;
     }
@@ -730,7 +740,7 @@ __DEFINE_LXSYSCALL3(int, write, int, fd, void*, buf, size_t, count)
         goto done;
     }
 
-    if ((file->inode->itype & VFS_IFDIR)) {
+    if (!(file->inode->itype & F_FILE)) {
         errno = EISDIR;
         goto done;
     }
@@ -852,13 +862,12 @@ vfs_readlink(struct v_dnode* dnode, char* buf, size_t size)
 int
 vfs_get_dtype(int itype)
 {
-    switch (itype) {
-        case VFS_IFDIR:
-            return DT_DIR;
-        case VFS_IFSYMLINK:
-            return DT_SYMLINK;
-        default:
-            return DT_PIPE;
+    if ((itype & VFS_IFSYMLINK)) {
+        return DT_SYMLINK;
+    } else if (!(itype & VFS_IFFILE)) {
+        return DT_DIR;
+    } else {
+        return DT_FILE;
     }
 }
 
@@ -913,6 +922,8 @@ __DEFINE_LXSYSCALL4(int,
         goto done;
     }
 
+    pathname = pathname ? pathname : "";
+
     struct v_dnode* dnode;
     if (!(errno = vfs_walk(
             fd_s->file->dnode, pathname, &dnode, NULL, VFS_WALK_NOFOLLOW))) {
@@ -974,7 +985,7 @@ __DEFINE_LXSYSCALL1(int, rmdir, const char*, pathname)
     lock_dnode(parent);
     lock_inode(parent->inode);
 
-    if ((dnode->inode->itype & VFS_IFDIR)) {
+    if (!(dnode->inode->itype & F_MFILE)) {
         errno = parent->inode->ops->rmdir(parent->inode, dnode);
         if (!errno) {
             vfs_dcache_remove(dnode);
@@ -1018,7 +1029,7 @@ __DEFINE_LXSYSCALL1(int, mkdir, const char*, path)
         errno = ENOTSUP;
     } else if (!parent->inode->ops->mkdir) {
         errno = ENOTSUP;
-    } else if (!(parent->inode->itype & VFS_IFDIR)) {
+    } else if ((parent->inode->itype & F_FILE)) {
         errno = ENOTDIR;
     } else if (!(errno = parent->inode->ops->mkdir(parent->inode, dir))) {
         vfs_dcache_add(parent, dir);
@@ -1052,7 +1063,7 @@ __vfs_do_unlink(struct v_dnode* dnode)
 
     if (inode->open_count) {
         errno = EBUSY;
-    } else if (!(inode->itype & VFS_IFDIR)) {
+    } else if ((inode->itype & F_MFILE)) {
         errno = inode->ops->unlink(inode);
         if (!errno) {
             vfs_d_free(dnode);
@@ -1255,7 +1266,7 @@ vfs_do_chdir(struct proc_info* proc, struct v_dnode* dnode)
 
     lock_dnode(dnode);
 
-    if (!(dnode->inode->itype & VFS_IFDIR)) {
+    if ((dnode->inode->itype & F_FILE)) {
         errno = ENOTDIR;
         goto done;
     }
@@ -1429,4 +1440,46 @@ __DEFINE_LXSYSCALL2(int, rename, const char*, oldpath, const char*, newpath)
 done:
     vfree((void*)name.value);
     return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL2(int, fstat, int, fd, struct file_stat*, stat)
+{
+    int errno = 0;
+    struct v_fd* fds;
+
+    if ((errno = vfs_getfd(fd, &fds))) {
+        goto done;
+    }
+
+    struct v_inode* vino = fds->file->inode;
+    struct device* fdev = vino->sb->dev;
+
+    *stat = (struct file_stat){ .st_ino = vino->id,
+                                .st_blocks = vino->lb_usage,
+                                .st_size = vino->fsize,
+                                .mode = vino->itype,
+                                .st_ioblksize = PG_SIZE,
+                                .st_blksize = vino->sb->blksize };
+
+    if (VFS_DEVFILE(vino->itype)) {
+        struct device* rdev = (struct device*)vino->data;
+        if (!rdev || rdev->magic != DEV_STRUCT_MAGIC) {
+            errno = EINVAL;
+            goto done;
+        }
+
+        stat->st_rdev = (dev_t){ .meta = rdev->class->meta,
+                                 .devident = device_id_from_class(rdev->class),
+                                 .dev_uid = rdev->dev_uid };
+    }
+
+    if (fdev) {
+        u32_t devident = device_id_from_class(fdev->class);
+        stat->st_dev = (dev_t){ .meta = fdev->class->meta,
+                                .devident = devident,
+                                .dev_uid = fdev->dev_uid };
+    }
+
+done:
+    return DO_STATUS(errno);
 }
\ No newline at end of file
index 2aa1ed9f83f8c4253712c47d9e9dca5320485c9a..36ed5ee28d52aef1f8a6f84e627a278bbb3a2575 100644 (file)
@@ -129,7 +129,7 @@ taskfs_dirlookup(struct v_inode* this, struct v_dnode* dnode)
         return ENOENT;
     }
 
-    return taskfs_mknod(dnode, pid, 0, VFS_IFDIR);
+    return taskfs_mknod(dnode, pid, 0, F_FILE);
 }
 
 static struct v_file_ops taskfs_file_ops = { .close = default_file_close,
index 46f4dd253ce00fbf9499e6e07f6947b5ca5008e6..17dddfd1113f3e95a3e5ecb1eb0b5d1efc107572 100644 (file)
@@ -343,7 +343,8 @@ console_start_flushing()
 static int
 lxconsole_spawn_ttydev(struct device_def* devdef)
 {
-    struct device* tty_dev = device_addseq(NULL, &lx_console, "tty");
+    struct device* tty_dev =
+      device_addseq(NULL, &devdef->class, &lx_console, "tty");
     tty_dev->ops.write = __tty_write;
     tty_dev->ops.write_page = __tty_write_pg;
     tty_dev->ops.read = __tty_read;
index 5f28766c2663455c6dd65341dfaaf70a68f1c71c..c345ab75a055d55879de5aa4859ecd758fe3942f 100644 (file)
@@ -2,3 +2,5 @@
 #include <fcntl.h>
 
 __LXSYSCALL2(int, open, const char*, path, int, options)
+
+__LXSYSCALL2(int, fstat, int, fd, struct file_stat*, stat)
index b013d70d9f0c1a602ef671024d997cd0559ae6b7..7e89dc265662ae8fe2ddd21194e4032bcce44a48 100644 (file)
@@ -7,4 +7,7 @@
 extern int
 open(const char* path, int flags);
 
+extern int
+fstat(int fd, struct file_stat* stat);
+
 #endif /* __LUNAIX_FCNTL_H */
index d0374d6d97dbd8c6bdb9eb02d96796ceb3cac4bc..e2a98d021d39aa23b9dc612e806599fc986a0fb9 100644 (file)
@@ -34,6 +34,7 @@ app-list += signal_demo
 app-list += sh
 app-list += cat
 app-list += testp
+app-list += stat
 
 mkapp-list := $(addprefix app-, $(app-list))
 
diff --git a/lunaix-os/usr/stat/main.c b/lunaix-os/usr/stat/main.c
new file mode 100644 (file)
index 0000000..541378f
--- /dev/null
@@ -0,0 +1,73 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static char buf[256];
+
+int
+main(int argc, char* argv[])
+{
+    if (argc <= 1) {
+        printf("missing operand\n");
+        return 1;
+    }
+
+    int fd = open(argv[1], FO_RDONLY | FO_NOFOLLOW);
+    if (fd < 0) {
+        printf("fail to open %d\n", fd);
+        return 1;
+    }
+
+    struct file_stat stat;
+    if (fstat(fd, &stat) < 0) {
+        printf("fail to get stat %d\n", errno);
+        return 1;
+    }
+
+    printf("File: %s ", argv[1]);
+
+    char* ftype = "directory";
+    int mode = stat.mode;
+    if ((mode & F_MDEV)) {
+        if (!((mode & F_SEQDEV) ^ F_SEQDEV)) {
+            ftype = "sequential device";
+        } else if (!((mode & F_VOLDEV) ^ F_VOLDEV)) {
+            ftype = "volumetric device";
+        } else {
+            ftype = "regular device";
+        }
+    } else if ((mode & F_MSLNK)) {
+        if (readlinkat(fd, NULL, buf, 256) < 0) {
+            printf("fail to readlink %d\n", errno);
+        } else {
+            printf("-> %s", buf);
+        }
+        ftype = "symbolic link";
+    } else if ((mode & F_MFILE)) {
+        ftype = "regular file";
+    }
+
+    printf("\nType: %s\n", ftype);
+    printf("Size: %d;  Blocks: %d;  FS Block: %d;  IO Blocks: %d\n",
+           stat.st_size,
+           stat.st_blocks,
+           stat.st_blksize,
+           stat.st_ioblksize);
+    printf("Inode: %d;  ", stat.st_ino);
+
+    dev_t* dev;
+    if (!(stat.mode & F_MDEV)) {
+        dev = &stat.st_dev;
+    } else {
+        dev = &stat.st_rdev;
+    }
+
+    printf("Device: %xh:%d:%d;\n",
+           dev->meta,
+           dev->devident >> 16,
+           dev->devident & 0xffff);
+
+    close(fd);
+    return 0;
+}
\ No newline at end of file
diff --git a/lunaix-os/usr/stat/makefile b/lunaix-os/usr/stat/makefile
new file mode 100644 (file)
index 0000000..33802bd
--- /dev/null
@@ -0,0 +1,21 @@
+define src_files
+       main.c
+endef
+
+obj_files := $(addsuffix .o,$(src_files))
+include_opt := $(addprefix -I,$(INCLUDES))
+
+out := $(BUILD_DIR)/bin
+
+%.c.o: %.c
+       $(call status_,CC,$<)
+       @$(CC) $(CFLAGS) $(include_opt) -c $< -o $@
+
+$(out)/$(BUILD_NAME): $(obj_files)
+       $(call status_,LD,$(@F))
+       @$(CC) -T $(LD_SCRIPT) -o $@ $< $(LIBC) $(LDFLAGS)
+
+all: $(out)/$(BUILD_NAME)
+
+clean:
+       @rm -f $(obj_files)
\ No newline at end of file