File: sig.c

package info (click to toggle)
procps 1%3A2.0.6-5
  • links: PTS
  • area: main
  • in suites: potato
  • size: 932 kB
  • ctags: 1,146
  • sloc: ansic: 10,494; makefile: 229; sh: 80
file content (234 lines) | stat: -rw-r--r-- 6,166 bytes parent folder | download | duplicates (2)
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
/*
 * Copyright 1998 by Albert Cahalan; all rights resered.
 * This file may be used subject to the terms and conditions of the
 * GNU Library General Public License Version 2, or any later version
 * at your option, as published by the Free Software Foundation.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Library General Public License for more details.
 */
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

/* Linux signals:
 *
 * SIGSYS is required by Unix98.
 * SIGEMT is part of SysV, BSD, and ancient UNIX tradition.
 *
 * They are provided by these Linux ports: alpha, mips, sparc, and sparc64.
 * You get SIGSTKFLT and SIGUNUSED instead on i386, m68k, ppc, and arm.
 * (this is a Linux & libc bug -- both must be fixed)
 *
 * Total garbage: SIGIO SIGINFO SIGIOT SIGLOST SIGCLD
 *                 (popular ones are handled as aliases)
 * Nearly garbage: SIGSTKFLT SIGUNUSED (nothing else to fill slots)
 */

/* Linux 2.3.29 replaces SIGUNUSED with the standard SIGSYS signal */
#ifndef SIGSYS
#  warning Standards require that <signal.h> define SIGSYS
#  define SIGSYS SIGUNUSED
#endif

/* If we see both, it is likely SIGSTKFLT (junk) was replaced. */
#ifdef SIGEMT
#  undef SIGSTKFLT
#endif

#ifndef SIGRTMIN
#  warning Standards require that <signal.h> define SIGRTMIN; assuming 32
#  define SIGRTMIN 32
#endif

/* It seems the SPARC libc does not know the kernel supports SIGPWR. */
#ifndef SIGPWR
#  warning Your header files lack SIGPWR. (assuming it is number 29)
#  define SIGPWR 29
#endif

typedef struct mapstruct {
  char *name;
  int num;
} mapstruct;


static mapstruct sigtable[] = {
  {"ABRT",   SIGABRT},  /* IOT */
  {"ALRM",   SIGALRM},
  {"BUS",    SIGBUS},
  {"CHLD",   SIGCHLD},  /* CLD */
  {"CONT",   SIGCONT},
#ifdef SIGEMT
  {"EMT",    SIGEMT},
#endif
  {"FPE",    SIGFPE},
  {"HUP",    SIGHUP},
  {"ILL",    SIGILL},
  {"INT",    SIGINT},
  {"KILL",   SIGKILL},
  {"PIPE",   SIGPIPE},
  {"POLL",   SIGPOLL},  /* IO */
  {"PROF",   SIGPROF},
  {"PWR",    SIGPWR},
  {"QUIT",   SIGQUIT},
  {"SEGV",   SIGSEGV},
#ifdef SIGSTKFLT
  {"STKFLT", SIGSTKFLT},
#endif
  {"STOP",   SIGSTOP},
  {"SYS",    SIGSYS},   /* UNUSED */
  {"TERM",   SIGTERM},
  {"TRAP",   SIGTRAP},
  {"TSTP",   SIGTSTP},
  {"TTIN",   SIGTTIN},
  {"TTOU",   SIGTTOU},
  {"URG",    SIGURG},
  {"USR1",   SIGUSR1},
  {"USR2",   SIGUSR2},
  {"VTALRM", SIGVTALRM},
  {"WINCH",  SIGWINCH},
  {"XCPU",   SIGXCPU},
  {"XFSZ",   SIGXFSZ}
};

static const int number_of_signals = sizeof(sigtable)/sizeof(mapstruct);

static int compare_signal_names(const void *a, const void *b){
  return strcasecmp( ((mapstruct*)a)->name, ((mapstruct*)b)->name );
}

