char *parse_lock(char *line, struct response *req) { char *more; more = get_fpos(line, &req->r_fpos, REQUIRES_MORE); if (more == NULL) return more; more = get_lock_type(more, &req->r_lock_type); if (more == NULL) return more; if (req->r_lock_type != F_RDLCK && req->r_lock_type != F_WRLCK) { errno = EINVAL; strcpy(errdetail, "Invalid lock type"); sprintf(badtoken, "%s", str_lock_type(req->r_lock_type)); } more = get_longlong(more, &req->r_start, REQUIRES_MORE, "Invalid lock start"); if (more == NULL) return more; return get_longlong(more, &req->r_length, REQUIRES_NO_MORE, "Invalid lock len"); }
void do_lock(struct response *resp) { int rc; struct flock lock; int cmd; if (resp->r_cmd == CMD_LOCKW) cmd = F_SETLKW; else cmd = F_SETLK; if (resp->r_fpos != 0 && fno[resp->r_fpos] == 0) { strcpy(errdetail, "Invalid file number"); sprintf(badtoken, "%ld", resp->r_fpos); resp->r_status = STATUS_ERRNO; resp->r_errno = EBADF; return; } lock.l_whence = SEEK_SET; lock.l_type = resp->r_lock_type; lock.l_start = resp->r_start; lock.l_len = resp->r_length; if (cmd == F_SETLKW && alarmtag == 0) { /* Don't let a blocking lock block hang us * Test case can set an alarm before LOCKW to specify * a different time */ resp->r_secs = 30; do_alarm(resp); } rc = fcntl(fno[resp->r_fpos], cmd, &lock); if (rc == -1) { if (errno == EAGAIN) { resp->r_status = STATUS_DENIED; } else if (errno == EINTR) { resp->r_status = STATUS_CANCELED; } else if (errno == EDEADLK) { resp->r_status = STATUS_DEADLOCK; } else { strcpy(errdetail, "Lock failed"); sprintf(badtoken, "%s %lld %lld", str_lock_type(lock.l_type), resp->r_start, resp->r_length); resp->r_status = STATUS_ERRNO; resp->r_errno = errno; } } else resp->r_status = STATUS_GRANTED; if (cmd == F_SETLKW && alarmtag == resp->r_tag) { /* cancel the alarm we set */ alarm(0); alarmtag = 0; } }
void do_test(struct response *resp) { int rc; struct flock lock; int cmd = F_GETLK; if (resp->r_fpos != 0 && fno[resp->r_fpos] == 0) { strcpy(errdetail, "Invalid file number"); sprintf(badtoken, "%ld", resp->r_fpos); resp->r_status = STATUS_ERRNO; resp->r_errno = EBADF; return; } lock.l_whence = SEEK_SET; lock.l_type = resp->r_lock_type; lock.l_start = resp->r_start; lock.l_len = resp->r_length; fprintf(stdout, "TEST lock type %s\n", str_lock_type(lock.l_type)); rc = fcntl(fno[resp->r_fpos], cmd, &lock); if (rc == -1) { strcpy(errdetail, "Test failed"); sprintf(badtoken, "%s %lld %lld", str_lock_type(lock.l_type), resp->r_start, resp->r_length); resp->r_status = STATUS_ERRNO; return; } if (lock.l_type == F_UNLCK) { fprintf(stdout, "GRANTED TEST lock type %s\n", str_lock_type(lock.l_type)); resp->r_status = STATUS_GRANTED; } else { resp->r_lock_type = lock.l_type; resp->r_pid = lock.l_pid; resp->r_start = lock.l_start; resp->r_length = lock.l_len; resp->r_status = STATUS_CONFLICT; } }
void do_unhop(struct response *resp) { int rc; int pos; struct flock lock; int cmd; cmd = F_SETLK; if (resp->r_fpos != 0 && fno[resp->r_fpos] == 0) { strcpy(errdetail, "Invalid file number"); sprintf(badtoken, "%ld", resp->r_fpos); resp->r_status = STATUS_ERRNO; resp->r_errno = EBADF; return; } for (pos = resp->r_start; pos < resp->r_start + resp->r_length; pos++) { if ((pos == 0) || (pos == (resp->r_start + resp->r_length - 1))) lock.l_start = pos; else if ((pos & 1) == 0) lock.l_start = pos - 1; else lock.l_start = pos + 1; lock.l_whence = SEEK_SET; lock.l_type = resp->r_lock_type; lock.l_len = 1; rc = fcntl(fno[resp->r_fpos], cmd, &lock); if (rc == -1) { strcpy(errdetail, "Unhop failed"); sprintf(badtoken, "%s %ld", str_lock_type(resp->r_lock_type), lock.l_start); resp->r_status = STATUS_ERRNO; break; } else resp->r_status = STATUS_GRANTED; } if (resp->r_status != STATUS_GRANTED) { lock.l_whence = SEEK_SET; lock.l_type = F_UNLCK; lock.l_start = resp->r_start; lock.l_len = resp->r_length; rc = fcntl(fno[resp->r_fpos], cmd, &lock); if (rc == -1) { strcpy(errdetail, "Unhop Unlock failed"); sprintf(badtoken, "%lld %lld", resp->r_start, resp->r_length); resp->r_status = STATUS_ERRNO; } } }
int list_locks(long long int start, long long int end, struct response *resp) { long long int conf_end; struct flock lock; int rc; lock.l_whence = SEEK_SET; lock.l_type = F_WRLCK; lock.l_start = start; if (end == INT64_MAX) lock.l_len = 0; else lock.l_len = end - start; rc = fcntl(fno[resp->r_fpos], F_GETLK, &lock); if (rc == -1) { strcpy(errdetail, "Test failed"); sprintf(badtoken, "%s %lld %lld", str_lock_type(lock.l_type), resp->r_start, resp->r_length); resp->r_errno = errno; resp->r_status = STATUS_ERRNO; respond(resp); return false; } /* Our test succeeded */ if (lock.l_type == F_UNLCK) return false; resp->r_status = STATUS_CONFLICT; resp->r_lock_type = lock.l_type; resp->r_pid = lock.l_pid; resp->r_start = lock.l_start; resp->r_length = lock.l_len; respond(resp); conf_end = lock_end(lock.l_start, lock.l_len); if (lock.l_start > start) make_test_item(start, lock.l_start); if (conf_end < end) make_test_item(conf_end, end); return true; }
void sprintf_resp(char *line, const char *lead, struct response *resp) { char *rest = line; if (lead != NULL) { const char *name = "<NULL>"; if (resp->r_client != NULL) name = resp->r_client->c_name; rest = rest + sprintf(line, "%s %s ", lead, name); } rest = rest + sprintf(rest, "%ld %s %s", resp->r_tag, commands[resp->r_cmd].cmd_name, str_status(resp->r_status)); switch (resp->r_status) { case STATUS_OK: switch (resp->r_cmd) { case CMD_COMMENT: case CMD_HELLO: sprintf(rest, " \"%s\"\n", resp->r_data); break; case CMD_LOCKW: case CMD_LOCK: case CMD_UNLOCK: case CMD_TEST: case CMD_LIST: case CMD_HOP: case CMD_UNHOP: case NUM_COMMANDS: sprintf(rest, " Unexpected Status\n"); break; case CMD_ALARM: sprintf(rest, " %ld\n", resp->r_secs); break; case CMD_QUIT: sprintf(rest, "\n"); break; case CMD_OPEN: sprintf(rest, " %ld %ld\n", resp->r_fpos, resp->r_fno); break; case CMD_CLOSE: case CMD_SEEK: sprintf(rest, " %ld\n", resp->r_fpos); break; case CMD_WRITE: sprintf(rest, " %ld %lld\n", resp->r_fpos, resp->r_length); break; case CMD_READ: sprintf(rest, " %ld %lld \"%s\"\n", resp->r_fpos, resp->r_length, resp->r_data); break; } break; case STATUS_AVAILABLE: case STATUS_GRANTED: case STATUS_DENIED: case STATUS_DEADLOCK: if (resp->r_cmd == CMD_LIST) sprintf(rest, " %ld %lld %lld\n", resp->r_fpos, resp->r_start, resp->r_length); else sprintf(rest, " %ld %s %lld %lld\n", resp->r_fpos, str_lock_type(resp->r_lock_type), resp->r_start, resp->r_length); break; case STATUS_CONFLICT: sprintf(rest, " %ld %ld %s %lld %lld\n", resp->r_fpos, resp->r_pid, str_lock_type(resp->r_lock_type), resp->r_start, resp->r_length); break; case STATUS_CANCELED: if (resp->r_cmd == CMD_LOCKW) { sprintf(rest, " %ld %s %lld %lld\n", resp->r_fpos, str_lock_type(resp->r_lock_type), resp->r_start, resp->r_length); } else if (resp->r_cmd == CMD_ALARM) { sprintf(rest, " %ld\n", resp->r_secs); } else { } break; case STATUS_COMPLETED: sprintf(rest, "\n"); break; case STATUS_ERRNO: if (errno == 0) sprintf(rest, " %ld \"%s\"\n", resp->r_errno, errdetail); else sprintf(rest, " %ld \"%s\" \"%s\" bad token \"%s\"\n", resp->r_errno, strerror(resp->r_errno), errdetail, badtoken); break; case STATUS_PARSE_ERROR: break; case STATUS_ERROR: break; } }
void sprintf_req(char *line, const char *lead, struct response *req) { char *rest = line; if (lead != NULL) { const char *name = "<NULL>"; if (req->r_client != NULL) name = req->r_client->c_name; rest = rest + sprintf(line, "%s %s ", lead, name); } rest = rest + sprintf(rest, "%ld %s", req->r_tag, commands[req->r_cmd].cmd_name); switch (req->r_cmd) { case CMD_COMMENT: case CMD_HELLO: sprintf(rest, " \"%s\"\n", req->r_data); break; case CMD_LOCKW: case CMD_LOCK: case CMD_TEST: case CMD_HOP: sprintf(rest, " %ld %s %lld %lld\n", req->r_fpos, str_lock_type(req->r_lock_type), req->r_start, req->r_length); break; case CMD_UNLOCK: case CMD_LIST: case CMD_UNHOP: sprintf(rest, " %ld %lld %lld\n", req->r_fpos, req->r_start, req->r_length); break; case NUM_COMMANDS: sprintf(rest, " Unexpected Command\n"); break; case CMD_ALARM: sprintf(rest, " %ld\n", req->r_secs); break; case CMD_QUIT: sprintf(rest, "\n"); break; case CMD_OPEN: rest += sprintf(rest, " %ld %s", req->r_fpos, str_read_write_flags(req->r_flags)); rest += sprintf_open_flags(rest, req->r_flags); rest += sprintf(rest, " \"%s\"\n", req->r_data); break; case CMD_CLOSE: sprintf(rest, " %ld\n", req->r_fpos); break; case CMD_SEEK: sprintf(rest, " %ld %lld\n", req->r_fpos, req->r_start); break; case CMD_WRITE: sprintf(rest, " %ld %s\n", req->r_fpos, req->r_data); break; case CMD_READ: sprintf(rest, " %ld %lld\n", req->r_fpos, req->r_length); break; } }