分类 Ubuntu 下的文章

“Ubuntu是以桌面应用为主的Linux发行版,基于Debian。Ubuntu有三个正式版本,包括桌面版、服务器版及用于物联网设备和机器人的Core版。从17.10版本开始,Ubuntu以GNOME为默认桌面环境。 Ubuntu是著名的Linux发行版之一,也是目前最多用户的Linux版本。 ”

在用户空间访问 I/O 端口
以上函数主要提供给设备驱动使用,但它们也可在用户空间使用,至少在 PC上可以。 GNU C 库在 中定义了它们。如果在用户空间代码中使用必须满足以下条件:

(1)程序必须使用 -O 选项编译来强制扩展内联函数。

(2)必须用ioperm 和 iopl 系统调用(#include ) 来获得对端口 I/O 操作的权限。ioperm 为获取单独端口操作权限,而 iopl 为整个 I/O 空间的操作权限。 (x86 特有的)

(3)程序以 root 来调用 ioperm 和 iopl,或是其父进程必须以 root 获得端口操作权限。(x86 特有的)

若平台没有 ioperm 和 iopl 系统调用,用户空间可以仍然通过使用 /dev/prot 设备文件访问 I/O 端口。注意:这个文件的定义是体系相关的,并且I/O 端口必须先被注册。

ioperm和iopl介绍。

1.ioperm
 
功能描述:

为调用进程设置I/O端口访问权能。ioperm的使用需要具有超级用户的权限,只有低端的[0-0x3ff] I/O端口可被设置,要想指定更多端口的权能,可使用iopl函数。这一调用只可用于i386平台。 

用法:

int ioperm(unsigned long from, unsigned long num, int turn_on);      

参数:

from:起始端口地址。

num:需要修改权能的端口数。

turn_on:端口的新权能位。1为开启,0为关闭。

返回说明:

成功执行时,返回0。失败返回-1,errno被设为以下的某个值

EINVAL:参数无效
EIO:这一调用不被支持
EPERM:调用进程权能不足。 

  1. iopl

功能描述:该调用用于修改当前进程的操作端口的权限。可以用于所有65536个端口的权限。因此,ioperm相当于该调用的子集。和ioperm一样,这一调用仅适用于i386平台。 

用法:
   int iopl(int level);

参数:

level: 端口的权限级别。为3时可以读写端口。默认权能级别为0,用户空间不可读写。

返回说明:成功执行时,返回0。失败返回-1,errno被设为以下的某个值

EINVAL:level值大于3
ENOSYS:未实现该调用
EPERM:调用进程权能不足。 

二、程序示例

  1. ioperm.c

操作低于0x3FF的端口

该程序首先设置0x3FF端口的读写权限,然后读出原先的值,然后将原值的LSB翻转并写回端口,并在此读取端口值。

/*Description:This function is used to test ioperm()*/

#define PORT_ADDR 0x3FF 

int main(void)
{
      int ret;
      char port_val;

      /*set r/w permission of port_addr on, only one port*/
      ret = ioperm(PORT_ADDR, 1, 1);
      if(ret < 0){
           perror("ioperm set error");
           return 0;
      }
      port_val = inb(PORT_ADDR);
      printf("Original value of port 0x%x is : %.2x\n", PORT_ADDR, port_val);    
      /*reverse the least significant bit */
      outb(port_val^0x01, PORT_ADDR);
      port_val = inb(PORT_ADDR);
      printf("Current value of port 0x%x is : %.2x\n", PORT_ADDR, port_val);    
      /*set r/w permission of PORT_ADDR off, only one port*/
      ret = ioperm(PORT_ADDR, 1, 0);
      if(ret < 0){
           perror("ioperm set error");
           return 0;
      }
      return 0;
} 

程序执行的结果是:

[root@localhost misc-progs]# ./a.out
Original value of port 0x3ff is : 00
Current value of port 0x3ff is : 01
[root@localhost misc-progs]# ./a.out
Original value of port 0x3ff is : 01
Current value of port 0x3ff is : 00

该程序执行几次,将进行几次的LSB翻转。

这里有一个问题值得注意:在2.4(RH9)的内核上,当端口值大于0x3FF时,执行该程序则会报错:ioperm set error: Invalid argument。即IO端口的值设置有问题,超出了限制。但是在2.6内核下并没有报错,而且执行结果也符合程序既定的结果。但是man ioperm中仍然说明了0x3FF的限制。暂且存疑。

  1. iopl.c

该程序可以操作所有65536个端口。

该程序首先设置0x3FF端口的读写权限,然后读出原先的值,然后将原值的LSB翻转并写回端口,并在此读取端口值。

代码如下:

/*Description:This function is used to test iopl()*/

#define PORT_ADDR 0x3FF 

int main(void)
{
      int ret;
      char port_val; 

      /*set r/w permission of all 65536 ports*/
      ret = iopl(3);
      if(ret < 0){
           perror("iopl set error");
           return 0;
      }

      port_val = inb(PORT_ADDR);
      printf("Original value of port 0x%x is : %.2x\n", PORT_ADDR, port_val);    

      /*reverse the least significant bit */
      outb(port_val^0x01, PORT_ADDR);
      port_val = inb(PORT_ADDR);
      printf("Current value of port 0x%x is : %.2x\n", PORT_ADDR, port_val);  
      /*set r/w permission of  all 65536 ports*/
      ret = iopl(0);

      if(ret < 0){
           perror("iopl set error");
           return 0;
      }
      return 0;
}

程序执行结果:

[root@linux misc-progs]# ./a.out
Original value of port 0x3ff is : 01
Current value of port 0x3ff is : 00
[root@linux misc-progs]# ./a.out
Original value of port 0x3ff is : 00
Current value of port 0x3ff is : 01

该程序执行几次,将进行几次的LSB翻转。
Referenced from:http://blog.chinaunix.net/uid-10167808-id-25953.html

linux O_WRONLY 头文件 #include "fcntl.h"

#include <bits/stdc++.h>
#include "unistd.h"
#include "fcntl.h"

using namespace std;
#define MAX_BUF 256

int main(int argc, char* argv[])
{
    int fd;
    char buf[MAX_BUF]; 
    int gpio = 1;

    fd = open("/sys/class/gpio/export", O_WRONLY);
    sprintf(buf, "%d", gpio); 
    write(fd, buf, strlen(buf));
    close(fd);

    sprintf(buf, "/sys/class/gpio/gpio%d/direction", gpio);
    fd = open(buf, O_WRONLY);
    // Set out direction
    write(fd, "out", 3); 
    // Set in direction
    write(fd, "in", 2); 
    close(fd);

    sprintf(buf, "/sys/class/gpio/gpio%d/value", gpio);
    fd = open(buf, O_WRONLY);
    // Set GPIO high status
    write(fd, "1", 1); 
    // Set GPIO low status 
    write(fd, "0", 1);
    close(fd);

    char value;
    sprintf(buf, "/sys/class/gpio/gpio%d/value", gpio);
    fd = open(buf, O_RDONLY);
    read(fd, &value, 1);
    if(value == '0')
    { 
        // Current GPIO status low
    }
    else
    {
        // Current GPIO status high
    }
    close(fd);

    fd = open("/sys/class/gpio/unexport", O_WRONLY);
    sprintf(buf, "%d", gpio);
    write(fd, buf, strlen(buf));
    close(fd);

    return 0;
}

gdb ./test
b main
set args .
r
p argc
p argv[0]
p argv[1]

gdb> b main
gdb>......
gdb> set args 127.0.0.1
gdb> r
gdb> p argc ------ 值:2
gdb> p argv @1 ------- 值:127.0.0.1

gdb调试命令的使用及总结
设置断点  (gdb) b 6

  这样会在运行到源码第6行时停止,可以查看变量的值、堆栈情况等;这个行号是gdb的行号。

查看断点处情况  (gdb) info b

  可以键入"info b"来查看断点处情况,可以设置多个断点;

运行代码  (gdb) r

显示变量值  (gdb) p n

  在程序暂停时,键入"p 变量名"(print)即可;

  GDB在显示变量值时都会在对应值之前加上"$N"标记,它是当前变量值的引用标记,以后若想再次引用此变量,就可以直接写作"$N",而无需写冗长的变量名;

观察变量  (gdb) watch n

 在某一循环处,往往希望能够观察一个变量的变化情况,这时就可以键入命令"watch"来观察变量的变化情况,GDB在"n"设置了观察点;

单步运行  (gdb) n

程序继续运行  (gdb) c

  使程序继续往下运行,直到再次遇到断点或程序结束;

10)退出GDB  (gdb) q
Referenced from:https://www.jb51.net/article/36393.htm

