diskd.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section -- External DISKD process implementation. */
10 
11 #include "squid.h"
12 #include "compat/socket.h"
13 #include "compat/unistd.h"
15 #include "hash.h"
16 
17 #include <cerrno>
18 #include <iostream>
19 #if HAVE_SYS_IPC_H
20 #include <sys/ipc.h>
21 #endif
22 #if HAVE_SYS_MSG_H
23 #include <sys/msg.h>
24 #endif
25 #if HAVE_SYS_SHM_H
26 #include <sys/shm.h>
27 #endif
28 
29 void
30 xassert(const char *msg, const char *file, int line)
31 {
32  fprintf(stderr,"assertion failed: %s:%d: \"%s\"\n", file, line, msg);
33 
34  abort();
35 }
36 
37 const int diomsg::msg_snd_rcv_sz = sizeof(diomsg) - sizeof(mtyp_t);
38 #define DEBUG(LEVEL) if ((LEVEL) <= DebugLevel)
39 
40 typedef struct _file_state file_state;
41 
42 struct _file_state {
43  void *key;
45  int id;
46  int fd;
47  off_t offset;
48 };
49 
50 static hash_table *hash = nullptr;
51 static pid_t mypid;
52 static char *shmbuf;
53 static int DebugLevel = 0;
54 
55 static int
56 do_open(diomsg * r, int, const char *buf)
57 {
58  file_state *fs;
59  /*
60  * note r->offset holds open() flags
61  */
62  const auto fd = xopen(buf, r->offset, 0600);
63 
64  if (fd < 0) {
65  DEBUG(1) {
66  fprintf(stderr, "%d %s: ", (int) mypid, buf);
67  perror("open");
68  }
69 
70  return -errno;
71  }
72 
73  fs = (file_state *)xcalloc(1, sizeof(*fs));
74  fs->id = r->id;
75  fs->key = &fs->id; /* gack */
76  fs->fd = fd;
77  hash_join(hash, (hash_link *) fs);
78  DEBUG(2) {
79  fprintf(stderr, "%d OPEN id %d, FD %d, fs %p\n",
80  (int) mypid,
81  fs->id,
82  fs->fd,
83  fs);
84  }
85  return fd;
86 }
87 
88 static int
89 do_close(diomsg * r, int)
90 {
91  int fd;
92  file_state *fs;
93  fs = (file_state *) hash_lookup(hash, &r->id);
94 
95  if (nullptr == fs) {
96  errno = EBADF;
97  DEBUG(1) {
98  fprintf(stderr, "%d CLOSE id %d: ", (int) mypid, r->id);
99  perror("do_close");
100  }
101 
102  return -errno;
103  }
104 
105  fd = fs->fd;
107  DEBUG(2) {
108  fprintf(stderr, "%d CLOSE id %d, FD %d, fs %p\n",
109  (int) mypid,
110  r->id,
111  fs->fd,
112  fs);
113  }
114  xfree(fs);
115  return xclose(fd);
116 }
117 
118 static int
119 do_read(diomsg * r, int, char *buf)
120 {
121  int readlen = r->size;
122  file_state *fs;
123  fs = (file_state *) hash_lookup(hash, &r->id);
124 
125  if (nullptr == fs) {
126  errno = EBADF;
127  DEBUG(1) {
128  fprintf(stderr, "%d READ id %d: ", (int) mypid, r->id);
129  perror("do_read");
130  }
131 
132  return -errno;
133  }
134 
135  if (r->offset > -1 && r->offset != fs->offset) {
136  DEBUG(2) {
137  fprintf(stderr, "seeking to %" PRId64 "\n", (int64_t)r->offset);
138  }
139 
140  if (lseek(fs->fd, r->offset, SEEK_SET) < 0) {
141  DEBUG(1) {
142  fprintf(stderr, "%d FD %d, offset %" PRId64 ": ", (int) mypid, fs->fd, (int64_t)r->offset);
143  perror("lseek");
144  }
145  }
146  }
147 
148  const auto x = xread(fs->fd, buf, readlen);
149  DEBUG(2) {
150  fprintf(stderr, "%d READ %d,%d,%" PRId64 " ret %d\n", (int) mypid,
151  fs->fd, readlen, (int64_t)r->offset, x);
152  }
153 
154  if (x < 0) {
155  DEBUG(1) {
156  fprintf(stderr, "%d FD %d: ", (int) mypid, fs->fd);
157  perror("read");
158  }
159 
160  return -errno;
161  }
162 
163  fs->offset = r->offset + x;
164  return x;
165 }
166 
167 static int
168 do_write(diomsg * r, int, const char *buf)
169 {
170  int wrtlen = r->size;
171  file_state *fs;
172  fs = (file_state *) hash_lookup(hash, &r->id);
173 
174  if (nullptr == fs) {
175  errno = EBADF;
176  DEBUG(1) {
177  fprintf(stderr, "%d WRITE id %d: ", (int) mypid, r->id);
178  perror("do_write");
179  }
180 
181  return -errno;
182  }
183 
184  if (r->offset > -1 && r->offset != fs->offset) {
185  if (lseek(fs->fd, r->offset, SEEK_SET) < 0) {
186  DEBUG(1) {
187  fprintf(stderr, "%d FD %d, offset %" PRId64 ": ", (int) mypid, fs->fd, (int64_t)r->offset);
188  perror("lseek");
189  }
190  }
191  }
192 
193  DEBUG(2) {
194  fprintf(stderr, "%d WRITE %d,%d,%" PRId64 "\n", (int) mypid,
195  fs->fd, wrtlen, (int64_t)r->offset);
196  }
197  const auto x = xwrite(fs->fd, buf, wrtlen);
198 
199  if (x < 0) {
200  DEBUG(1) {
201  fprintf(stderr, "%d FD %d: ", (int) mypid, fs->fd);
202  perror("write");
203  }
204 
205  return -errno;
206  }
207 
208  fs->offset = r->offset + x;
209  return x;
210 }
211 
212 static int
213 do_unlink(diomsg * r, int, const char *buf)
214 {
215  if (unlink(buf) < 0) {
216  DEBUG(1) {
217  fprintf(stderr, "%d UNLNK id %d %s: ", (int) mypid, r->id, buf);
218  perror("unlink");
219  }
220 
221  return -errno;
222  }
223 
224  DEBUG(2) {
225  fprintf(stderr, "%d UNLNK %s\n", (int) mypid, buf);
226  }
227  return 0;
228 }
229 
230 static void
231 msg_handle(diomsg * r, int rl, diomsg * s)
232 {
233  char *buf = nullptr;
234  s->mtype = r->mtype;
235  s->id = r->id;
236  s->seq_no = r->seq_no; /* optional, debugging */
238  s->requestor = r->requestor;
239  s->size = 0; /* optional, debugging */
240  s->offset = 0; /* optional, debugging */
241  s->shm_offset = r->shm_offset;
242  s->newstyle = r->newstyle;
243 
244  if (s->shm_offset > -1)
245  buf = shmbuf + s->shm_offset;
246  else if (r->mtype != _MQD_CLOSE) {
247  fprintf(stderr, "%d UNLNK id(%u) Error: no filename in shm buffer\n", (int) mypid, s->id);
248  return;
249  }
250 
251  switch (r->mtype) {
252 
253  case _MQD_OPEN:
254 
255  case _MQD_CREATE:
256  s->status = do_open(r, rl, buf);
257  break;
258 
259  case _MQD_CLOSE:
260  s->status = do_close(r, rl);
261  break;
262 
263  case _MQD_READ:
264  s->status = do_read(r, rl, buf);
265  break;
266 
267  case _MQD_WRITE:
268  s->status = do_write(r, rl, buf);
269  break;
270 
271  case _MQD_UNLINK:
272  s->status = do_unlink(r, rl, buf);
273  break;
274 
275  default:
276  assert(0);
277  break;
278  }
279 }
280 
281 static int
282 fsCmp(const void *a, const void *b)
283 {
284  const int *A = (const int *)a;
285  const int *B = (const int *)b;
286  return *A != *B;
287 }
288 
289 static unsigned int
290 fsHash(const void *key, unsigned int n)
291 {
292  /* note, n must be a power of 2! */
293  const int *k = (const int *)key;
294  return (*k & (--n));
295 }
296 
297 extern "C" {
298  static void alarm_handler(int) {}
299 };
300 
301 int
302 main(int argc, char *argv[])
303 {
304  int key;
305  int rmsgid;
306  int smsgid;
307  int shmid;
308  diomsg rmsg;
309  diomsg smsg;
310  int rlen;
311  char rbuf[512];
312 
313  struct sigaction sa;
314  setbuf(stdout, nullptr);
315  setbuf(stderr, nullptr);
316  mypid = getpid();
317  assert(4 == argc);
318  key = atoi(argv[1]);
319  rmsgid = msgget(key, 0600);
320 
321  if (rmsgid < 0) {
322  perror("msgget");
323  exit(EXIT_FAILURE);
324  }
325 
326  key = atoi(argv[2]);
327  smsgid = msgget(key, 0600);
328 
329  if (smsgid < 0) {
330  perror("msgget");
331  exit(EXIT_FAILURE);
332  }
333 
334  key = atoi(argv[3]);
335  shmid = shmget(key, 0, 0600);
336 
337  if (shmid < 0) {
338  perror("shmget");
339  exit(EXIT_FAILURE);
340  }
341 
342  shmbuf = (char *)shmat(shmid, nullptr, 0);
343 
344  if (shmbuf == (void *) -1) {
345  perror("shmat");
346  exit(EXIT_FAILURE);
347  }
348 
349  hash = hash_create(fsCmp, 1 << 4, fsHash);
350  assert(hash);
351  if (fcntl(0, F_SETFL, SQUID_NONBLOCK) < 0) {
352  perror(xstrerr(errno));
353  exit(EXIT_FAILURE);
354  }
355  memset(&sa, '\0', sizeof(sa));
356  sa.sa_handler = alarm_handler;
357  sa.sa_flags = SA_RESTART;
358  sigaction(SIGALRM, &sa, nullptr);
359 
360  for (;;) {
361  alarm(1);
362  memset(&rmsg, '\0', sizeof(rmsg));
363  DEBUG(2) {
364  std::cerr << "msgrcv: " << rmsgid << ", "
365  << &rmsg << ", " << diomsg::msg_snd_rcv_sz
366  << ", " << 0 << ", " << 0 << std::endl;
367  }
368  rlen = msgrcv(rmsgid, &rmsg, diomsg::msg_snd_rcv_sz, 0, 0);
369 
370  if (rlen < 0) {
371  if (EINTR == errno) {
372  if (xread(0, rbuf, 512) <= 0) {
373  if (EWOULDBLOCK == errno)
374  (void) 0;
375  else if (EAGAIN == errno)
376  (void) 0;
377  else
378  break;
379  }
380  }
381 
382  if (EAGAIN == errno) {
383  continue;
384  }
385 
386  perror("msgrcv");
387  break;
388  }
389 
390  alarm(0);
391  msg_handle(&rmsg, rlen, &smsg);
392 
393  if (msgsnd(smsgid, &smsg, diomsg::msg_snd_rcv_sz, 0) < 0) {
394  perror("msgsnd");
395  break;
396  }
397  }
398 
399  DEBUG(2) {
400  fprintf(stderr, "%d diskd exiting\n", (int) mypid);
401  }
402 
403  if (msgctl(rmsgid, IPC_RMID, nullptr) < 0)
404  perror("msgctl IPC_RMID");
405 
406  if (msgctl(smsgid, IPC_RMID, nullptr) < 0)
407  perror("msgctl IPC_RMID");
408 
409  if (shmdt(shmbuf) < 0)
410  perror("shmdt");
411 
412  if (shmctl(shmid, IPC_RMID, nullptr) < 0)
413  perror("shmctl IPC_RMID");
414 
415  return EXIT_SUCCESS;
416 }
417 
void xassert(const char *msg, const char *file, int line)
Definition: diskd.cc:30
const char * xstrerr(int error)
Definition: xstrerror.cc:83
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:71
@ _MQD_WRITE
Definition: diomsg.h:24
static unsigned int fsHash(const void *key, unsigned int n)
Definition: diskd.cc:290
void * key
Definition: diskd.cc:43
void hash_remove_link(hash_table *, hash_link *)
Definition: hash.cc:220
static int DebugLevel
Definition: diskd.cc:53
@ _MQD_CREATE
Definition: diomsg.h:21
int xwrite(int fd, const void *buf, size_t bufSize)
POSIX write(2) equivalent.
Definition: unistd.h:67
long mtyp_t
Definition: types.h:141
hash_link * hash_lookup(hash_table *, const void *)
Definition: hash.cc:146
int status
Definition: diomsg.h:38
Lock * requestor
Definition: diomsg.h:35
static int do_close(diomsg *r, int)
Definition: diskd.cc:89
static int do_read(diomsg *r, int, char *buf)
Definition: diskd.cc:119
static void msg_handle(diomsg *r, int rl, diomsg *s)
Definition: diskd.cc:231
@ _MQD_CLOSE
Definition: diomsg.h:22
#define DEBUG(LEVEL)
Definition: diskd.cc:38
int seq_no
Definition: diomsg.h:33
static uint32 A
Definition: md4.c:43
@ _MQD_UNLINK
Definition: diomsg.h:25
static const int msg_snd_rcv_sz
Definition: diomsg.h:41
#define assert(EX)
Definition: assert.h:17
size_t size
Definition: diomsg.h:36
int main(int argc, char *argv[])
Definition: diskd.cc:302
#define SQUID_NONBLOCK
static int do_write(diomsg *r, int, const char *buf)
Definition: diskd.cc:168
static int fsCmp(const void *a, const void *b)
Definition: diskd.cc:282
#define SA_RESTART
@ _MQD_OPEN
Definition: diomsg.h:20
int fd
Definition: diskd.cc:46
#define xfree
@ _MQD_READ
Definition: diomsg.h:23
int shm_offset
Definition: diomsg.h:40
static void alarm_handler(int)
Definition: diskd.cc:298
static int do_open(diomsg *r, int, const char *buf)
Definition: diskd.cc:56
off_t offset
Definition: diomsg.h:37
int id
Definition: diskd.cc:45
hash_table * hash_create(HASHCMP *, int, HASHHASH *)
Definition: hash.cc:108
int id
Definition: diomsg.h:32
Definition: diomsg.h:30
int xread(int fd, void *buf, size_t bufSize)
POSIX read(2) equivalent.
Definition: unistd.h:61
int xopen(const char *filename, int oflag, int pmode=0)
POSIX open(2) equivalent.
Definition: unistd.h:55
#define PRId64
Definition: types.h:104
static pid_t mypid
Definition: diskd.cc:51
int xclose(int fd)
POSIX close(2) equivalent.
Definition: unistd.h:43
file_state * next
Definition: diskd.cc:44
static uint32 B
Definition: md4.c:43
bool newstyle
Definition: diomsg.h:39
static char * shmbuf
Definition: diskd.cc:52
static int do_unlink(diomsg *r, int, const char *buf)
Definition: diskd.cc:213
static hash_table * hash
Definition: diskd.cc:50
void * callback_data
Definition: diomsg.h:34
mtyp_t mtype
Definition: diomsg.h:31
void hash_join(hash_table *, hash_link *)
Definition: hash.cc:131
off_t offset
Definition: diskd.cc:47

 

Introduction

Documentation

Support

Miscellaneous