Akawa

ETY001的博客

转自:http://blog.chinaunix.net/uid-27105712-id-3349522.html

在linux下,关于文件权限,大部分人接触比较多,也比较熟悉了解.但是对进程权限一般知之甚少。本文总结一下linux系统下进程权限问题和现象。

需要强调的是,本文是linux系统下讨论,因为linux和unix有很多不同的地方,并且各个不同的unix系统也有很多不同。

先开门见山的列出本文讨论对象:ruid(实际用户id: real userid)、euid(有效用户用户:effective userid), suid(保存用户id:saved userid)、fuid(文件系统用户id)。

除了上面4个,还涉及到一个位 设置用户id位(set user id bit),,即我们通常所说的处rwx之外那个s标志位。

另外,本文主要讨论userid,groupid规则基本一样,例如rgid, egid, sgid, fgid等,本文就不做组id方面的重复讨论了。

首先,查看这几个uid的方法有两种方式:一是ps 命令 (ps -ax -o ruid -o euid -o suid -o fuid -o pid -o fname)列出这几个uid;二是查看status文件,(cat /proc/2495/status | grep Uid)。

本文创建5个test用户 test1~test5用来做本文中sample讨论使用,代表常见普通权限用户。

阅读全文 »

换行符
unix系列用 \n
windows系列用 \r\n
mac用 \r
PHP中可以用PHP_EOL来替代,以提高代码的源代码级可移植性

如:

类似常用的还有
DIRECTORY_SEPARATOR

可以用函数get_defined_constants()来获取所有PHP常量

转: http://www.cnblogs.com/codefor/archive/2011/06/18/2084300.html

转自:http://www.oschina.net/code/snippet_856191_23751

在实际应用中可以做用户权限的应用
我这里说到的权限管理办法是一个普遍采用的方法,主要是使用到”位运行符”操作,& 位与运算符、| 位或运行符。参与运算的如果是10进制数,则会被转换至2进制数参与运算,然后计算结果会再转换为10进制数输出。
它的权限值是这样的

1
2
3
4
2^0=1,相应2进数为”0001″(在这里^我表示成”次方”,即:2的0次方,下同)
2^1=2,相应2进数为”0010″
2^2=4,相应2进数为”0100″
2^3=8,相应2进数为”1000″

要判断一个数在某些数范围内就可以使用 & 运算符(数值从上面的表中得来)
如:7=4|2|1 (你也可以简单理解成7=4+2+1)
用 & 来操作,可以知道7&4、7&2、7&1都是真的,而如果7&8则是假的
&、| 不熟悉的就要去查查手册,看看是怎么用的了
下面来看例子吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 赋予权限值-->删除:8、上传:4、写入:2、只读:1
define(“mDELETE”,8);
define(“mUPLOAD”,4);
define(“mWRITE”,2);
define(“mREAD”,1);
//vvvvvvvvvvvvv使用说明vvvvvvvvvvvvv
//部门经理的权限为(假设它拥有此部门的所有权限),| 是位或运行符,不熟悉的就查查资料
echo mDELETE|mUPLOAD|mWRITE|mREAD ,'';// 相当于是把上面的权限值加起来:8+4+2+1=15
// 设我只有 upload 和 read 权限,则
echo mUPLOAD|mREAD ,'';//相当于是把上传、只读的权限值分别相加:4+1=5
/*
*赋予它多个权限就分别取得权限值相加,又比如某位员工拥有除了删除外的权限其余都拥有,那它的权限值是多少?
*应该是:4+2+1=7
*明白了怎么赋值给权限吧?
*/
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//判断某人的权限可用,设权限值在$key中
/*
*判断权限用&位与符,
*/
$key = 13;//13=8+4+1
if($key & mDELETE) echo '有删除权限'; //8
if($key & mUPLOAD) echo '有上传权限'; //4
$a=$key & mWRITE; echo '有写权限'.$a; //无此权限
if($key & mREAD) echo '有读权限'; //1
?>

  OK,权限分值的这其中一个算法就是这样的,可以说是简单高效。也不知大家明白没有,不明白也没关系,记住例子就行了。前提就是做好权限值的分布,即那个1、2、4、8、16….(这里还有个顺序问题,越高级的权限就要越高的权限值,比如上面的例子所演示的删除权限)。有了权限分布表就可以确定给某个人什么权限了,你简单的理解成要哪个权限就加上相应的权限值吧。
  这个方法很好用的,缺点就是如果权限分布得细的话,那么权限值会越来越大,你自己想想,2的几次方、如果所有的权限都要则是全部相加。不过对于一般的权限来说这个已经足够了。