GDB常用命令使用说明(一) - 爱折腾的西山居士 - 博客园
update:2021-11-16
gdb使用前置条件:编译时加入debug信息。

    gcc/g++是在编译时加入-g,其他语言请自行百度。值得注意的是,-g分4个等级:

-g0等于不加-g。即不包含任何信息
-g1只包含最小信息,一般来说只有你不需要debug,只需要backtrace信息,并且真的很在意程序大小,或者有其他保密/特殊需求时才会使用-g1。
–g2为gdb默认等级,包含绝大多数你需要的信息。
–g3包含一些额外信息,例如包含宏定义信息。当你需要调试宏定义时,请使用-g3
 

二、gdb最常见的几个用法:

     1. 调试程序。有几种方法可以在gdb下运行你的程序:

        1)    gdb ${你的程序} 进入gdb后,输入run(简写r) ${arg1} ${arg2} … ${argN}

        2)    gdb --args ${你的程序} ${arg1} ${arg2} … ${argN} 进入gdb后,运行run。

        3)    gdb进入gdb后,输入file ${你的程序}。然后使用set args  ${arg1} ${arg2} … ${argN} 设定好你的程序参数,再运行run。

     2. 调试正在运行的程序:

        gdb ${你的程序} ${程序pid}

     3. 查core:

        gdb ${你的程序} ${core文件}
