1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Error string handling
4 *
5 * Plan 9 uses error strings, Unix uses error numbers. These functions
6 * try to help manage that and provide for dynamically adding error
7 * mappings.
8 *
9 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
10 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
11 */
12
13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14
15#include <linux/module.h>
16#include <linux/list.h>
17#include <linux/jhash.h>
18#include <linux/errno.h>
19#include <linux/hashtable.h>
20#include <net/9p/9p.h>
21
22/**
23 * struct errormap - map string errors from Plan 9 to Linux numeric ids
24 * @name: string sent over 9P
25 * @val: numeric id most closely representing @name
26 * @namelen: length of string
27 * @list: hash-table list for string lookup
28 */
29struct errormap {
30 char *name;
31 int val;
32
33 int namelen;
34 struct hlist_node list;
35};
36
37#define ERRHASH_BITS 5
38static DEFINE_HASHTABLE(hash_errmap, ERRHASH_BITS);
39
40/* FixMe - reduce to a reasonable size */
41static struct errormap errmap[] = {
42 {"Operation not permitted", EPERM},
43 {.name: "wstat prohibited", EPERM},
44 {.name: "No such file or directory", ENOENT},
45 {.name: "directory entry not found", ENOENT},
46 {.name: "file not found", ENOENT},
47 {.name: "Interrupted system call", EINTR},
48 {.name: "Input/output error", EIO},
49 {.name: "No such device or address", ENXIO},
50 {.name: "Argument list too long", E2BIG},
51 {.name: "Bad file descriptor", EBADF},
52 {.name: "Resource temporarily unavailable", EAGAIN},
53 {.name: "Cannot allocate memory", ENOMEM},
54 {.name: "Permission denied", EACCES},
55 {.name: "Bad address", EFAULT},
56 {.name: "Block device required", ENOTBLK},
57 {.name: "Device or resource busy", EBUSY},
58 {.name: "File exists", EEXIST},
59 {.name: "Invalid cross-device link", EXDEV},
60 {.name: "No such device", ENODEV},
61 {.name: "Not a directory", ENOTDIR},
62 {.name: "Is a directory", EISDIR},
63 {.name: "Invalid argument", EINVAL},
64 {.name: "Too many open files in system", ENFILE},
65 {.name: "Too many open files", EMFILE},
66 {.name: "Text file busy", ETXTBSY},
67 {.name: "File too large", EFBIG},
68 {.name: "No space left on device", ENOSPC},
69 {.name: "Illegal seek", ESPIPE},
70 {.name: "Read-only file system", EROFS},
71 {.name: "Too many links", EMLINK},
72 {.name: "Broken pipe", EPIPE},
73 {.name: "Numerical argument out of domain", EDOM},
74 {.name: "Numerical result out of range", ERANGE},
75 {.name: "Resource deadlock avoided", EDEADLK},
76 {.name: "File name too long", ENAMETOOLONG},
77 {.name: "No locks available", ENOLCK},
78 {.name: "Function not implemented", ENOSYS},
79 {.name: "Directory not empty", ENOTEMPTY},
80 {.name: "Too many levels of symbolic links", ELOOP},
81 {.name: "No message of desired type", ENOMSG},
82 {.name: "Identifier removed", EIDRM},
83 {.name: "No data available", ENODATA},
84 {.name: "Machine is not on the network", ENONET},
85 {.name: "Package not installed", ENOPKG},
86 {.name: "Object is remote", EREMOTE},
87 {.name: "Link has been severed", ENOLINK},
88 {.name: "Communication error on send", ECOMM},
89 {.name: "Protocol error", EPROTO},
90 {.name: "Bad message", EBADMSG},
91 {.name: "File descriptor in bad state", EBADFD},
92 {.name: "Streams pipe error", ESTRPIPE},
93 {.name: "Too many users", EUSERS},
94 {.name: "Socket operation on non-socket", ENOTSOCK},
95 {.name: "Message too long", EMSGSIZE},
96 {.name: "Protocol not available", ENOPROTOOPT},
97 {.name: "Protocol not supported", EPROTONOSUPPORT},
98 {.name: "Socket type not supported", ESOCKTNOSUPPORT},
99 {.name: "Operation not supported", EOPNOTSUPP},
100 {.name: "Protocol family not supported", EPFNOSUPPORT},
101 {.name: "Network is down", ENETDOWN},
102 {.name: "Network is unreachable", ENETUNREACH},
103 {.name: "Network dropped connection on reset", ENETRESET},
104 {.name: "Software caused connection abort", ECONNABORTED},
105 {.name: "Connection reset by peer", ECONNRESET},
106 {.name: "No buffer space available", ENOBUFS},
107 {.name: "Transport endpoint is already connected", EISCONN},
108 {.name: "Transport endpoint is not connected", ENOTCONN},
109 {.name: "Cannot send after transport endpoint shutdown", ESHUTDOWN},
110 {.name: "Connection timed out", ETIMEDOUT},
111 {.name: "Connection refused", ECONNREFUSED},
112 {.name: "Host is down", EHOSTDOWN},
113 {.name: "No route to host", EHOSTUNREACH},
114 {.name: "Operation already in progress", EALREADY},
115 {.name: "Operation now in progress", EINPROGRESS},
116 {.name: "Is a named type file", EISNAM},
117 {.name: "Remote I/O error", EREMOTEIO},
118 {.name: "Disk quota exceeded", EDQUOT},
119/* errors from fossil, vacfs, and u9fs */
120 {.name: "fid unknown or out of range", EBADF},
121 {.name: "permission denied", EACCES},
122 {.name: "file does not exist", ENOENT},
123 {.name: "authentication failed", ECONNREFUSED},
124 {.name: "bad offset in directory read", ESPIPE},
125 {.name: "bad use of fid", EBADF},
126 {.name: "wstat can't convert between files and directories", EPERM},
127 {.name: "directory is not empty", ENOTEMPTY},
128 {.name: "file exists", EEXIST},
129 {.name: "file already exists", EEXIST},
130 {.name: "file or directory already exists", EEXIST},
131 {.name: "fid already in use", EBADF},
132 {.name: "file in use", ETXTBSY},
133 {.name: "i/o error", EIO},
134 {.name: "file already open for I/O", ETXTBSY},
135 {.name: "illegal mode", EINVAL},
136 {.name: "illegal name", ENAMETOOLONG},
137 {.name: "not a directory", ENOTDIR},
138 {.name: "not a member of proposed group", EPERM},
139 {.name: "not owner", EACCES},
140 {.name: "only owner can change group in wstat", EACCES},
141 {.name: "read only file system", EROFS},
142 {.name: "no access to special file", EPERM},
143 {.name: "i/o count too large", EIO},
144 {.name: "unknown group", EINVAL},
145 {.name: "unknown user", EINVAL},
146 {.name: "bogus wstat buffer", EPROTO},
147 {.name: "exclusive use file already open", EAGAIN},
148 {.name: "corrupted directory entry", EIO},
149 {.name: "corrupted file entry", EIO},
150 {.name: "corrupted block label", EIO},
151 {.name: "corrupted meta data", EIO},
152 {.name: "illegal offset", EINVAL},
153 {.name: "illegal path element", ENOENT},
154 {.name: "root of file system is corrupted", EIO},
155 {.name: "corrupted super block", EIO},
156 {.name: "protocol botch", EPROTO},
157 {.name: "file system is full", ENOSPC},
158 {.name: "file is in use", EAGAIN},
159 {.name: "directory entry is not allocated", ENOENT},
160 {.name: "file is read only", EROFS},
161 {.name: "file has been removed", EIDRM},
162 {.name: "only support truncation to zero length", EPERM},
163 {.name: "cannot remove root", EPERM},
164 {.name: "file too big", EFBIG},
165 {.name: "venti i/o error", EIO},
166 /* these are not errors */
167 {.name: "u9fs rhostsauth: no authentication required", .val: 0},
168 {.name: "u9fs authnone: no authentication required", .val: 0},
169 {NULL, .val: -1}
170};
171
172/**
173 * p9_error_init - preload mappings into hash list
174 *
175 */
176
177int p9_error_init(void)
178{
179 struct errormap *c;
180 u32 hash;
181
182 /* load initial error map into hash table */
183 for (c = errmap; c->name; c++) {
184 c->namelen = strlen(c->name);
185 hash = jhash(key: c->name, length: c->namelen, initval: 0);
186 INIT_HLIST_NODE(h: &c->list);
187 hash_add(hash_errmap, &c->list, hash);
188 }
189
190 return 1;
191}
192EXPORT_SYMBOL(p9_error_init);
193
194/**
195 * p9_errstr2errno - convert error string to error number
196 * @errstr: error string
197 * @len: length of error string
198 *
199 */
200
201int p9_errstr2errno(char *errstr, int len)
202{
203 int errno;
204 struct errormap *c;
205 u32 hash;
206
207 errno = 0;
208 c = NULL;
209 hash = jhash(key: errstr, length: len, initval: 0);
210 hash_for_each_possible(hash_errmap, c, list, hash) {
211 if (c->namelen == len && !memcmp(c->name, errstr, len)) {
212 errno = c->val;
213 break;
214 }
215 }
216
217 if (errno == 0) {
218 /* TODO: if error isn't found, add it dynamically */
219 errstr[len] = 0;
220 pr_err("%s: server reported unknown error %s\n",
221 __func__, errstr);
222 errno = ESERVERFAULT;
223 }
224
225 return -errno;
226}
227EXPORT_SYMBOL(p9_errstr2errno);
228