computing-offload/qtfs/qtinfo/qtinfo.c
Yikun Jiang a68570b5d9 Add computing offloading code
1. Add computing offloading code
2. Add script.md
3. Add virsh_demo.xml

Change-Id: Id9ef883e2f0eb727eb5448b9d1c47767f46b1021
Signed-off-by: Yikun Jiang <yikunkero@gmail.com>
2023-10-23 19:29:57 +08:00

628 lines
19 KiB
C

/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
* qtfs licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
* PURPOSE.
* See the Mulan PSL v2 for more details.
* Author: Liqiang
* Create: 2023-03-20
* Description:
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <string.h>
#include <stddef.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "qtinfo.h"
#include "comm.h"
#include "ipc/uds_module.h"
#ifdef client
#define QTFS_DEV_NAME "/dev/qtfs_client"
#else
#define QTFS_DEV_NAME "/dev/qtfs_server"
#endif
#define qtinfo_out(info, ...) \
do {\
printf(info"\n", ##__VA_ARGS__);\
} while (0);
#define qtinfo_out2(info, ...) \
do {\
printf(info, ##__VA_ARGS__);\
} while (0);
#define qtinfo_err(info, ...) \
do {\
printf("ERROR: "info"\n", ##__VA_ARGS__);\
} while (0);
#define RECV_BUFF_LEN 256
struct qtinfo_type_str qtinfo_all_events[] = {
{QTFS_REQ_NULL, "null"},
{QTFS_REQ_MOUNT, "mount"},
{QTFS_REQ_OPEN, "open"},
{QTFS_REQ_CLOSE, "close"},
{QTFS_REQ_READ, "read"},
{QTFS_REQ_READITER, "readiter"}, //5
{QTFS_REQ_WRITE, "write"},
{QTFS_REQ_LOOKUP, "lookup"},
{QTFS_REQ_READDIR, "readdir"},
{QTFS_REQ_MKDIR, "mkdir"},
{QTFS_REQ_RMDIR, "rmdir"}, //10
{QTFS_REQ_GETATTR, "getattr"},
{QTFS_REQ_SETATTR, "setattr"},
{QTFS_REQ_ICREATE, "icreate"},
{QTFS_REQ_MKNOD, "mknod"},
{QTFS_REQ_UNLINK, "unlink"}, //15
{QTFS_REQ_SYMLINK, "symlink"},
{QTFS_REQ_LINK, "link"},
{QTFS_REQ_GETLINK, "getlink"},
{QTFS_REQ_READLINK, "readlink"},
{QTFS_REQ_RENAME, "rename"}, //20
{QTFS_REQ_XATTRLIST, "xattrlist"},
{QTFS_REQ_XATTRGET, "xattrget"},
{QTFS_REQ_XATTRSET, "xattrset"},
{QTFS_REQ_SYSMOUNT, "sysmount"},
{QTFS_REQ_SYSUMOUNT, "sysumount"}, //25
{QTFS_REQ_FIFOPOLL, "fifo_poll"},
{QTFS_REQ_STATFS, "statfs"},
{QTFS_REQ_IOCTL, "ioctl"},
{QTFS_REQ_EPOLL_CTL, "epollctl"},
{QTFS_REQ_EPOLL_EVENT, "epollevent"}, // 30
{QTFS_REQ_LLSEEK, "llseek"},
{QTFS_SC_KILL, "sc_kill"},
{QTFS_SC_SCHED_GETAFFINITY, "sc_getaffi"},
{QTFS_SC_SCHED_SETAFFINITY, "sc_setaffi"},
};
static void qtinfo_events_count(struct qtinfo *evts)
{
unsigned long total = 0;
int i;
#ifdef client
qtinfo_out("++++++++++++++++++++++++++send events count++++++++++++++++++++++++++");
for (i = 0; i < (sizeof(qtinfo_all_events) / sizeof(struct qtinfo_type_str)) - 3; i += 3) {
qtinfo_out("%-10s: %-10lu %-10s: %-10lu %-10s: %-10lu",
qtinfo_all_events[i].str, evts->c.o_events[i],
qtinfo_all_events[i+1].str, evts->c.o_events[i+1],
qtinfo_all_events[i+2].str, evts->c.o_events[i+2]);
total += evts->c.o_events[i] + evts->c.o_events[i+1] + evts->c.o_events[i+2];
}
for (; i < sizeof(qtinfo_all_events)/sizeof(struct qtinfo_type_str); i++) {
qtinfo_out2("%-10s: %-10lu ", qtinfo_all_events[i].str, evts->c.o_events[i]);
total += evts->c.o_events[i];
}
qtinfo_out2("\n");
qtinfo_out("Send events total: %lu", total);
total = 0;
qtinfo_out("++++++++++++++++++++++++++recv events count++++++++++++++++++++++++++");
for (i = 0; i < (sizeof(qtinfo_all_events)/sizeof(struct qtinfo_type_str)) - 3; i+=3) {
qtinfo_out("%-10s: %-10lu %-10s: %-10lu %-10s: %-10lu",
qtinfo_all_events[i].str, evts->c.i_events[i],
qtinfo_all_events[i+1].str, evts->c.i_events[i+1],
qtinfo_all_events[i+2].str, evts->c.i_events[i+2]);
total += evts->c.i_events[i] + evts->c.i_events[i+1] + evts->c.i_events[i+2];
}
for(; i < sizeof(qtinfo_all_events)/sizeof(struct qtinfo_type_str); i++) {
qtinfo_out2("%-10s: %-10lu ", qtinfo_all_events[i].str, evts->c.i_events[i]);
total += evts->c.i_events[i];
}
qtinfo_out2("\n");
qtinfo_out("Recv events total: %lu", total);
total = 0;
qtinfo_out("++++++++++++++++++++++++++send error count+++++++++++++++++++++++++++");
for(i = 0; i < (sizeof(qtinfo_all_events)/sizeof(struct qtinfo_type_str)) - 3; i+=3) {
qtinfo_out("%-10s: %-10lu %-10s: %-10lu %-10s: %-10lu",
qtinfo_all_events[i].str, evts->c.send_err[i],
qtinfo_all_events[i+1].str, evts->c.send_err[i+1],
qtinfo_all_events[i+2].str, evts->c.send_err[i+2]);
total += evts->c.send_err[i] + evts->c.send_err[i+1] + evts->c.send_err[i+2];
}
for(; i < sizeof(qtinfo_all_events)/sizeof(struct qtinfo_type_str); i++) {
qtinfo_out2("%-10s: %-10lu ", qtinfo_all_events[i].str, evts->c.send_err[i]);
total += evts->c.send_err[i];
}
qtinfo_out2("\n");
qtinfo_out("Send events error total: %lu", total);
total = 0;
qtinfo_out("++++++++++++++++++++++++++recv error count+++++++++++++++++++++++++++");
for(i = 0; i < (sizeof(qtinfo_all_events)/sizeof(struct qtinfo_type_str)) - 3; i+=3) {
qtinfo_out("%-10s: %-10lu %-10s: %-10lu %-10s: %-10lu",
qtinfo_all_events[i].str, evts->c.recv_err[i],
qtinfo_all_events[i+1].str, evts->c.recv_err[i+1],
qtinfo_all_events[i+2].str, evts->c.recv_err[i+2]);
total += evts->c.recv_err[i] + evts->c.recv_err[i+1] + evts->c.recv_err[i+2];
}
for(; i < sizeof(qtinfo_all_events)/sizeof(struct qtinfo_type_str); i++) {
qtinfo_out2("%-10s: %-10lu ", qtinfo_all_events[i].str, evts->c.recv_err[i]);
total += evts->c.recv_err[i];
}
qtinfo_out2("\n");
qtinfo_out("Recv events error total: %lu", total);
total = 0;
#endif
#ifdef server
qtinfo_out("++++++++++++++++++++++++++send events count++++++++++++++++++++++++++");
for (i = 0; i < (sizeof(qtinfo_all_events)/sizeof(struct qtinfo_type_str)) - 3; i+=3) {
qtinfo_out("%-10s: %-10lu %-10s: %-10lu %-10s: %-10lu",
qtinfo_all_events[i].str, evts->s.o_events[i],
qtinfo_all_events[i+1].str, evts->s.o_events[i+1],
qtinfo_all_events[i+2].str, evts->s.o_events[i+2]);
total += evts->s.o_events[i] + evts->s.o_events[i+1] + evts->s.o_events[i+2];
}
for (; i < sizeof(qtinfo_all_events)/sizeof(struct qtinfo_type_str); i++) {
qtinfo_out2("%-10s: %-10lu ", qtinfo_all_events[i].str, evts->s.o_events[i]);
total += evts->s.o_events[i];
}
qtinfo_out2("\n");
qtinfo_out("Send events total: %lu", total);
total = 0;
qtinfo_out("++++++++++++++++++++++++++recv events count++++++++++++++++++++++++++");
for (i = 0; i < (sizeof(qtinfo_all_events)/sizeof(struct qtinfo_type_str)) - 3; i+=3) {
qtinfo_out("%-10s: %-10lu %-10s: %-10lu %-10s: %-10lu",
qtinfo_all_events[i].str, evts->s.i_events[i],
qtinfo_all_events[i+1].str, evts->s.i_events[i+1],
qtinfo_all_events[i+2].str, evts->s.i_events[i+2]);
total += evts->s.i_events[i] + evts->s.i_events[i+1] + evts->s.i_events[i+2];
}
for(; i < sizeof(qtinfo_all_events)/sizeof(struct qtinfo_type_str); i++) {
qtinfo_out2("%-10s: %-10lu ", qtinfo_all_events[i].str, evts->s.i_events[i]);
total += evts->s.i_events[i];
}
qtinfo_out2("\n");
qtinfo_out("Recv events total: %lu", total);
qtinfo_out("++++++++++++++++++++++++++req check err+++++++++++++++++++++++++++++++");
for (i = 0; i < (sizeof(qtinfo_all_events)/sizeof(struct qtinfo_type_str)) - 3; i+=3) {
qtinfo_out("%-10s: %-10lu %-10s: %-10lu %-10s: %-10lu",
qtinfo_all_events[i].str, evts->s.req_check[i],
qtinfo_all_events[i+1].str, evts->s.req_check[i+1],
qtinfo_all_events[i+2].str, evts->s.req_check[i+2]);
}
for(; i < sizeof(qtinfo_all_events)/sizeof(struct qtinfo_type_str); i++) {
qtinfo_out2("%-10s: %-10lu ", qtinfo_all_events[i].str, evts->s.req_check[i]);
}
qtinfo_out("\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
#endif
}
static void qtinfo_misc_count(struct qtinfo *info)
{
qtinfo_out("++++++++++++++++++++++++++++++Misc count+++++++++++++++++++++++++++++");
#ifdef client
qtinfo_out("Active connects: %-8lu Seq err count : %-8lu Restartsys : %-8lu",
info->c.cnts[QTINF_ACTIV_CONN], info->c.cnts[QTINF_SEQ_ERR], info->c.cnts[QTINF_RESTART_SYS]);
qtinfo_out("Type mismatch : %-8lu Epoll add fds : %-8lu Epoll del fds: %-8lu",
info->c.cnts[QTINF_TYPE_MISMATCH], info->c.cnts[QTINF_EPOLL_ADDFDS], info->c.cnts[QTINF_EPOLL_DELFDS]);
qtinfo_out("Epoll err fds : %-8lu",
info->c.cnts[QTINF_EPOLL_FDERR]);
#else
qtinfo_out("Active connects: %-8lu Epoll add fds: %-8lu Epoll del fds: %-8lu",
info->s.cnts[QTINF_ACTIV_CONN], info->s.cnts[QTINF_EPOLL_ADDFDS], info->s.cnts[QTINF_EPOLL_DELFDS]);
#endif
}
static void qtinfo_thread_state(struct qtinfo *info)
{
int i = 0;
qtinfo_out("+++++++++++++++++++++++++++Connection state++++++++++++++++++++++++++");
for (i = 0; i < QTFS_MAX_THREADS - 3; i+=3) {
qtinfo_out("Conn%-2d: %-10s Conn%-2d: %-10s Conn%-2d: %-10s",
i+1, QTINFO_STATE(info->thread_state[i]),
i+2, QTINFO_STATE(info->thread_state[i+1]),
i+3, QTINFO_STATE(info->thread_state[i+2]));
}
for (; i < QTFS_MAX_THREADS; i++) {
qtinfo_out2("Conn%-2d: %-10s ", i+1, QTINFO_STATE(info->thread_state[i]));
}
qtinfo_out("Epoll state: %-10s", QTINFO_STATE(info->epoll_state));
return;
}
static void qtinfo_pvar_count(struct qtinfo *info)
{
int i = 0;
qtinfo_out("+++++++++++++++++++++++++++++Param count+++++++++++++++++++++++++++++");
qtinfo_out("Parameter valid count: %-2d Parameter busy count: %-2d",
info->pvar_vld, info->pvar_busy);
for (i = 0; i < QTFS_MAX_THREADS; i++) {
qtinfo_out("Conn%-2d holder: [%-20s]", i+1, (info->who_using[i][0] == '\0') ? "No one" : info->who_using[i]);
}
}
static void qtinfo_log_level(struct qtinfo *info)
{
qtinfo_out("Log level: %d", info->log_level);
}
static int qtinfo_opt_a(int fd)
{
struct qtinfo *diag = (struct qtinfo *)malloc(sizeof(struct qtinfo));
if (diag == NULL) {
qtinfo_err("malloc failed.");
return -1;
}
memset(diag, 0, sizeof(struct qtinfo));
int ret = ioctl(fd, QTFS_IOCTL_ALLINFO, diag);
if (ret != QTOK) {
qtinfo_err("ioctl failed, ret:%d.", ret);
free(diag);
return -1;
}
qtinfo_events_count(diag);
qtinfo_misc_count(diag);
qtinfo_log_level(diag);
qtinfo_thread_state(diag);
qtinfo_pvar_count(diag);
free(diag);
return 0;
}
static int qtinfo_opt_c(int fd)
{
int ret = ioctl(fd, QTFS_IOCTL_CLEARALL, NULL);
return ret;
}
static int qtinfo_opt_l(int fd, char *level)
{
int ret;
ret = ioctl(fd, QTFS_IOCTL_LOGLEVEL, level);
if (ret != QTOK) {
qtinfo_err("Set qtfs log level:%s failed.", level);
return ret;
}
qtinfo_out("Set qtfs log level to %s success.", level);
return ret;
}
static int qtinfo_opt_t(int fd)
{
int i;
struct qtinfo *diag = (struct qtinfo *)malloc(sizeof(struct qtinfo));
if (diag == NULL) {
qtinfo_err("malloc failed.");
return -1;
}
int ret = ioctl(fd, QTFS_IOCTL_ALLINFO, (unsigned long)diag);
qtinfo_out("++++++++++++++++++++++++++qtreq_xxx size++++++++++++++++++++++++++");
for (i = 0; i < (sizeof(qtinfo_all_events)/sizeof(struct qtinfo_type_str)) - 3; i+=3) {
qtinfo_out("%-10s req: %-10lu %-10s req: %-10lu %-10s req: %-10lu",
qtinfo_all_events[i].str, diag->req_size[i],
qtinfo_all_events[i+1].str, diag->req_size[i+1],
qtinfo_all_events[i+2].str, diag->req_size[i+2]);
}
for (; i < sizeof(qtinfo_all_events)/sizeof(struct qtinfo_type_str); i++) {
qtinfo_out2("%-10s req: %-10lu ", qtinfo_all_events[i].str, diag->req_size[i]);
}
qtinfo_out2("\n");
qtinfo_out("++++++++++++++++++++++++++qtrsp_xxx size++++++++++++++++++++++++++");
for (i = 0; i < (sizeof(qtinfo_all_events)/sizeof(struct qtinfo_type_str)) - 3; i+=3) {
qtinfo_out("%-10s rsp: %-10lu %-10s rsp: %-10lu %-10s rsp: %-10lu",
qtinfo_all_events[i].str, diag->rsp_size[i],
qtinfo_all_events[i+1].str, diag->rsp_size[i+1],
qtinfo_all_events[i+2].str, diag->rsp_size[i+2]);
}
for (; i < sizeof(qtinfo_all_events)/sizeof(struct qtinfo_type_str); i++) {
qtinfo_out2("%-10s rsp: %-10lu ", qtinfo_all_events[i].str, diag->rsp_size[i]);
}
qtinfo_out2("\n");
free(diag);
return ret;
}
static int qtinfo_opt_p(int fd, char *support)
{
int ret;
int sup = atoi(support);
ret = ioctl(fd, QTFS_IOCTL_EPOLL_SUPPORT, sup);
if (ret != QTOK) {
qtinfo_out("Set qtfs epoll support to:%s failed.", (sup == 1) ? "any file" : "fifo file");
return ret;
}
qtinfo_out("Set qtfs epoll support to %s success.", (sup == 1) ? "any file" : "fifo file");
return ret;
}
#define PATH_MAX 4096
static int qtinfo_opt_u()
{
int ret = -1;
int len;
struct sockaddr_un svr;
char buf[RECV_BUFF_LEN];
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0) {
qtinfo_err("Create socket fd failed.");
return -1;
}
memset(&svr, 0, sizeof(svr));
svr.sun_family = AF_UNIX;
strcpy(svr.sun_path, UDS_DIAG_ADDR);
len = offsetof(struct sockaddr_un, sun_path) + strlen(svr.sun_path);
if (connect(sockfd, (struct sockaddr *)&svr, len) < 0) {
qtinfo_err("connect to %s failed.", UDS_DIAG_ADDR);
close(sockfd);
return -1;
}
while (1) {
memset(buf, 0, RECV_BUFF_LEN);
ret = recv(sockfd, buf, RECV_BUFF_LEN, 0);
if (ret <= 0)
break;
qtinfo_out2("%s", buf);
}
qtinfo_out2("\n");
close(sockfd);
return ret;
}
static int qtinfo_opt_s()
{
int ret = -1;
int len;
struct sockaddr_un svr;
char buf[RECV_BUFF_LEN];
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0) {
qtinfo_err("Create socket fd failed.");
return -1;
}
memset(&svr, 0, sizeof(svr));
svr.sun_family = AF_UNIX;
strcpy(svr.sun_path, UDS_LOGLEVEL_UPD);
len = offsetof(struct sockaddr_un, sun_path) + strlen(svr.sun_path);
if (connect(sockfd, (struct sockaddr *)&svr, len) < 0) {
qtinfo_err("connect to %s failed.", UDS_LOGLEVEL_UPD);
close(sockfd);
return -1;
}
while (1) {
memset(buf, 0, RECV_BUFF_LEN);
ret = recv(sockfd, buf, RECV_BUFF_LEN, 0);
if (ret <= 0)
break;
qtinfo_out2("%s", buf);
}
qtinfo_out2("\n");
close(sockfd);
return ret;
}
char wl_type_str[QTFS_WHITELIST_MAX][16] = {
#ifdef server
"Open",
"Write",
"Read",
"Readdir",
"Mkdir",
"Rmdir",
"Create",
"Unlink",
"Rename",
"Setattr",
"Setxattr",
"Mount",
"Kill",
#endif
"Udsconnect"
};
int qtinfo_match_cap(char *cap)
{
if (cap == NULL)
return -1;
for (int type = 0; type < QTFS_WHITELIST_MAX; type++) {
if (strcasecmp(wl_type_str[type], cap) == 0)
return type;
}
return -1;
}
#define PATH_MAX 4096
static int qtinfo_opt_x(int fd, char *path, char *cap)
{
int ret = -1;
int index = 0;
struct qtfs_wl_item head;
ret = qtinfo_match_cap(cap);
if (ret < 0) {
qtinfo_err("White list add type:%s unknown.", cap);
return -1;
}
head.type = ret;
head.len = strlen(path);
if (head.len >= PATH_MAX || head.len == 0) {
qtinfo_err("White list add len:%u invalid", head.len);
return -1;
}
head.path = path;
ret = ioctl(fd, QTFS_IOCTL_WL_ADD, &head);
if (ret != QTOK) {
qtinfo_err("ioctl add white list failed");
ret = -1;
} else {
qtinfo_out("successed to add white list item:%s successed", path);
ret = 0;
}
return ret;
}
static int qtinfo_opt_y(int fd, char *index, char *cap)
{
struct qtfs_wl_item head;
int ret = qtinfo_match_cap(cap);
if (ret < 0) {
qtinfo_err("White list delete type:%s unknown.", cap);
return -1;
}
head.index = atoi(index);
head.type = ret;
head.path = NULL;
head.len = 0;
ret = ioctl(fd, QTFS_IOCTL_WL_DEL, &head);
if (ret != QTOK) {
qtinfo_err("failed to delete white list index:%d", head.index);
return -1;
} else {
qtinfo_out("successed to delete white list index:%d", head.index);
}
return 0;
}
static void qtinfo_opt_z_bytype(int fd, unsigned int type)
{
int ret;
char query[PATH_MAX];
struct qtfs_wl_item head;
head.path = query;
head.type = type;
qtinfo_out("Get qtfs <%s> white list:", wl_type_str[type]);
for (unsigned int index = 0; index < QTFS_WL_MAX_NUM; index++) {
memset(head.path, 0, PATH_MAX);
head.index = index;
ret = ioctl(fd, QTFS_IOCTL_WL_GET, &head);
if (ret != QTOK)
break;
qtinfo_out(" [index:%u][path:%s]", index, head.path);
}
return;
}
static int qtinfo_opt_z(int fd, char *cap)
{
int ret = -1;
int index = 0;
ret = qtinfo_match_cap(cap);
if (ret >= 0 && ret < QTFS_WHITELIST_MAX) {
qtinfo_opt_z_bytype(fd, ret);
return 0;
}
for (int i = 0; i < QTFS_WHITELIST_MAX; i++) {
qtinfo_opt_z_bytype(fd, i);
}
return 0;
}
static void qtinfo_help(char *exec)
{
qtinfo_out("Usage: %s [OPTION].", exec);
qtinfo_out("Display qtfs client/server diagnostic information.");
#ifndef QTINFO_RELEASE
qtinfo_out(" -a, All diag info.");
qtinfo_out(" -c, Clear all diag info.");
qtinfo_out(" -l, Set log level(valid param: \"NONE\", \"ERROR\", \"WARN\", \"INFO\", \"DEBUG\").");
qtinfo_out(" -t, For test informations.");
qtinfo_out(" -p, Epoll support file mode(1: any files; 0: only fifo).");
qtinfo_out(" -u, Display unix socket proxy diagnostic info");
qtinfo_out(" -s, Set unix socket proxy log level(Increase by 1 each time)");
#endif
#ifdef server
qtinfo_out(" -w, White list type(open/write/read/readdir/mkdir/rmdir/create/\n"
" unlink/rename/setattr/setxattr/mount/kill/udsconnect)");
#endif
#ifdef client
qtinfo_out(" -w, White list type(udsconnect)");
#endif
qtinfo_out(" -x, Add a qtfs white list path(example: -x /home/, must use with -w)");
qtinfo_out(" -y, Delete a qtfs white list with index(example: -y 1, must use with -w)");
qtinfo_out(" -z, Get all qtfs white list(just use -z, or with white list type)");
}
int main(int argc, char *argv[])
{
#define MAX_CAP_LEN 16
int ret = -1;
int ch;
char wl_cap[MAX_CAP_LEN] = {0};
if ((argc == 1) || (argc == 2 && strcmp(argv[1], "--help") == 0)) {
qtinfo_help(argv[0]);
return -1;
}
int fd = open(QTFS_DEV_NAME, O_RDONLY|O_NONBLOCK);
if (fd < 0) {
qtinfo_err("open file %s failed.", QTFS_DEV_NAME);
#ifdef QTINFO_RELEASE
return -1;
#endif
}
#ifndef QTINFO_RELEASE
while ((ch = getopt(argc, argv, "acl:tp:usw:x:y:z::")) != -1) {
#else
while ((ch = getopt(argc, argv, "w:x:y:z::")) != -1) {
#endif
switch (ch) {
#ifndef QTINFO_RELEASE
case 'a':
ret = qtinfo_opt_a(fd);
break;
case 'c':
ret = qtinfo_opt_c(fd);
break;
case 'l':
ret = qtinfo_opt_l(fd, optarg);
break;
case 't':
ret = qtinfo_opt_t(fd);
break;
case 'p':
ret = qtinfo_opt_p(fd, optarg);
break;
case 'u':
ret = qtinfo_opt_u();
break;
case 's':
ret = qtinfo_opt_s();
break;
#endif
case 'w':
strncpy(wl_cap, optarg, MAX_CAP_LEN - 1);
break;
case 'x':
ret = qtinfo_opt_x(fd, optarg, wl_cap);
break;
case 'y':
ret = qtinfo_opt_y(fd, optarg, wl_cap);
break;
case 'z':
ret = qtinfo_opt_z(fd, optarg);
break;
default:
ret = 0;
qtinfo_help(argv[0]);
break;
}
}
close(fd);
return ret;
}