Updated with Tizen:Base source codes
[external/procps.git] / proc / sig.c
1 /*
2  * Copyright 1998-2003 by Albert Cahalan; all rights resered.
3  * This file may be used subject to the terms and conditions of the
4  * GNU Library General Public License Version 2, or any later version
5  * at your option, as published by the Free Software Foundation.
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU Library General Public License for more details.
10  */
11 #include <signal.h>
12 #include <string.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include "sig.h"
16
17 /* Linux signals:
18  *
19  * SIGSYS is required by Unix98.
20  * SIGEMT is part of SysV, BSD, and ancient UNIX tradition.
21  *
22  * They are provided by these Linux ports: alpha, mips, sparc, and sparc64.
23  * You get SIGSTKFLT and SIGUNUSED instead on i386, m68k, ppc, and arm.
24  * (this is a Linux & libc bug -- both must be fixed)
25  *
26  * Total garbage: SIGIO SIGINFO SIGIOT SIGLOST SIGCLD
27  *                 (popular ones are handled as aliases)
28  * Nearly garbage: SIGSTKFLT SIGUNUSED (nothing else to fill slots)
29  */
30
31 /* Linux 2.3.29 replaces SIGUNUSED with the standard SIGSYS signal */
32 #ifndef SIGSYS
33 #  warning Standards require that <signal.h> define SIGSYS
34 #  define SIGSYS SIGUNUSED
35 #endif
36
37 /* If we see both, it is likely SIGSTKFLT (junk) was replaced. */
38 #ifdef SIGEMT
39 #  undef SIGSTKFLT
40 #endif
41
42 #ifndef SIGRTMIN
43 #  warning Standards require that <signal.h> define SIGRTMIN; assuming 32
44 #  define SIGRTMIN 32
45 #endif
46
47 /* It seems the SPARC libc does not know the kernel supports SIGPWR. */
48 #ifndef SIGPWR
49 #  warning Your header files lack SIGPWR. (assuming it is number 29)
50 #  define SIGPWR 29
51 #endif
52
53 typedef struct mapstruct {
54   const char *name;
55   int num;
56 } mapstruct;
57
58
59 static const mapstruct sigtable[] = {
60   {"ABRT",   SIGABRT},  /* IOT */
61   {"ALRM",   SIGALRM},
62   {"BUS",    SIGBUS},
63   {"CHLD",   SIGCHLD},  /* CLD */
64   {"CONT",   SIGCONT},
65 #ifdef SIGEMT
66   {"EMT",    SIGEMT},
67 #endif
68   {"FPE",    SIGFPE},
69   {"HUP",    SIGHUP},
70   {"ILL",    SIGILL},
71   {"INT",    SIGINT},
72   {"KILL",   SIGKILL},
73   {"PIPE",   SIGPIPE},
74   {"POLL",   SIGPOLL},  /* IO */
75   {"PROF",   SIGPROF},
76   {"PWR",    SIGPWR},
77   {"QUIT",   SIGQUIT},
78   {"SEGV",   SIGSEGV},
79 #ifdef SIGSTKFLT
80   {"STKFLT", SIGSTKFLT},
81 #endif
82   {"STOP",   SIGSTOP},
83   {"SYS",    SIGSYS},   /* UNUSED */
84   {"TERM",   SIGTERM},
85   {"TRAP",   SIGTRAP},
86   {"TSTP",   SIGTSTP},
87   {"TTIN",   SIGTTIN},
88   {"TTOU",   SIGTTOU},
89   {"URG",    SIGURG},
90   {"USR1",   SIGUSR1},
91   {"USR2",   SIGUSR2},
92   {"VTALRM", SIGVTALRM},
93   {"WINCH",  SIGWINCH},
94   {"XCPU",   SIGXCPU},
95   {"XFSZ",   SIGXFSZ}
96 };
97
98 static const int number_of_signals = sizeof(sigtable)/sizeof(mapstruct);
99
100 static int compare_signal_names(const void *a, const void *b){
101   return strcasecmp( ((const mapstruct*)a)->name, ((const mapstruct*)b)->name );
102 }
103
104 /* return -1 on failure */
105 int signal_name_to_number(const char *restrict name){
106   long val;
107   int offset;
108
109   /* clean up name */
110   if(!strncasecmp(name,"SIG",3)) name += 3;
111
112   if(!strcasecmp(name,"CLD")) return SIGCHLD;
113   if(!strcasecmp(name,"IO"))  return SIGPOLL;
114   if(!strcasecmp(name,"IOT")) return SIGABRT;
115
116   /* search the table */
117   {
118     const mapstruct ms = {name,0};
119     const mapstruct *restrict const ptr = bsearch(
120       &ms,
121       sigtable,
122       number_of_signals,
123       sizeof(mapstruct),
124       compare_signal_names
125     );
126     if(ptr) return ptr->num;
127   }
128
129   if(!strcasecmp(name,"RTMIN")) return SIGRTMIN;
130   if(!strcasecmp(name,"EXIT"))  return 0;
131   if(!strcasecmp(name,"NULL"))  return 0;
132
133   offset = 0;
134   if(!strncasecmp(name,"RTMIN+",6)){
135     name += 6;
136     offset = SIGRTMIN;
137   }
138
139   /* not found, so try as a number */
140   {
141     char *endp;
142     val = strtol(name,&endp,10);
143     if(*endp || endp==name) return -1; /* not valid */
144   }
145   if(val+SIGRTMIN>127) return -1; /* not valid */
146   return val+offset;
147 }
148
149 const char *signal_number_to_name(int signo){
150   static char buf[32];
151   int n = number_of_signals;
152   signo &= 0x7f; /* need to process exit values too */
153   while(n--){
154     if(sigtable[n].num==signo) return sigtable[n].name;
155   }
156   if(signo == SIGRTMIN) return "RTMIN";
157   if(signo) sprintf(buf, "RTMIN+%d", signo-SIGRTMIN);
158   else      strcpy(buf,"0");  /* AIX has NULL; Solaris has EXIT */
159   return buf;
160 }
161
162 int print_given_signals(int argc, const char *restrict const *restrict argv, int max_line){
163   char buf[1280]; /* 128 signals, "RTMIN+xx" is largest */
164   int ret = 0;  /* to be used as exit code by caller */
165   int place = 0; /* position on this line */
166   int amt;
167   if(argc > 128) return 1;
168   while(argc--){
169     char tmpbuf[16];
170     const char *restrict const txt = *argv;
171     if(*txt >= '0' && *txt <= '9'){
172       long val;
173       char *endp;
174       val = strtol(txt,&endp,10);
175       if(*endp){
176         fprintf(stderr, "Signal \"%s\" not known.\n", txt);
177         ret = 1;
178         goto end;
179       }
180       amt = sprintf(tmpbuf, "%s", signal_number_to_name(val));
181     }else{
182       int sno;
183       sno = signal_name_to_number(txt);
184       if(sno == -1){
185         fprintf(stderr, "Signal \"%s\" not known.\n", txt);
186         ret = 1;
187         goto end;
188       }
189       amt = sprintf(tmpbuf, "%d", sno);
190     }
191
192     if(!place){
193       strcpy(buf,tmpbuf);
194       place = amt;
195       goto end;
196     }
197     if(amt+place+1 > max_line){
198       printf("%s\n", buf);
199       strcpy(buf,tmpbuf);
200       place = amt;
201       goto end;
202     }
203     sprintf(buf+place, " %s", tmpbuf);
204     place += amt+1;
205 end:
206     argv++;
207   }
208   if(place) printf("%s\n", buf);
209   return ret;
210 }
211
212 void pretty_print_signals(void){
213   int i = 0;
214   while(++i <= number_of_signals){
215     int n;
216     n = printf("%2d %s", i, signal_number_to_name(i));
217     if(i%7) printf("           \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + n);
218     else printf("\n");
219   }
220   if((i-1)%7) printf("\n");
221 }
222
223 void unix_print_signals(void){
224   int pos = 0;
225   int i = 0;
226   while(++i <= number_of_signals){
227     if(i-1) printf("%c", (pos>73)?(pos=0,'\n'):(pos++,' ') );
228     pos += printf("%s", signal_number_to_name(i));
229   }
230   printf("\n");
231 }
232
233 /* sanity check */
234 static int init_signal_list(void) __attribute__((constructor));
235 static int init_signal_list(void){
236   if(number_of_signals != 31){
237     fprintf(stderr, "WARNING: %d signals -- adjust and recompile.\n", number_of_signals);
238   }
239   return 0;
240 }