/* return -1 on failure */
int signal_name_to_number(char *name){
  const mapstruct *ptr;
  mapstruct ms;
  long val;
  char *endp;
  int offset;

  /* clean up name */
  if(!strncasecmp(name,"SIG",3)) name += 3;

  if(!strcasecmp(name,"CLD")) return SIGCHLD;
  if(!strcasecmp(name,"IO"))  return SIGPOLL;
  if(!strcasecmp(name,"IOT")) return SIGABRT;

  /* search the table */
  ms.name = name;
  ptr = bsearch(&ms, sigtable, number_of_signals,
     sizeof(mapstruct), compare_signal_names
  );
  if(ptr) return ptr->num;

  if(!strcasecmp(name,"RTMIN")) return SIGRTMIN;
  if(!strcasecmp(name,"EXIT"))  return 0;
  if(!strcasecmp(name,"NULL"))  return 0;

  offset = 0;
  if(!strncasecmp(name,"RTMIN+",6)){
    name += 6;
    offset = SIGRTMIN;
  }

  /* not found, so try as a number */
  val = strtol(name,&endp,10);
  if(*endp) return -1; /* not valid */
  if(val+SIGRTMIN>127) return -1; /* not valid */
  return val+offset;
}

static const char *signal_number_to_name(int signo){
  static char buf[32];
  int n = number_of_signals;
  signo &= 0x7f; /* need to process exit values too */
  while(n--){
    if(sigtable[n].num==signo) return sigtable[n].name;
  }
  if(signo == SIGRTMIN) return "RTMIN";
  if(signo) sprintf(buf, "RTMIN+%d", signo-SIGRTMIN);
  else      strcpy(buf,"0");  /* AIX has NULL; Solaris has EXIT */
  return buf;
}

int print_given_signals(int argc, char *argv[], int max_line){
  char buf[1280]; /* 128 signals, "RTMIN+xx" is largest */
  int ret = 0;  /* to be used as exit code by caller */
  int place = 0; /* position on this line */
  int amt;
  if(argc > 128) return 1;
  while(argc--){
    char tmpbuf[16];
    char *txt; /* convenient alias */
    txt = *argv;
    if(*txt >= '0' && *txt <= '9'){
      long val;
      char *endp;
      val = strtol(txt,&endp,10);
      if(*endp){
        fprintf(stderr, "Signal \"%s\" not known.\n", txt);
        ret = 1;
        goto end;
      }
      amt = sprintf(tmpbuf, "%s", signal_number_to_name(val));
    }else{
      int sno;
      sno = signal_name_to_number(txt);
      if(sno == -1){
        fprintf(stderr, "Signal \"%s\" not known.\n", txt);
        ret = 1;
        goto end;
      }
      amt = sprintf(tmpbuf, "%d", sno);
    }

    if(!place){
      strcpy(buf,tmpbuf);
      place = amt;
      goto end;
    }
    if(amt+place+1 > max_line){
      printf("%s\n", buf);
      strcpy(buf,tmpbuf);
      place = amt;
      goto end;
    }
    sprintf(buf+place, " %s", tmpbuf);
    place += amt+1;
end:
    argv++;
  }
  if(place) printf("%s\n", buf);
  return ret;
}

void pretty_print_signals(void){
  int i = 0;
  while(++i <= number_of_signals){
    int n;
    n = printf("%2d %s", i, signal_number_to_name(i));
    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);
    else printf("\n");
  }
  if((i-1)%7) printf("\n");
}

void unix_print_signals(void){
  int pos = 0;
  int i = 0;
  while(++i <= number_of_signals){
    if(i-1) printf("%c", (pos>73)?(pos=0,'\n'):(pos++,' ') );
    pos += printf("%s", signal_number_to_name(i));
  }
  printf("\n");
}

/* sanity check */
static int init_signal_list(void) __attribute__((constructor));
static int init_signal_list(void){
  if(number_of_signals != 31){
    fprintf(stderr, "WARNING: %d signals -- adjust and recompile.\n", number_of_signals);
  }
  return 0;
}