Referenced from:https://www.cnblogs.com/xsln/p/gdb_instructions1.html

代码如下:

/* Example code that uploads a file name 'foo' to a remote script that accepts
 * "HTML form based" (as described in RFC1738) uploads using HTTP POST.
 *
 * The imaginary form we will fill in looks like:
 *
 * <form method="post" enctype="multipart/form-data" action="examplepost.cgi">
 * Enter file: <input type="file" name="sendfile" size="40">
 * Enter file name: <input type="text" name="filename" size="30">
 * <input type="submit" value="send" name="submit">
 * </form>
 *
 */
 
#include <stdio.h>
#include <string.h>
 
#include <curl/curl.h>
 
int main(int argc, char *argv[])
{
  CURL *curl;
  CURLcode res;
 
  curl_mime *form = NULL;
  curl_mimepart *field = NULL;
  struct curl_slist *headerlist = NULL;
  static const char buf[] = "Expect:";
 
  curl_global_init(CURL_GLOBAL_ALL);
 
  curl = curl_easy_init();
  if(curl) {
    /* Create the form */
    form = curl_mime_init(curl);
 
    /* Fill in the file upload field */
    field = curl_mime_addpart(form);
    curl_mime_name(field, "sendfile");
    curl_mime_filedata(field, "postit2.c");
 
    /* Fill in the filename field */
    field = curl_mime_addpart(form);
    curl_mime_name(field, "filename");
    curl_mime_data(field, "postit2.c", CURL_ZERO_TERMINATED);
 
    /* Fill in the submit field too, even if this is rarely needed */
    field = curl_mime_addpart(form);
    curl_mime_name(field, "submit");
    curl_mime_data(field, "send", CURL_ZERO_TERMINATED);
 
    /* initialize custom header list (stating that Expect: 100-continue is not
       wanted */
    headerlist = curl_slist_append(headerlist, buf);
    /* what URL that receives this POST */
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/examplepost.cgi");
    if((argc == 2) && (!strcmp(argv[1], "noexpectheader")))
      /* only disable 100-continue header if explicitly requested */
      curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
    curl_easy_setopt(curl, CURLOPT_MIMEPOST, form);
 
    /* Perform the request, res will get the return code */
    res = curl_easy_perform(curl);
    /* Check for errors */
    if(res != CURLE_OK)
      fprintf(stderr, "curl_easy_perform() failed: %s\n",
              curl_easy_strerror(res));
 
    /* always cleanup */
    curl_easy_cleanup(curl);
 
    /* then cleanup the form */
    curl_mime_free(form);
    /* free slist */
    curl_slist_free_all(headerlist);
  }
  return 0;
}