下面是些简单应用举例

(1) 判断int型变量a是奇数还是偶数

a&1 = 0 偶数

a&1 = 1 奇数

(2) 取int型变量a的第k位 (k=0,1,2……sizeof(int)),即a>>k&1

(3) 将int型变量a的第k位清0,即a=a&~(1<

<>

(4) 将int型变量a的第k位置1, 即a=a|(1<

<>

(5) int型变量循环左移k次,即a=a<>16-k (设sizeof(int)=16)

(6) int型变量a循环右移k次,即a=a>>k|a<<16-k (设sizeof(int)=16)

(7)整数的平均值

对于两个整数x,y,如果用 (x+y)/2 求平均值,会产生溢出,因为 x+y 可能会大于INT_MAX,但是我们知道它们的平均值是肯定不会溢出的,我们用如下算法:

int average(int x, int y) //返回X,Y 的平均值

{

return (x&y)+((x^y)>>1);

}

(8)判断一个整数是不是2的幂,对于一个数 x >= 0,判断他是不是2的幂

boolean power2(int x)

{

return ((x&(x-1))==0)&&(x!=0);

}

(9)不用temp交换两个整数

void swap(int x , int y)

{

x ^= y;

y ^= x;

x ^= y;

}

(10)计算绝对值

int abs( int x )

{

int y ;

y = x >> 31 ;

return (x^y)-y ; //or: (x+y)^y

}

(11)取模运算转化成位运算 (在不产生溢出的情况下)

a % (2^n) 等价于 a & (2^n – 1)

(12)乘法运算转化成位运算 (在不产生溢出的情况下)

a * (2^n) 等价于 a<< n

(13)除法运算转化成位运算 (在不产生溢出的情况下)

a / (2^n) 等价于 a>> n

例: 12/8 == 12>>3

(14) a % 2 等价于 a & 1

(15) if (x == a) x= b;

   else x= a;

   等价于 x= a ^ b ^ x;

(16) x 的 相反数 表示为 (~x+1)

在32位系统上不要右移超过32位,不要在结果可能超过 32 位的情况下左移

转自:http://levi.cg.am/?p=3023

事务处理在各种管理系统中都有着广泛的应用,比如人员管理系统,很多同步数据库操作大都需要用到事务处理。比如说,在人员管理系统中,你删除一个人员,你即需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!
删除的SQL语句

delete from userinfo where ~~~
delete from mail where ~~
delete from article where~~
~~

如果没有事务处理,在你删除的过程中,假设出错了,只执行了第一句,那么其后果是难以想象的!
但用事务处理。如果删除出错,你只要rollback就可以取消删除操作(其实是只要你没有commit你就没有确实的执行该删除操作)

一般来说,在商务级的应用中,都必须考虑事务处理的!

阅读全文 »

最近在做的一个东西需要用到php去调用一个应用程序,而程序却不一定会第一时间就返回结果(执行效果有点像top命令),这就导致如果用php直接exec执行这个程序的话,php页面将会处于一直等待的状态中,直到最大超时时间到了后,会返回网关错误(我用的nginx做前端)。我自己曾试过在要执行的命令后面加&,使其变成后台程序,这样php就会立即返回了,不过用grep进程列表获取该程序的进程的时候,就发现如果多个空格就会导致搜索不到指定的进程,这样就没法kill掉这个进程了。于是又写了一个C程序,以实现这个C程序可以把一条命令转成守护进程执行,并且返回该守护进程的pid,这样我就可以直接在php里把返回的pid存起来,到时候直接kill掉就OK啦~

如果你以为这样就结束了,那你就错了,我在v2ex上发帖子希望能让大家帮我看看这个程序是否有安全隐患,没想到还有很多的解决措施,尤其是php自带的一些函数方法之前是不知道的。

1、pcntl系的函数。不过这个需要自己先安装这个扩展,在ext/pcntl下面,自己编译下就ok了,得到的so文件放到扩展目录,在php.ini中配置下就ok。不过就我刚才的测试来看,貌似还达不到我要的效果,pid的返回有些问题。

2、php-childprocess :项目地址,https://github.com/hfcorriez/php-childprocess,这个还没有时间仔细来看是如何实现以及该怎么用,不过看上去是很强大的样子。

如果还有回复的话,我会再补充到这里。

我写的那段C程地址在这里:https://github.com/ety001/mytools/tree/master/daemonRun

补充:

最后用shell脚本完爆啊。。

ffmpeg ******** >/dev/null 2>1 & echo $!

Linux下的网络编程分为两部分:服务器编程和客户机编程。一般服务器程序在接收客户机连接请求之前,都要创建一个守护进程。守护进程是linux/Unix编程中一个非常重要的概念,因为在创建一个守护进程的时候,我们要接触到子进程、进程组、会晤期、信号机制以及文件、目录、控制终端等多个概念,因此详细地讨论一下守护进程,对初学者学习进程间关系是非常有帮助的。

首先看一段将普通进程转换为守护进程的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/****************************************************************
function:   daemonize
description: detach the server process from the current context, creating a pristine, predictable        environment in which it will execute.
arguments:  servfd file descriptor in use by server.
return value: none.
calls:    none.
globals:   none.
****************************************************************/
void daemonize (servfd)
int servfd;
{
int childpid, fd, fdtablesize;
/* ignore terminal I/O, stop signals */
signal(SIGTTOU,SIG_IGN);
signal(SIGTTIN,SIG_IGN);
signal(SIGTSTP,SIG_IGN);
/* fork to put us in the background (whether or not the user
specified '&' on the command line */
if ((childpid = fork()) < 0) {
fputs("failed to fork first childrn",stderr);
exit(1);
}
else if (childpid > 0)
exit(0); /* terminate parent, continue in child */
/* dissociate from process group */
if (setpgrp(0,getpid())<0) {
fputs("failed to become process group leaderrn",stderr);
exit(1);
}
/* lose controlling terminal */
if ((fd = open("/dev/tty",O_RDWR)) >= 0) {
ioctl(fd,TIOCNOTTY,NULL);
close(fd);
}
/* close any open file descriptors */
for (fd = 0, fdtablesize = getdtablesize(); fd < fdtablesize; fd++)
if (fd != servfd)
close(fd);
/* set working directory to allow filesystems to be unmounted */
chdir("/");
/* clear the inherited umask */
umask(0);
/* setup zombie prevention */
signal(SIGCLD,(Sigfunc *)reap_status);
}

在linux系统中,如果要将一个普通进程转换为守护进程,需要执行的步骤如下:

1、调用fork()函数创建子进程,然后中止父进程,保留子进程继续运行。因为,当一个进程是以前台进程的方式由shell启动时,如果中止了父进程,子进程就会自动转为后台进程。另外,在下一步时,我们需要创建一个新的会晤期,这就要求创建会晤期的进程不是一个进程组的组长进程。当父进程中止,子进程继续运行时,就保证了进程组的组ID与子进程的进程ID不会相等。
fork()函数的定义为:

1
2
3
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);

fork()函数被调用一次,会返回两次值。这两次返回的值分别是子进程的返回值和父进程的返回值,子进程的返回值为“0”,父进程的返回值为子进程的进程ID。如果出错返回“-1”。

1、保证进程不会获得任何控制终端。这是为了避免在关闭某些终端时会显示有程序正在运行而无法关闭的情况。这一步通常的做法是:调用函数setsid()创建一个新的会晤期。
setsid()函数的定义为:

1
2
3
#include <sys/types.h>
#include <unistd.h>
pid_t setsid(void);

在第一步里我们已经保证了调用此函数的进程不是进程组的组长,那么调用此函数将创建一个新的会晤。其结果是:首先,此进程编程该会晤期的首进程(session leader,系统默认会晤期的首进程是创建该会晤期的进程)。而且,此进程是该会晤期中的唯一进程。然后,此进程将成为一个新的进程组的组长,新进程组的组ID就是该进程的进程ID。最后,保证此进程没有控制终端,即使在调用setsid()之前此进程拥有控制终端,在创建会晤期后这种联系也将被解除。如果调用该函数的进程是一个进程组的组长,那么函数将返回出错信息“-1”。

还有一个方法可以让进程无法获得控制终端,如下:

1
2
3
4
if((fd = fopen("/dev/tty",0_RDWR)) >= 0){
ioctl(fd,TIOCNOTTY,NULL);
close(fd);
}

其中/dev/tty是一个流设备,也是我们的终端映射。调用close()函数将终端关闭。

3、信号处理。一般要忽略掉某些信号。信号相当于软件中断,Linux/Unix下的信号机制提供了一种处理异步事件的方法,终端用户键入引发中断的键,或是系统发出信号,这都会通过信号处理机制终止一个或多个程序的运行。

不同情况下引发的信号不同,所有的信号都有自己的名字,这些名字都是以“SIG”开头的,只是后面有所不同。我们可以通过这些名字了解到系统中到底发生了什么事。当信号出现时,我们可以要求系统进行一下三种操作:

a、忽略信号。大多数信号都采用这种处理方法,但是对SIGKILL和SIGSTOP信号不能做忽略处理。

b、捕捉信号。这是一种最为灵活的操作方式。这种处理方式的意思就是:当某种信号发生时,我们可以调用一个函数对这种情况进行响应的处理。最常见的情况是:如果捕捉到SIGCHID信号,则表示子进程已经终止,然后可作此信号的捕捉函数中调用waitpid()函数取得该子进程的进程ID已经他的终止状态。如果进程创建了临时文件,那么就要为进程终止信号SIGTERM编写一个信号捕捉函数来清除这些临时文件。

c、执行系统的默认动作。对绝大多数信号而言,系统的默认动作都是终止该进程。

在Linux下,信号有很多种,我在这里就不一一介绍了,如果想详细地对这些信号进行了解,可以查看头文件<sigal.h>,这些信号都被定义为正整数,也就是它们的信号编号。在对信号进行处理时,必须要用到函数signal(),此函数的详细描述为:

1
2
#include <signal.h>
void (*signal (int signo, void (*func)(int)))(int);

其中参数signo为信号名,参数func的值根据我们的需要可以是以下几种情况:(1)常数SIG_DFL,表示执行系统的默认动作。(2)常数SIG_IGN,表示忽略信号。(3)收到信号后需要调用的处理函数的地址,此信号捕捉程序应该有一个整型参数但是没有返回值。signal()函数返回一个函数指针,而该指针指向的函数应该无返回值(void),这个指针其实指向以前的信号捕捉程序。

下面 回到我们的daemonize()函数上来。这个函数在创建守护进程时忽略了三个信号:

1
2
3
signal(SIGTTOU,SIG_IGN);
signal(SIGTTIN,SIG_IGN);
signal(SIGTSTP,SIG_IGN);

这三个信号的含义分别是:SIGTTOU表示后台进程写控制终端,SIGTTIN表示后台进程读控制终端,SIGTSTP表示终端挂起。

4.关闭不再需要的文件描述符,并为标准输入、标准输出和标准错误输出打开新的文件描述符(也可以继承父进程的标准输入、标准输出和标准错误输出文件描述符,这个操作是可选的)。在我们这段例程中,因为是代理服务器程序,而且是在执行了listen()函数之后执行这个daemonize()的,所以要保留已经转换成功的倾听套接字,所以我们可以见到这样的语句:
if (fd != servfd)
close(fd);

5.调用函数chdir(“/“)将当前工作目录更改为根目录。这是为了保证我们的进程不使用任何目录。否则我们的守护进程将一直占用某个目录,这可能会造成超级用户不能卸载一个文件系统。

6.调用函数umask(0)将文件方式创建屏蔽字设置为”0”。这是因为由继承得来的文件创建方式屏蔽字可能会禁止某些许可权。例如我们的守护进程需要创建一组可读可写的文件,而此守护进程从父进程那里继承来的文件创建方式屏蔽字却有可能屏蔽掉了这两种许可权,则新创建的一组文件其读或写操作就不能生效。因此要将文件方式创建屏蔽字设置为”0”。
在daemonize()函数的最后,我们可以看到这样的信号捕捉处理语句:

1
signal(SIGCLD,(Sigfunc *)reap_status);

这不是创建守护进程过程中必须的一步,它的作用是调用我们自定义的reap_status()函数来处理僵死进程。reap_status()在例程中的定义为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/****************************************************************
function:    reap_status
description:   handle a SIGCLD signal by reaping the exit status of the perished child, and            discarding it.
arguments:    none.
return value:  none.
calls:      none.
globals:     none.
****************************************************************/
void reap_status()
{
int pid;
union wait status;
while ((pid = wait3(&status,WNOHANG,NULL)) > 0)
; /* loop while there are more dead children */
}

上面信号捕捉语句的原文为:
signal(SIGCLD, reap_status);
我们刚才说过,signal()函数的第二个参数一定要有有一个整型参数但是没有返回值。而reap_status()是没有参数的,所以原来的语句在编译时无法通过。所以我在预编译部分加入了对Sigfunc()的类型定义,在这里用做对reap_status进行强制类型转换。而且在BSD系统中通常都使用SIGCHLD信号来处理子进程终止的有关信息,SIGCLD是System V中定义的一个信号名,如果将SIGCLD信号的处理方式设定为捕捉,那么内核将马上检查系统中是否存在已经终止等待处理的子进程,如果有,则立即调用信号捕捉处理程序。
一般在信号捕捉处理程序中都要调用wait()、waitpid()、wait3()或是wait4()来返回子进程的终止状态。这些”等待”函数的区别是,当要求函数”等待”的子进程还没有终止时,wait()将使其调用者阻塞;而在waitpid()的参数中可以设定使调用者不发生阻塞,wait()函数不被设置为等待哪个具体的子进程,它等待调用者所有子进程中首先终止的那个,而在调用waitpid()时却必须在参数中设定被等待的子进程ID。而wait3()和wait4()的参数分别比wait()和waitpid()还要多一个”rusage”。例程中的reap_status()就调用了函数wait3(),这个函数是BSD系统支持的,我们把它和wait4()的定义一起列出来:

1
2
3
4
5
6
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
pid_t wait3(int *statloc, int options, struct rusage *rusage);
pid_t wait4(pid_t pid, int *statloc, int options, struct rusage *rusage);

其中指针statloc如果不为”NULL”,那么它将指向返回的子进程终止状态。参数pid是我们指定的被等待的子进程的进程ID。参数options是我们的控制选择项,一般为WNOHANG或是WUNTRACED。例程中使用了选项WNOHANG,意即如果不能立即返回子进程的终止状态(譬如由于子进程还未结束),那么等待函数不阻塞,此时返回”0”。      WUNTRACED选项的意思是如果系统支持作业控制,如果要等待的子进程的状态已经暂停,而且其状态自从暂停以来还从未报告过,则返回其状态。参数rusage如果不为”NULL”,则它将指向内核返回的由终止进程及其所有子进程使用的资源摘要,该摘要包括用户CPU时间总量、缺页次数、接收到信号的次数等。


最近在做的一个项目的web服务器是放在内网环境中的,使用lnmp,在整个网络的出口通过nginx进行proxy到这台web服务器。不过有时候访问的时候,会出现502错误,因此在出口处的nginx中增加了以下配置,有待观察效果:

1
2
3
4
5
6
7
8
9
10
proxy_connect_timeout 600;
proxy_read_timeout 600;
proxy_send_timeout 600;
proxy_buffer_size 16k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_temp_path /data/nginx_temp_path;
proxy_cache_path /data/nginx_cache_path levels=1:2 keys_zone=cac
he_one:2000m inactive=1d max_size=5m;

尔湾市

安装一个工具,mdbtools,地址:http://mdbtools.sourceforge.net/,ubuntu应该可以直接安装,archlinux在aur中有。

具体使用方法:

To get the list of tables, you run the following command:

mdb-tables database.mdb

You can then get a CSV version for each table using:

mdb-export database.mdb table_name

You can also convert the mdb into a format required by MySQL. First you must get the put the table schema into the database using the following command:

mdb-schema database.mdb | mysql -u username -p database_name

You then import each table by running:

mdb-export -I database.mdb table_name | sed -e 's/)$/)\;/' | mysql -u username -p database_name
0%