一些说明,以及为什么要disable 100-continue

1)Expect: 100-continue的来龙去脉:

HTTP/1.1 协议里设计 100 (Continue) HTTP 状态码的的目的是,在客户端发送 Request Message 之前,HTTP/1.1 协议允许客户端先判定服务器是否愿意接受客户端发来的消息主体(基于 Request Headers)。

即, Client 和 Server 在Post (较大)数据之前,允许双方“握手”,如果匹配上了,Client 才开始发送(较大)数据。

这么做的原因是,如果客户端直接发送请求数据,但是服务器又将该请求拒绝的话,这种行为将带来很大的资源开销。

协议对 HTTP/1.1 clients 的要求是:

如果 client 预期等待“100-continue”的应答,那么它发的请求必须包含一个 " Expect: 100-continue" 的头域!

2)libcurl 发送大于1024字节数据时启用Expect:100-continue特性:

这也就是 Laruence 在 2011 年撰文所写的:

在使用 curl 做 POST 的时候,当要POST 的数据大于 1024 字节的时候,curl 并不会直接就发起 POST 请求,而是会分为两步:

  1. 发送一个请求,包含一个 "Expect:100-continue" 头域,询问 Server 是否愿意接收数据;
  2. 接收到 Server 返回的100-continue 应答以后,才把数据 POST 给Server;

这是 libcurl 的行为。

第一, libcurl在发送大于1024 字节的 POST 请求时采用了这种方法,但是相对的,它会引起请求延迟的加大。

第二,并不是所有的 web server 都能正确处理并应答“100-continue”,比如 lighttpd,就会返回417”Expectation Failed “,造成请求逻辑出错。

( 注1:lighttpd 1.4 版本有此严重问题,于1.5版本修复。注2:Resin 于 3.0.5 版本增加了对 Expect: 100-continue 的支持。)

3)PHP Curl-library 可以主动封禁此特性:

有人在 PHP手册::curl_setopt 下留言说:

PHP curl 遵从 libcurl 的特性。由于不是所有 web servers 都支持这个特性,所以会产生各种各样的错误。如果你遇到了,可以用下面的命令封禁"Expect"头域:

<?php
    curl_setopt($ch, CURLOPT_HTTPHEADER,array('Expect:'));
?>

一个或者多个空格替换成逗号:

sed 's/[ ][ ]*/,/g' a.txt >a.csv

或者:

cat a.txt |sed 's/\s+/,/g'  >a.csv

可以转成csv格式

一、原始文本word.txt内容

a c      b   d
d   b   c  a
a  c   d    b
c    a   r s
d   s   g   h

二、shell脚本

cat word.txt | sed 's/[ ][ ]*/,/g'

脚本说明:

s代表替换指令;
每个[ ]都包含有一个空格;
*号代表0个或多个;
g代表替换每行的所有匹配;

三、替换效果

a,c,b,d
d,b,c,a
a,c,d,b
c,a,r,s
d,s,g,h

Referenced from:https://blog.csdn.net/tterminator/article/details/52792959

linux shell 批量替换文件名中空格为下划线

for file in *; do mv "$file" `echo $file | tr ' ' '_'`; done